1use crate::sheet_::Header;
2use std::borrow::Cow;
3use std::convert::{TryFrom, TryInto};
4use std::fs::File;
5use std::io::{BufRead, BufReader, Cursor, Read, Seek, Write};
6use std::mem;
7use std::path::Path;
8use std::str::from_utf8;
9
10use chrono::{Duration, NaiveDateTime};
11use quick_xml::events::attributes::Attribute;
12use quick_xml::events::{BytesRef, BytesStart, Event};
13use quick_xml::{Decoder, Reader};
14use zip::ZipArchive;
15
16use crate::attrmap2::AttrMap2;
17use crate::cell_::CellData;
18use crate::condition::{Condition, ValueCondition};
19use crate::config::{Config, ConfigItem, ConfigItemType, ConfigValue};
20use crate::draw::{Annotation, DrawFrame, DrawFrameContent, DrawImage};
21use crate::ds::detach::Detach;
22use crate::error::OdsError;
23use crate::format::{FormatPart, FormatPartType, ValueFormatTrait, ValueStyleMap};
24use crate::io::parse::{
25 parse_bool, parse_currency, parse_datetime, parse_duration, parse_f64, parse_i16, parse_i32,
26 parse_i64, parse_string, parse_u32, parse_visibility, parse_xlink_actuate, parse_xlink_show,
27 parse_xlink_type,
28};
29use crate::io::NamespaceMap;
30use crate::manifest::Manifest;
31use crate::metadata::{
32 MetaAutoReload, MetaDocumentStatistics, MetaHyperlinkBehaviour, MetaTemplate, MetaUserDefined,
33 MetaValue,
34};
35use crate::refs::{parse_cellranges, parse_cellref};
36use crate::sheet::{Grouped, SplitMode};
37use crate::sheet_::{dedup_colheader, CellDataIter, CellDataIterMut, ColHeader, RowHeader};
38use crate::style::stylemap::StyleMap;
39use crate::style::tabstop::TabStop;
40use crate::style::{
41 AnyStyleRef, ColStyle, ColStyleRef, FontFaceDecl, GraphicStyle, HeaderFooter, MasterPage,
42 MasterPageRef, PageStyle, ParagraphStyle, RowStyle, RowStyleRef, RubyStyle, StyleOrigin,
43 StyleUse, TableStyle, TableStyleRef, TextStyle,
44};
45use crate::text::{TextP, TextTag};
46use crate::validation::{MessageType, Validation, ValidationError, ValidationHelp, ValidationRef};
47use crate::workbook::{EventListener, Script};
48use crate::xmltree::XmlTag;
49use crate::{
50 CellStyle, CellStyleRef, Length, Sheet, Value, ValueFormatBoolean, ValueFormatCurrency,
51 ValueFormatDateTime, ValueFormatNumber, ValueFormatPercentage, ValueFormatText,
52 ValueFormatTimeDuration, ValueType, WorkBook,
53};
54
55type OdsXmlReader<'a> = quick_xml::Reader<&'a mut dyn BufRead>;
56
57#[derive(Debug, Default)]
59pub struct OdsOptions {
60 content_only: bool,
62 use_repeat_for_cells: bool,
64 ignore_empty_cells: bool,
66}
67
68impl OdsOptions {
69 pub fn content_only(mut self) -> Self {
74 self.content_only = true;
75 self
76 }
77
78 pub fn read_styles(mut self) -> Self {
84 self.content_only = false;
85 self
86 }
87
88 pub fn use_repeat_for_cells(mut self) -> Self {
95 self.use_repeat_for_cells = true;
96 self
97 }
98
99 pub fn use_clone_for_cells(mut self) -> Self {
109 self.use_repeat_for_cells = false;
110 self
111 }
112
113 pub fn ignore_empty_cells(mut self) -> Self {
118 self.ignore_empty_cells = true;
119 self
120 }
121
122 pub fn read_empty_cells(mut self) -> Self {
130 self.ignore_empty_cells = false;
131 self
132 }
133
134 pub fn read_ods<T: Read + Seek>(&self, read: T) -> Result<WorkBook, OdsError> {
136 let zip = ZipArchive::new(read)?;
137 if self.content_only {
138 read_ods_impl_content_only(zip, self)
139 } else {
140 read_ods_impl(zip, self)
141 }
142 }
143
144 pub fn read_fods<T: BufRead>(&self, mut read: T) -> Result<WorkBook, OdsError> {
146 if self.content_only {
147 read_fods_impl_content_only(&mut read, self)
148 } else {
149 read_fods_impl(&mut read, self)
150 }
151 }
152}
153
154pub fn read_ods_buf(buf: &[u8]) -> Result<WorkBook, OdsError> {
156 let read = Cursor::new(buf);
157 OdsOptions::default().read_ods(read)
158}
159
160pub fn read_ods_from<T: Read + Seek>(read: T) -> Result<WorkBook, OdsError> {
162 OdsOptions::default().read_ods(read)
163}
164
165pub fn read_ods<P: AsRef<Path>>(path: P) -> Result<WorkBook, OdsError> {
167 let read = BufReader::new(File::open(path.as_ref())?);
168 OdsOptions::default().read_ods(read)
169}
170
171pub fn read_fods_buf(buf: &[u8]) -> Result<WorkBook, OdsError> {
173 let mut read = Cursor::new(buf);
174 OdsOptions::default().read_fods(&mut read)
175}
176
177pub fn read_fods_from<T: Read>(read: T) -> Result<WorkBook, OdsError> {
179 let read = BufReader::new(read);
180 OdsOptions::default().read_fods(read)
181}
182
183pub fn read_fods<P: AsRef<Path>>(path: P) -> Result<WorkBook, OdsError> {
185 let read = BufReader::new(File::open(path.as_ref())?);
186 OdsOptions::default().read_fods(read)
187}
188
189struct OdsContext {
190 book: WorkBook,
191
192 decoder: Decoder,
193
194 #[allow(dead_code)]
195 content_only: bool,
196 use_repeat_for_cells: bool,
197 ignore_empty_cells: bool,
198
199 buffers: Vec<Vec<u8>>,
200 xml_buffer: Vec<XmlTag>,
201 col_group_buffer: Vec<Grouped>,
202 row_group_buffer: Vec<Grouped>,
203}
204
205impl OdsContext {
206 fn new(options: &OdsOptions) -> Self {
207 Self {
208 book: Default::default(),
209 decoder: Reader::from_reader(Vec::<u8>::new().as_slice()).decoder(),
210 content_only: options.content_only,
211 use_repeat_for_cells: options.use_repeat_for_cells,
212 ignore_empty_cells: options.ignore_empty_cells,
213
214 buffers: vec![],
215 xml_buffer: vec![],
216 col_group_buffer: vec![],
217 row_group_buffer: vec![],
218 }
219 }
220
221 fn pop_xml_buf(&mut self) -> Vec<XmlTag> {
222 mem::take(&mut self.xml_buffer)
223 }
224
225 fn push_xml_buf(&mut self, mut buf: Vec<XmlTag>) {
226 buf.clear();
227 self.xml_buffer = buf;
228 }
229
230 fn pop_colgroup_buf(&mut self) -> Vec<Grouped> {
231 mem::take(&mut self.col_group_buffer)
232 }
233
234 fn push_colgroup_buf(&mut self, mut buf: Vec<Grouped>) {
235 buf.clear();
236 self.col_group_buffer = buf;
237 }
238
239 fn pop_rowgroup_buf(&mut self) -> Vec<Grouped> {
240 mem::take(&mut self.row_group_buffer)
241 }
242
243 fn push_rowgroup_buf(&mut self, mut buf: Vec<Grouped>) {
244 buf.clear();
245 self.row_group_buffer = buf;
246 }
247
248 fn pop_buf(&mut self) -> Vec<u8> {
250 self.buffers.pop().unwrap_or_default()
251 }
252
253 fn push_buf(&mut self, mut buf: Vec<u8>) {
255 buf.clear();
256 self.buffers.push(buf);
257 }
258}
259
260fn read_fods_impl(read: &mut dyn BufRead, options: &OdsOptions) -> Result<WorkBook, OdsError> {
261 let mut ctx = OdsContext::new(options);
262 let mut xml = quick_xml::Reader::from_reader(read);
263
264 let mut buf = ctx.pop_buf();
265 loop {
266 let evt = xml.read_event_into(&mut buf)?;
267 if cfg!(feature = "dump_xml") {
268 println!("read_fods_content {:?}", evt);
269 }
270
271 match &evt {
272 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:document" => {
273 let (version, xmlns) = read_namespaces_and_version(&mut ctx, xml_tag)?;
274 ctx.book.xmlns.insert("fods.xml".to_string(), xmlns);
275 if let Some(version) = version {
276 ctx.book.set_version(version);
277 }
278 }
279 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:document" => {}
280
281 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:meta" => {
282 read_office_meta(&mut ctx, &mut xml)?;
283 }
284 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:settings" => {
285 read_office_settings(&mut ctx, &mut xml)?;
286 }
287 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:scripts" => {
288 read_scripts(&mut ctx, &mut xml)?
289 }
290 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:font-face-decls" => {
291 read_office_font_face_decls(&mut ctx, &mut xml, StyleOrigin::Content)?
292 }
293 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:styles" => {
294 read_office_styles(&mut ctx, &mut xml, StyleOrigin::Content)?
295 }
296 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:automatic-styles" => {
297 read_office_automatic_styles(&mut ctx, &mut xml, StyleOrigin::Content)?
298 }
299 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:master-styles" => {
300 read_office_master_styles(&mut ctx, &mut xml, StyleOrigin::Content)?
301 }
302 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:body" => {
303 read_office_body(&mut ctx, &mut xml)?;
304 }
305
306 Event::Decl(_) => {}
307 Event::Eof => {
308 break;
309 }
310 _ => {
311 unused_event("read_fods_content", &evt)?;
312 }
313 }
314 }
315 ctx.push_buf(buf);
316
317 calculations(&mut ctx)?;
318
319 calc_derived(&mut ctx.book)?;
321
322 Ok(ctx.book)
323}
324
325fn read_fods_impl_content_only(
326 read: &mut dyn BufRead,
327 options: &OdsOptions,
328) -> Result<WorkBook, OdsError> {
329 let mut ctx = OdsContext::new(options);
330 let mut xml: quick_xml::Reader<&mut dyn BufRead> = quick_xml::Reader::from_reader(read);
331
332 let mut buf = ctx.pop_buf();
333 loop {
334 let evt = xml.read_event_into(&mut buf)?;
335 if cfg!(feature = "dump_xml") {
336 println!("read_fods_content_only {:?}", evt);
337 }
338
339 match &evt {
340 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:body" => {
341 read_office_body(&mut ctx, &mut xml)?;
342 }
343 Event::Eof => {
344 break;
345 }
346 _ => {
347 }
349 }
350 }
351 ctx.push_buf(buf);
352
353 calculations(&mut ctx)?;
354
355 Ok(ctx.book)
356}
357
358fn read_ods_impl<R: Read + Seek>(
360 mut zip: ZipArchive<R>,
361 options: &OdsOptions,
362) -> Result<WorkBook, OdsError> {
363 let mut ctx = OdsContext::new(options);
364
365 if let Ok(z) = zip.by_name("META-INF/manifest.xml") {
366 let mut read = BufReader::new(z);
367 let read: &mut dyn BufRead = &mut read;
368 let mut xml = quick_xml::Reader::from_reader(read);
369
370 read_ods_manifest(&mut ctx, &mut xml)?;
371 }
372
373 read_ods_extras(&mut ctx, &mut zip)?;
374
375 if let Ok(z) = zip.by_name("meta.xml") {
376 let mut read = BufReader::new(z);
377 let read: &mut dyn BufRead = &mut read;
378 let mut xml = quick_xml::Reader::from_reader(read);
379
380 read_ods_metadata(&mut ctx, &mut xml)?;
381 }
382
383 if let Ok(z) = zip.by_name("settings.xml") {
384 let mut read = BufReader::new(z);
385 let read: &mut dyn BufRead = &mut read;
386 let mut xml = quick_xml::Reader::from_reader(read);
387 read_ods_settings(&mut ctx, &mut xml)?;
388 }
389
390 if let Ok(z) = zip.by_name("styles.xml") {
391 let mut read = BufReader::new(z);
392 let read: &mut dyn BufRead = &mut read;
393 let mut xml = quick_xml::Reader::from_reader(read);
394 read_ods_styles(&mut ctx, &mut xml)?;
395 }
396
397 {
398 let mut read = BufReader::new(zip.by_name("content.xml")?);
399 let read: &mut dyn BufRead = &mut read;
400 let mut xml = quick_xml::Reader::from_reader(read);
401 read_ods_content(&mut ctx, &mut xml)?;
402 }
403
404 calculations(&mut ctx)?;
405
406 calc_derived(&mut ctx.book)?;
408
409 Ok(ctx.book)
410}
411
412fn read_ods_impl_content_only<R: Read + Seek>(
414 mut zip: ZipArchive<R>,
415 options: &OdsOptions,
416) -> Result<WorkBook, OdsError> {
417 let mut ctx = OdsContext::new(options);
418
419 let mut read = BufReader::new(zip.by_name("content.xml")?);
420 let read: &mut dyn BufRead = &mut read;
421 let mut xml = quick_xml::Reader::from_reader(read);
422
423 read_ods_content(&mut ctx, &mut xml)?;
425
426 calculations(&mut ctx)?;
427
428 Ok(ctx.book)
429}
430
431fn read_ods_extras<R: Read + Seek>(
432 ctx: &mut OdsContext,
433 zip: &mut ZipArchive<R>,
434) -> Result<(), OdsError> {
435 for manifest in ctx.book.manifest.values_mut().filter(|v| !v.is_dir()) {
437 if !matches!(
438 manifest.full_path.as_str(),
439 "/" | "settings.xml" | "styles.xml" | "content.xml" | "meta.xml"
440 ) {
441 let mut ze = zip.by_name(manifest.full_path.as_str())?;
442 let mut buf = Vec::new();
443 ze.read_to_end(&mut buf)?;
444 manifest.buffer = Some(buf);
445 }
446 }
447
448 Ok(())
449}
450
451fn read_ods_manifest(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
452 let mut buf = ctx.pop_buf();
453 loop {
454 let evt = xml.read_event_into(&mut buf)?;
455 match &evt {
456 Event::Decl(_) => {}
457
458 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"manifest:manifest" => {}
459 Event::End(xml_tag) if xml_tag.name().as_ref() == b"manifest:manifest" => {}
460
461 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"manifest:file-entry" => {
462 let mut manifest = Manifest::default();
463
464 for attr in xml_tag.attributes().with_checks(false) {
465 let attr = attr?;
466
467 if attr.key.as_ref() == b"manifest:full-path" {
468 manifest.full_path =
469 attr.decode_and_unescape_value(ctx.decoder)?.to_string();
470 } else if attr.key.as_ref() == b"manifest:version" {
471 manifest.version =
472 Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
473 } else if attr.key.as_ref() == b"manifest:media-type" {
474 manifest.media_type =
475 attr.decode_and_unescape_value(ctx.decoder)?.to_string();
476 }
477 }
478
479 if manifest.full_path != "mimetype" && manifest.full_path != "META-INF/manifest.xml"
481 {
482 ctx.book.add_manifest(manifest);
483 }
484 }
485 Event::Eof => {
486 break;
487 }
488 _ => {
489 unused_event("read_manifest", &evt)?;
490 }
491 }
492 buf.clear();
493 }
494 ctx.push_buf(buf);
495 Ok(())
496}
497
498fn calculations(ctx: &mut OdsContext) -> Result<(), OdsError> {
500 for i in 0..ctx.book.num_sheets() {
501 dedup_colheader(ctx.book.sheet_mut(i))?;
502 if ctx.use_repeat_for_cells {
503 calc_repeat_sheet(ctx.book.sheet_mut(i))?;
504 } else {
505 calc_cloned_sheet(ctx.book.sheet_mut(i))?;
506 }
507 }
508 Ok(())
509}
510
511fn calc_repeat_sheet(sheet: &mut Sheet) -> Result<(), OdsError> {
513 let mut dropped = Vec::new();
514
515 for (_row, rh) in sheet.row_header.iter_mut().rev().take(5) {
519 if rh.repeat > 1000 {
520 rh.repeat = 1;
521 }
522 }
523
524 let mut it = CellDataIterMut::new(sheet.data.range_mut(..));
526 loop {
527 let Some(((row, col), data)) = it.next() else {
528 break;
529 };
530
531 if data.repeat > 1 {
532 let last_in_row = if let Some((next_row, _next_col)) = it.peek_cell() {
533 row != next_row
534 } else {
535 true
536 };
537 if last_in_row && data.is_empty() {
538 dropped.push((row, col));
540 continue;
541 }
542 }
543 }
544 for (row, col) in dropped {
545 sheet.data.remove(&(row, col));
546 }
547
548 Ok(())
549}
550
551fn calc_cloned_sheet(sheet: &mut Sheet) -> Result<(), OdsError> {
553 let mut cloned = Vec::new();
554 let mut dropped = Vec::new();
555
556 for (_row, rh) in sheet.row_header.iter_mut().rev().take(5) {
560 if rh.repeat > 1000 {
561 rh.repeat = 1;
562 }
563 }
564 for (row, rh) in sheet.row_header.iter().filter(|(_, v)| v.repeat > 1) {
566 let cit = CellDataIter::new(sheet.data.range((*row, 0)..(row + 1, 0)));
568 for ((row, col), data) in cit {
569 for i in 1..rh.repeat {
570 cloned.push((row + i, col, data.clone()));
571 }
572 }
573 }
574 for (row, col, data) in cloned.drain(..) {
575 sheet.data.insert((row, col), data);
576 }
577 for (_row, rh) in sheet.row_header.iter_mut() {
580 mem::swap(&mut rh.repeat, &mut rh.span);
581 }
582
583 let mut it = CellDataIterMut::new(sheet.data.range_mut(..));
586 loop {
587 let Some(((row, col), data)) = it.next() else {
588 break;
589 };
590
591 if data.repeat > 1 {
592 let repeat = mem::replace(&mut data.repeat, 1);
593
594 let last_in_row = if let Some((next_row, _next_col)) = it.peek_cell() {
595 row != next_row
596 } else {
597 true
598 };
599 if last_in_row && data.is_empty() {
600 dropped.push((row, col));
602 continue;
603 }
604
605 for i in 1..repeat {
606 cloned.push((row, col + i, data.clone()));
607 }
608 }
609 }
610 for (row, col) in dropped {
611 sheet.data.remove(&(row, col));
612 }
613 for (row, col, data) in cloned {
614 sheet.data.insert((row, col), data);
615 }
616
617 Ok(())
618}
619
620fn calc_derived(book: &mut WorkBook) -> Result<(), OdsError> {
622 let v = book
623 .config
624 .get_value(&["ooo:view-settings", "Views", "0", "ActiveTable"]);
625 if let Some(ConfigValue::String(n)) = v {
626 book.config_mut().active_table = n.clone();
627 }
628 let v = book
629 .config
630 .get_value(&["ooo:view-settings", "Views", "0", "HasSheetTabs"]);
631 if let Some(ConfigValue::Boolean(n)) = v {
632 book.config_mut().has_sheet_tabs = *n;
633 }
634 let v = book
635 .config
636 .get_value(&["ooo:view-settings", "Views", "0", "ShowGrid"]);
637 if let Some(ConfigValue::Boolean(n)) = v {
638 book.config_mut().show_grid = *n;
639 }
640 let v = book
641 .config
642 .get_value(&["ooo:view-settings", "Views", "0", "ShowPageBreaks"]);
643 if let Some(ConfigValue::Boolean(n)) = v {
644 book.config_mut().show_page_breaks = *n;
645 }
646
647 for i in 0..book.num_sheets() {
648 let mut sheet = book.detach_sheet(i);
649
650 for ch in sheet.col_header.values_mut() {
652 if let Some(style_name) = &ch.style {
653 if let Some(style) = book.colstyle(style_name) {
654 if style.use_optimal_col_width()? {
655 ch.width = Length::Default;
656 } else {
657 ch.width = style.col_width()?;
658 }
659 }
660 }
661 }
662
663 for rh in sheet.row_header.values_mut() {
665 if let Some(style_name) = &rh.style {
666 if let Some(style) = book.rowstyle(style_name) {
667 if style.use_optimal_row_height()? {
668 rh.height = Length::Default;
669 } else {
670 rh.height = style.row_height()?;
671 }
672 }
673 }
674 }
675
676 let v = book.config.get(&[
677 "ooo:view-settings",
678 "Views",
679 "0",
680 "Tables",
681 sheet.name().as_str(),
682 ]);
683
684 if let Some(cc) = v {
685 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["CursorPositionX"]) {
686 sheet.config_mut().cursor_x = *n as u32;
687 }
688 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["CursorPositionY"]) {
689 sheet.config_mut().cursor_y = *n as u32;
690 }
691 if let Some(ConfigValue::Short(n)) = cc.get_value_rec(&["HorizontalSplitMode"]) {
692 sheet.config_mut().hor_split_mode = SplitMode::try_from(*n)?;
693 }
694 if let Some(ConfigValue::Short(n)) = cc.get_value_rec(&["VerticalSplitMode"]) {
695 sheet.config_mut().vert_split_mode = SplitMode::try_from(*n)?;
696 }
697 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["HorizontalSplitPosition"]) {
698 sheet.config_mut().hor_split_pos = *n as u32;
699 }
700 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["VerticalSplitPosition"]) {
701 sheet.config_mut().vert_split_pos = *n as u32;
702 }
703 if let Some(ConfigValue::Short(n)) = cc.get_value_rec(&["ActiveSplitRange"]) {
704 sheet.config_mut().active_split_range = *n;
705 }
706 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["PositionLeft"]) {
707 sheet.config_mut().position_left = *n as u32;
708 }
709 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["PositionRight"]) {
710 sheet.config_mut().position_right = *n as u32;
711 }
712 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["PositionTop"]) {
713 sheet.config_mut().position_top = *n as u32;
714 }
715 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["PositionBottom"]) {
716 sheet.config_mut().position_bottom = *n as u32;
717 }
718 if let Some(ConfigValue::Short(n)) = cc.get_value_rec(&["ZoomType"]) {
719 sheet.config_mut().zoom_type = *n;
720 }
721 if let Some(ConfigValue::Int(n)) = cc.get_value_rec(&["ZoomValue"]) {
722 sheet.config_mut().zoom_value = *n;
723 }
724 if let Some(ConfigValue::Boolean(n)) = cc.get_value_rec(&["ShowGrid"]) {
725 sheet.config_mut().show_grid = *n;
726 }
727 }
728
729 book.attach_sheet(sheet);
730 }
731
732 Ok(())
733}
734
735fn read_ods_content(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
737 let mut buf = ctx.pop_buf();
738 loop {
739 let evt = xml.read_event_into(&mut buf)?;
740 if cfg!(feature = "dump_xml") {
741 println!(" read_ods_content {:?}", evt);
742 }
743 match &evt {
744 Event::Decl(_) => {}
745
746 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:document-content" => {
747 let (version, xmlns) = read_namespaces_and_version(ctx, xml_tag)?;
748 if let Some(version) = version {
749 ctx.book.set_version(version);
750 }
751 ctx.book.xmlns.insert("content.xml".to_string(), xmlns);
752 }
753 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:document-content" => {}
754
755 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"office:scripts" => {}
756 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:scripts" => {
757 read_scripts(ctx, xml)?
758 }
759 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:font-face-decls" => {
760 read_office_font_face_decls(ctx, xml, StyleOrigin::Content)?
761 }
762 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:styles" => {
763 read_office_styles(ctx, xml, StyleOrigin::Content)?
764 }
765 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:automatic-styles" => {
766 read_office_automatic_styles(ctx, xml, StyleOrigin::Content)?
767 }
768 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:master-styles" => {
769 read_office_master_styles(ctx, xml, StyleOrigin::Content)?
770 }
771 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:body" => {
772 read_office_body(ctx, xml)?;
773 }
774
775 Event::Eof => {
776 break;
777 }
778 _ => {
779 unused_event("read_ods_content", &evt)?;
780 }
781 }
782
783 buf.clear();
784 }
785 ctx.push_buf(buf);
786
787 Ok(())
788}
789
790fn read_office_body(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
792 let mut buf = ctx.pop_buf();
793 loop {
794 let evt = xml.read_event_into(&mut buf)?;
795 let empty_tag = matches!(evt, Event::Empty(_));
796 if cfg!(feature = "dump_xml") {
797 println!("read_office_body {:?}", evt);
798 }
799 match &evt {
800 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:body" => {}
801 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:body" => {
802 break;
803 }
804
805 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:spreadsheet" => {}
806 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:spreadsheet" => {}
807
808 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:content-validations" => {
809 read_validations(ctx, xml)?
810 }
811 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table" => {
812 read_table(ctx, xml, xml_tag)?
813 }
814
815 Event::Empty(xml_tag) | Event::Start(xml_tag)
817 if xml_tag.name().as_ref() == b"table:calculation-settings"
818 || xml_tag.name().as_ref() == b"table:label-ranges"
819 || xml_tag.name().as_ref() == b"table:tracked-changes"
820 || xml_tag.name().as_ref() == b"text:alphabetical-index-auto-mark-file"
821 || xml_tag.name().as_ref() == b"text:dde-connection-decls"
822 || xml_tag.name().as_ref() == b"text:sequence-decls"
823 || xml_tag.name().as_ref() == b"text:user-field-decls"
824 || xml_tag.name().as_ref() == b"text:variable-decls" =>
825 {
826 let v = read_xml(ctx, xml, xml_tag, empty_tag)?;
827 ctx.book.extra.push(v);
828 }
829 Event::Empty(xml_tag) | Event::Start(xml_tag)
831 if xml_tag.name().as_ref() == b"table:consolidation"
832 || xml_tag.name().as_ref() == b"table:data-pilot-tables"
833 || xml_tag.name().as_ref() == b"table:database-ranges"
834 || xml_tag.name().as_ref() == b"table:dde-links"
835 || xml_tag.name().as_ref() == b"table:named-expressions"
836 || xml_tag.name().as_ref() == b"calcext:conditional-formats" =>
837 {
838 let v = read_xml(ctx, xml, xml_tag, empty_tag)?;
839 ctx.book.extra.push(v);
840 }
841 Event::End(xml_tag)
843 if xml_tag.name().as_ref() == b"table:calculation-settings"
844 || xml_tag.name().as_ref() == b"table:label-ranges"
845 || xml_tag.name().as_ref() == b"table:tracked-changes"
846 || xml_tag.name().as_ref() == b"text:alphabetical-index-auto-mark-file"
847 || xml_tag.name().as_ref() == b"text:dde-connection-decls"
848 || xml_tag.name().as_ref() == b"text:sequence-decls"
849 || xml_tag.name().as_ref() == b"text:user-field-decls"
850 || xml_tag.name().as_ref() == b"text:variable-decls" => {}
851 Event::End(xml_tag)
853 if xml_tag.name().as_ref() == b"table:consolidation"
854 || xml_tag.name().as_ref() == b"table:data-pilot-tables"
855 || xml_tag.name().as_ref() == b"table:database-ranges"
856 || xml_tag.name().as_ref() == b"table:dde-links"
857 || xml_tag.name().as_ref() == b"table:named-expressions" => {}
858
859 Event::Eof => {
860 break;
861 }
862 _ => {
863 unused_event("read_office_body", &evt)?;
864 }
865 }
866
867 buf.clear();
868 }
869 ctx.push_buf(buf);
870
871 Ok(())
872}
873
874fn read_namespaces_and_version(
875 ctx: &mut OdsContext,
876 super_tag: &BytesStart<'_>,
877) -> Result<(Option<String>, NamespaceMap), OdsError> {
878 let mut version = None;
879 let mut xmlns = NamespaceMap::new();
880
881 for attr in super_tag.attributes().with_checks(false) {
882 match attr? {
883 attr if attr.key.as_ref() == b"office:version" => {
884 version = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
885 }
886 attr if attr.key.as_ref().starts_with(b"xmlns:") => {
887 let k = from_utf8(attr.key.as_ref())?.to_string();
888 let v = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
889 xmlns.insert(k, v);
890 }
891 attr if attr.key.as_ref() == b"office:mimetype" => {
892 if attr.decode_and_unescape_value(ctx.decoder)?
893 != "application/vnd.oasis.opendocument.spreadsheet"
894 {
895 return Err(OdsError::Parse(
896 "invalid content-type",
897 Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string()),
898 ));
899 }
900 }
901 attr => {
902 unused_attr(
903 "read_namespaces_and_version",
904 super_tag.name().as_ref(),
905 &attr,
906 )?;
907 }
908 }
909 }
910 Ok((version, xmlns))
911}
912
913fn read_table(
915 ctx: &mut OdsContext,
916 xml: &mut OdsXmlReader<'_>,
917 super_tag: &BytesStart<'_>,
918) -> Result<(), OdsError> {
919 let mut sheet = Sheet::new("");
920
921 read_table_attr(ctx, &mut sheet, super_tag)?;
922
923 let mut row: u32 = 0;
925 let mut col: u32 = 0;
926 let mut col_data: bool = false;
927
928 let mut col_range_from = 0;
930 let mut col_group = ctx.pop_colgroup_buf();
931
932 let mut row_repeat: u32 = 1;
934 let mut row_range_from = 0;
935 let mut row_group = ctx.pop_rowgroup_buf();
936
937 let mut buf = ctx.pop_buf();
938 loop {
939 let evt = xml.read_event_into(&mut buf)?;
940 let empty_tag = matches!(evt, Event::Empty(_));
941 if cfg!(feature = "dump_xml") {
942 println!(" read_table {:?}", evt);
943 }
944 match &evt {
945 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table" => {
946 break;
947 }
948
949 Event::Start(xml_tag) | Event::Empty(xml_tag)
951 if xml_tag.name().as_ref() == b"table:title"
952 || xml_tag.name().as_ref() == b"table:desc"
953 || xml_tag.name().as_ref() == b"table:table-source"
954 || xml_tag.name().as_ref() == b"office:dde-source"
955 || xml_tag.name().as_ref() == b"table:scenario"
956 || xml_tag.name().as_ref() == b"office:forms"
957 || xml_tag.name().as_ref() == b"table:shapes" =>
958 {
959 sheet.extra.push(read_xml(ctx, xml, xml_tag, empty_tag)?);
960 }
961 Event::End(xml_tag)
962 if xml_tag.name().as_ref() == b"table:title"
963 || xml_tag.name().as_ref() == b"table:desc"
964 || xml_tag.name().as_ref() == b"table:table-source"
965 || xml_tag.name().as_ref() == b"office:dde-source"
966 || xml_tag.name().as_ref() == b"table:scenario"
967 || xml_tag.name().as_ref() == b"office:forms"
968 || xml_tag.name().as_ref() == b"table:shapes" => {}
969
970 Event::Start(xml_tag) | Event::Empty(xml_tag)
972 if xml_tag.name().as_ref() == b"table:named-expressions"
973 || xml_tag.name().as_ref() == b"calcext:conditional-formats" =>
974 {
975 sheet.extra.push(read_xml(ctx, xml, xml_tag, empty_tag)?);
976 }
977 Event::End(xml_tag)
978 if xml_tag.name().as_ref() == b"table:named-expressions"
979 || xml_tag.name().as_ref() == b"calcext:conditional-formats" => {}
980
981 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-column-group" => {
985 let v = read_table_column_group_attr(col, xml_tag)?;
986 col_group.push(v);
987 }
988 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-column-group" => {
989 if let Some(mut v) = col_group.pop() {
990 v.set_to(col - 1);
991 sheet.group_cols.push(v);
992 }
993 }
994
995 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-header-columns" => {
996 col_range_from = col;
997 }
998 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-header-columns" => {
999 if let Some(header_cols) = &mut sheet.header_cols {
1000 header_cols.to = col - 1;
1001 } else {
1002 sheet.header_cols = Some(Header {
1003 from: col_range_from,
1004 to: col - 1,
1005 });
1006 }
1007 }
1008
1009 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-columns" => {}
1010 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-columns" => {}
1011
1012 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"table:table-column" => {
1013 let col_repeat = read_table_col_attr(ctx, &mut sheet, xml_tag, col)?;
1014 col += col_repeat;
1015 }
1016
1017 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-row-group" => {
1021 let v = read_table_row_group_attr(row, xml_tag)?;
1022 row_group.push(v);
1023 }
1024 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-row-group" => {
1025 if let Some(mut v) = row_group.pop() {
1026 v.set_to(row - 1);
1027 sheet.group_rows.push(v);
1028 } else {
1029 }
1031 }
1032
1033 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-header-rows" => {
1034 row_range_from = row;
1035 }
1036 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-header-rows" => {
1037 if let Some(header_rows) = &mut sheet.header_rows {
1038 header_rows.to = row - 1;
1039 } else {
1040 sheet.header_rows = Some(Header {
1041 from: row_range_from,
1042 to: row - 1,
1043 });
1044 }
1045 }
1046
1047 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-rows" => {
1048 }
1050 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-rows" => {
1051 }
1053 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:table-row" => {
1054 col = 0;
1055 row_repeat = read_table_row_attr(ctx, &mut sheet, row, xml_tag)?;
1056 }
1057 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-row" => {
1058 if col_data {
1059 sheet.set_row_repeat(row, row_repeat);
1061 }
1062 row += row_repeat;
1063 row_repeat = 1;
1064 col_data = false;
1065 }
1066
1067 Event::Empty(xml_tag) | Event::Start(xml_tag)
1071 if xml_tag.name().as_ref() == b"table:table-cell"
1072 || xml_tag.name().as_ref() == b"table:covered-table-cell" =>
1073 {
1074 let (cell_repeat, have_data) =
1075 read_table_cell(ctx, xml, &mut sheet, row, col, xml_tag, empty_tag)?;
1076 col += cell_repeat;
1077 col_data |= have_data;
1078 }
1079
1080 _ => {
1081 unused_event("read_table", &evt)?;
1082 }
1083 }
1084 buf.clear();
1085 }
1086
1087 ctx.push_buf(buf);
1088 ctx.push_colgroup_buf(col_group);
1089 ctx.push_rowgroup_buf(row_group);
1090
1091 ctx.book.push_sheet(sheet);
1092
1093 Ok(())
1094}
1095
1096fn read_table_attr(
1098 ctx: &mut OdsContext,
1099 sheet: &mut Sheet,
1100 super_tag: &BytesStart<'_>,
1101) -> Result<(), OdsError> {
1102 for attr in super_tag.attributes().with_checks(false) {
1103 match attr? {
1104 attr if attr.key.as_ref() == b"table:name" => {
1105 sheet.set_name(attr.decode_and_unescape_value(ctx.decoder)?);
1106 }
1107 attr if attr.key.as_ref() == b"table:style-name" => {
1108 let name = &attr.decode_and_unescape_value(ctx.decoder)?;
1109 sheet.style = Some(TableStyleRef::from(name.as_ref()));
1110 }
1111 attr if attr.key.as_ref() == b"table:print" => {
1112 sheet.set_print(parse_bool(&attr.value)?);
1113 }
1114 attr if attr.key.as_ref() == b"table:display" => {
1115 sheet.set_display(parse_bool(&attr.value)?);
1116 }
1117 attr if attr.key.as_ref() == b"table:print-ranges" => {
1118 let v = attr.decode_and_unescape_value(ctx.decoder)?;
1119 sheet.print_ranges = parse_cellranges(v.as_ref())?;
1120 }
1121 attr => {
1122 unused_attr("read_table_attr", super_tag.name().as_ref(), &attr)?;
1123 }
1124 }
1125 }
1126
1127 Ok(())
1128}
1129
1130fn read_table_row_attr(
1132 ctx: &mut OdsContext,
1133 sheet: &mut Sheet,
1134 row: u32,
1135 super_tag: &BytesStart<'_>,
1136) -> Result<u32, OdsError> {
1137 let mut row_repeat: u32 = 1;
1138 let mut row_header = None;
1139
1140 for attr in super_tag.attributes().with_checks(false) {
1141 match attr? {
1142 attr if attr.key.as_ref() == b"table:number-rows-repeated" => {
1144 row_repeat = parse_u32(&attr.value)?;
1145 }
1146 attr if attr.key.as_ref() == b"table:style-name" => {
1147 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1148 row_header.get_or_insert_with(RowHeader::default).style =
1149 Some(RowStyleRef::from(name.as_ref()));
1150 }
1151 attr if attr.key.as_ref() == b"table:default-cell-style-name" => {
1152 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1153 row_header.get_or_insert_with(RowHeader::default).cellstyle =
1154 Some(CellStyleRef::from(name.as_ref()));
1155 }
1156 attr if attr.key.as_ref() == b"table:visibility" => {
1157 let visible = parse_visibility(&attr.value)?;
1158 row_header.get_or_insert_with(RowHeader::default).visible = visible;
1159 }
1160 attr => {
1161 unused_attr("read_table_row_attr", super_tag.name().as_ref(), &attr)?;
1162 }
1163 }
1164 }
1165
1166 if let Some(mut row_header) = row_header {
1167 row_header.repeat = row_repeat;
1168 sheet.row_header.insert(row, row_header);
1169 }
1170
1171 Ok(row_repeat)
1172}
1173
1174fn read_table_column_group_attr(
1176 table_col: u32,
1177 super_tag: &BytesStart<'_>,
1178) -> Result<Grouped, OdsError> {
1179 let mut display = true;
1180
1181 for attr in super_tag.attributes().with_checks(false) {
1182 match attr? {
1183 attr if attr.key.as_ref() == b"table:display" => {
1184 display = parse_bool(&attr.value)?;
1185 }
1186 attr => {
1187 unused_attr(
1188 "read_table_column_group_attr",
1189 super_tag.name().as_ref(),
1190 &attr,
1191 )?;
1192 }
1193 }
1194 }
1195
1196 Ok(Grouped {
1197 from: table_col,
1198 to: 0,
1199 display,
1200 })
1201}
1202
1203fn read_table_row_group_attr(row: u32, super_tag: &BytesStart<'_>) -> Result<Grouped, OdsError> {
1205 let mut display = true;
1206
1207 for attr in super_tag.attributes().with_checks(false) {
1208 match attr? {
1209 attr if attr.key.as_ref() == b"table:display" => {
1210 display = parse_bool(&attr.value)?;
1211 }
1212 attr => {
1213 unused_attr(
1214 "read_table_row_group_attr",
1215 super_tag.name().as_ref(),
1216 &attr,
1217 )?;
1218 }
1219 }
1220 }
1221
1222 Ok(Grouped {
1223 from: row,
1224 to: 0,
1225 display,
1226 })
1227}
1228
1229fn read_table_col_attr(
1231 ctx: &mut OdsContext,
1232 sheet: &mut Sheet,
1233 super_tag: &BytesStart<'_>,
1234 table_col: u32,
1235) -> Result<u32, OdsError> {
1236 let mut col_repeat = 1;
1237 let mut col_header = None;
1238
1239 for attr in super_tag.attributes().with_checks(false) {
1240 match attr? {
1241 attr if attr.key.as_ref() == b"table:number-columns-repeated" => {
1242 col_repeat = parse_u32(&attr.value)?;
1243 }
1244 attr if attr.key.as_ref() == b"table:style-name" => {
1245 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1246 col_header.get_or_insert_with(ColHeader::default).style =
1247 Some(ColStyleRef::from(name.as_ref()));
1248 }
1249 attr if attr.key.as_ref() == b"table:default-cell-style-name" => {
1250 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1251 col_header.get_or_insert_with(ColHeader::default).cellstyle =
1252 Some(CellStyleRef::from(name.as_ref()));
1253 }
1254 attr if attr.key.as_ref() == b"table:visibility" => {
1255 let visible = parse_visibility(&attr.value)?;
1256 col_header.get_or_insert_with(ColHeader::default).visible = visible;
1257 }
1258 attr => {
1259 unused_attr("read_table_col_attr", super_tag.name().as_ref(), &attr)?;
1260 }
1261 }
1262 }
1263
1264 if let Some(mut col_header) = col_header {
1265 col_header.span = col_repeat;
1266 sheet.col_header.insert(table_col, col_header);
1267 }
1268
1269 Ok(col_repeat)
1270}
1271
1272#[derive(Debug)]
1273#[allow(variant_size_differences)]
1274enum TextContent {
1275 Empty,
1276 Text(String),
1277 Xml(TextTag),
1278 XmlVec(Vec<TextTag>),
1279}
1280
1281#[derive(Debug)]
1282struct ReadTableCell {
1283 val_type: ValueType,
1284 val_datetime: Option<NaiveDateTime>,
1285 val_duration: Option<Duration>,
1286 val_float: Option<f64>,
1287 val_bool: Option<bool>,
1288 val_string: Option<String>,
1289 val_currency: Option<String>,
1290
1291 content: TextContent,
1292}
1293
1294fn read_table_cell(
1295 ctx: &mut OdsContext,
1296 xml: &mut OdsXmlReader<'_>,
1297 sheet: &mut Sheet,
1298 row: u32,
1299 col: u32,
1300 super_tag: &BytesStart<'_>,
1301 empty_tag: bool,
1302) -> Result<(u32, bool), OdsError> {
1303 let mut cell = None;
1304 let mut repeat = 1;
1305
1306 let default_cellstyle = if let Some(ch) = sheet.valid_col_header(col) {
1308 ch.cellstyle.as_ref()
1309 } else {
1310 None
1311 };
1312
1313 let mut tc = ReadTableCell {
1314 val_type: ValueType::Empty,
1315 val_datetime: None,
1316 val_duration: None,
1317 val_float: None,
1318 val_bool: None,
1319 val_string: None,
1320 val_currency: None,
1321 content: TextContent::Empty,
1322 };
1323
1324 for attr in super_tag.attributes().with_checks(false) {
1325 match attr? {
1326 attr if attr.key.as_ref() == b"table:number-columns-repeated" => {
1327 repeat = parse_u32(&attr.value)?;
1328 }
1329 attr if attr.key.as_ref() == b"table:number-rows-spanned" => {
1330 let row_span = parse_u32(&attr.value)?;
1331 if row_span > 1 {
1332 cell.get_or_insert_with(CellData::default)
1333 .extra_mut()
1334 .span
1335 .row_span = row_span;
1336 }
1337 }
1338 attr if attr.key.as_ref() == b"table:number-columns-spanned" => {
1339 let col_span = parse_u32(&attr.value)?;
1340 if col_span > 1 {
1341 cell.get_or_insert_with(CellData::default)
1342 .extra_mut()
1343 .span
1344 .col_span = col_span;
1345 }
1346 }
1347 attr if attr.key.as_ref() == b"table:number-matrix-rows-spanned" => {
1348 let row_span = parse_u32(&attr.value)?;
1349 if row_span > 1 {
1350 cell.get_or_insert_with(CellData::default)
1351 .extra_mut()
1352 .matrix_span
1353 .row_span = row_span;
1354 }
1355 }
1356 attr if attr.key.as_ref() == b"table:number-matrix-columns-spanned" => {
1357 let col_span = parse_u32(&attr.value)?;
1358 if col_span > 1 {
1359 cell.get_or_insert_with(CellData::default)
1360 .extra_mut()
1361 .matrix_span
1362 .col_span = col_span;
1363 }
1364 }
1365 attr if attr.key.as_ref() == b"table:content-validation-name" => {
1366 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1367 cell.get_or_insert_with(CellData::default)
1368 .extra_mut()
1369 .validation_name = Some(ValidationRef::from(name.as_ref()));
1370 }
1371 attr if attr.key.as_ref() == b"calcext:value-type" => {
1372 }
1374 attr if attr.key.as_ref() == b"office:value-type" => {
1375 cell.get_or_insert_with(CellData::default);
1376 tc.val_type = match attr.value.as_ref() {
1377 b"string" => ValueType::Text,
1378 b"float" => ValueType::Number,
1379 b"percentage" => ValueType::Percentage,
1380 b"date" => ValueType::DateTime,
1381 b"time" => ValueType::TimeDuration,
1382 b"boolean" => ValueType::Boolean,
1383 b"currency" => ValueType::Currency,
1384 other => {
1385 return Err(OdsError::Parse(
1386 "Unknown cell-type {:?}",
1387 Some(from_utf8(other)?.into()),
1388 ));
1389 }
1390 }
1391 }
1392 attr if attr.key.as_ref() == b"office:date-value" => {
1393 cell.get_or_insert_with(CellData::default);
1394 tc.val_datetime = Some(parse_datetime(&attr.value)?);
1395 }
1396 attr if attr.key.as_ref() == b"office:time-value" => {
1397 cell.get_or_insert_with(CellData::default);
1398 tc.val_duration = Some(parse_duration(&attr.value)?);
1399 }
1400 attr if attr.key.as_ref() == b"office:value" => {
1401 cell.get_or_insert_with(CellData::default);
1402 tc.val_float = Some(parse_f64(&attr.value)?);
1403 }
1404 attr if attr.key.as_ref() == b"office:boolean-value" => {
1405 cell.get_or_insert_with(CellData::default);
1406 tc.val_bool = Some(parse_bool(&attr.value)?);
1407 }
1408 attr if attr.key.as_ref() == b"office:string-value" => {
1409 cell.get_or_insert_with(CellData::default);
1410 tc.val_string = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
1411 }
1412 attr if attr.key.as_ref() == b"office:currency" => {
1413 cell.get_or_insert_with(CellData::default);
1414 tc.val_currency = Some(parse_currency(&attr.value)?);
1415 }
1416 attr if attr.key.as_ref() == b"table:formula" => {
1417 cell.get_or_insert_with(CellData::default).formula =
1418 Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
1419 }
1420 attr if attr.key.as_ref() == b"table:style-name" => {
1421 let name = attr.decode_and_unescape_value(ctx.decoder)?;
1422 cell.get_or_insert_with(CellData::default).style =
1423 Some(CellStyleRef::from(name.as_ref()));
1424 }
1425 attr => {
1426 unused_attr("read_table_cell2", super_tag.name().as_ref(), &attr)?;
1427 }
1428 }
1429 }
1430
1431 if !empty_tag {
1432 let mut buf = ctx.pop_buf();
1433 loop {
1434 let evt = xml.read_event_into(&mut buf)?;
1435 if cfg!(feature = "dump_xml") {
1436 println!(" read_table_cell {:?}", evt);
1437 }
1438 match &evt {
1439 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"text:p" => {
1440 tc.content = append_text(TextContent::Text(String::new()), tc.content);
1441 }
1442 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"text:p" => {
1443 let new_txt = read_text_or_tag(ctx, xml, xml_tag, false)?;
1444 tc.content = append_text(new_txt, tc.content);
1445 }
1446
1447 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:annotation" => {
1448 let annotation = read_annotation(ctx, xml, xml_tag)?;
1449 cell.get_or_insert_with(CellData::default)
1450 .extra_mut()
1451 .annotation = Some(annotation);
1452 }
1453 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"draw:frame" => {
1454 let draw_frame = read_draw_frame(ctx, xml, xml_tag)?;
1455 cell.get_or_insert_with(CellData::default)
1456 .extra_mut()
1457 .draw_frames
1458 .push(draw_frame);
1459 }
1460
1461 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
1462 break;
1463 }
1464 Event::Eof => {
1465 break;
1466 }
1467 _ => {
1468 unused_event("read_table_cell", &evt)?;
1469 }
1470 }
1471
1472 buf.clear();
1473 }
1474 ctx.push_buf(buf);
1475 }
1476
1477 let have_data = if let Some(mut cell) = cell {
1478 set_value(tc, &mut cell)?;
1480
1481 if ignore_cell(ctx, default_cellstyle, &cell) {
1483 false
1484 } else {
1485 cell.repeat = repeat;
1486 sheet.add_cell_data(row, col, cell);
1487 true
1488 }
1489 } else {
1490 false
1491 };
1492
1493 Ok((repeat, have_data))
1494}
1495
1496#[allow(clippy::if_same_then_else)]
1497#[inline]
1498fn ignore_cell(
1499 ctx: &mut OdsContext,
1500 default_cellstyle: Option<&CellStyleRef>,
1501 cell: &CellData,
1502) -> bool {
1503 if cell.is_void(default_cellstyle) {
1504 return true;
1505 }
1506 if ctx.ignore_empty_cells && cell.is_empty() {
1507 return true;
1508 }
1509 false
1510}
1511
1512fn append_text(new_txt: TextContent, mut content: TextContent) -> TextContent {
1513 content = match content {
1515 TextContent::Empty => new_txt,
1516 TextContent::Text(txt) => {
1517 let p = TextP::new().text(txt).into_xmltag();
1520 let mut vec = vec![p];
1521
1522 match new_txt {
1523 TextContent::Empty => {}
1524 TextContent::Text(txt) => {
1525 let p2 = TextP::new().text(txt).into_xmltag();
1526 vec.push(p2);
1527 }
1528 TextContent::Xml(xml) => {
1529 vec.push(xml);
1530 }
1531 TextContent::XmlVec(_) => {
1532 unreachable!();
1533 }
1534 }
1535 TextContent::XmlVec(vec)
1536 }
1537 TextContent::Xml(xml) => {
1538 let mut vec = vec![xml];
1539 match new_txt {
1540 TextContent::Empty => {}
1541 TextContent::Text(txt) => {
1542 let p2 = TextP::new().text(txt).into_xmltag();
1543 vec.push(p2);
1544 }
1545 TextContent::Xml(xml) => {
1546 vec.push(xml);
1547 }
1548 TextContent::XmlVec(_) => {
1549 unreachable!();
1550 }
1551 }
1552 TextContent::XmlVec(vec)
1553 }
1554 TextContent::XmlVec(mut vec) => {
1555 match new_txt {
1556 TextContent::Empty => {}
1557 TextContent::Text(txt) => {
1558 let p2 = TextP::new().text(txt).into_xmltag();
1559 vec.push(p2);
1560 }
1561 TextContent::Xml(xml) => {
1562 vec.push(xml);
1563 }
1564 TextContent::XmlVec(_) => {
1565 unreachable!();
1566 }
1567 }
1568 TextContent::XmlVec(vec)
1569 }
1570 };
1571
1572 content
1573}
1574
1575#[inline(always)]
1576fn set_value(tc: ReadTableCell, cell: &mut CellData) -> Result<(), OdsError> {
1577 match tc.val_type {
1578 ValueType::Empty => {
1579 }
1581 ValueType::Boolean => {
1582 if let Some(v) = tc.val_bool {
1583 cell.value = Value::Boolean(v);
1584 } else {
1585 return Err(OdsError::Parse("no boolean value", None));
1586 }
1587 }
1588 ValueType::Number => {
1589 if let Some(v) = tc.val_float {
1590 cell.value = Value::Number(v);
1591 } else {
1592 return Err(OdsError::Parse("no float value", None));
1593 }
1594 }
1595 ValueType::Percentage => {
1596 if let Some(v) = tc.val_float {
1597 cell.value = Value::Percentage(v);
1598 } else {
1599 return Err(OdsError::Parse("no float value", None));
1600 }
1601 }
1602 ValueType::Currency => {
1603 if let Some(v) = tc.val_float {
1604 if let Some(c) = tc.val_currency {
1605 cell.value = Value::Currency(v, c.into_boxed_str());
1606 } else {
1607 cell.value = Value::Currency(v, "".into());
1608 }
1609 } else {
1610 return Err(OdsError::Parse("no float value", None));
1611 }
1612 }
1613 ValueType::Text => {
1614 if let Some(v) = tc.val_string {
1615 cell.value = Value::Text(v);
1616 } else {
1617 match tc.content {
1618 TextContent::Empty => {
1619 }
1621 TextContent::Text(txt) => {
1622 cell.value = Value::Text(txt);
1623 }
1624 TextContent::Xml(xml) => {
1625 cell.value = Value::TextXml(vec![xml]);
1626 }
1627 TextContent::XmlVec(vec) => {
1628 cell.value = Value::TextXml(vec);
1629 }
1630 }
1631 }
1632 }
1633 ValueType::TextXml => {
1634 unreachable!();
1635 }
1636 ValueType::DateTime => {
1637 if let Some(v) = tc.val_datetime {
1638 cell.value = Value::DateTime(v);
1639 } else {
1640 return Err(OdsError::Parse("no datetime value", None));
1641 }
1642 }
1643 ValueType::TimeDuration => {
1644 if let Some(v) = tc.val_duration {
1645 cell.value = Value::TimeDuration(v);
1646 } else {
1647 return Err(OdsError::Parse("no duration value", None));
1648 }
1649 }
1650 }
1651
1652 Ok(())
1653}
1654
1655fn read_annotation(
1656 ctx: &mut OdsContext,
1657 xml: &mut OdsXmlReader<'_>,
1658 super_tag: &BytesStart<'_>,
1659) -> Result<Box<Annotation>, OdsError> {
1660 let mut annotation = Box::new(Annotation::new_empty());
1661
1662 for attr in super_tag.attributes().with_checks(false) {
1663 match attr? {
1664 attr if attr.key.as_ref() == b"office:display" => {
1665 annotation.set_display(parse_bool(&attr.value)?);
1666 }
1667 attr if attr.key.as_ref() == b"office:name" => {
1668 annotation.set_name(attr.decode_and_unescape_value(ctx.decoder)?);
1669 }
1670 attr => {
1671 let k = from_utf8(attr.key.as_ref())?;
1672 let v = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
1673 annotation.attrmap_mut().push_attr(k, v);
1674 }
1675 }
1676 }
1677
1678 let mut buf = ctx.pop_buf();
1679 loop {
1680 let evt = xml.read_event_into(&mut buf)?;
1681 let empty_tag = matches!(evt, Event::Empty(_));
1682 if cfg!(feature = "dump_xml") {
1683 println!("read_annotation {:?}", evt);
1684 }
1685 match &evt {
1686 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:annotation" => {
1687 break;
1688 }
1689
1690 Event::Start(xml_tag) | Event::Empty(xml_tag)
1691 if xml_tag.name().as_ref() == b"dc:creator" =>
1692 {
1693 annotation.set_creator(read_text(ctx, xml, xml_tag, empty_tag, parse_string)?);
1694 }
1695 Event::Start(xml_tag) | Event::Empty(xml_tag)
1696 if xml_tag.name().as_ref() == b"dc:date" =>
1697 {
1698 annotation.set_date(read_text(ctx, xml, xml_tag, empty_tag, parse_datetime)?);
1699 }
1700 Event::Start(xml_tag) | Event::Empty(xml_tag)
1701 if xml_tag.name().as_ref() == b"text:list"
1702 || xml_tag.name().as_ref() == b"text:p" =>
1703 {
1704 annotation.push_text(read_xml(ctx, xml, xml_tag, empty_tag)?);
1705 }
1706
1707 Event::Eof => {
1708 break;
1709 }
1710 _ => {
1711 unused_event("read_annotation", &evt)?;
1712 }
1713 }
1714
1715 buf.clear();
1716 }
1717 ctx.push_buf(buf);
1718
1719 Ok(annotation)
1720}
1721
1722fn read_draw_frame(
1723 ctx: &mut OdsContext,
1724 xml: &mut OdsXmlReader<'_>,
1725 super_tag: &BytesStart<'_>,
1726) -> Result<DrawFrame, OdsError> {
1727 let mut draw_frame = DrawFrame::new();
1728
1729 copy_attr2(ctx, draw_frame.attrmap_mut(), super_tag)?;
1730
1731 let mut buf = ctx.pop_buf();
1732 loop {
1733 let evt = xml.read_event_into(&mut buf)?;
1734 let empty_tag = matches!(evt, Event::Empty(_));
1735 if cfg!(feature = "dump_xml") {
1736 println!("read_draw_frame {:?}", evt);
1737 }
1738 match &evt {
1739 Event::End(xml_tag) if xml_tag.name().as_ref() == b"draw:frame" => {
1740 break;
1741 }
1742 Event::Empty(xml_tag) | Event::Start(xml_tag)
1743 if xml_tag.name().as_ref() == b"draw:image" =>
1744 {
1745 draw_frame.push_content(DrawFrameContent::Image(read_image(
1746 ctx, xml, xml_tag, empty_tag,
1747 )?));
1748 }
1749 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"svg:desc" => {}
1750 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"svg:desc" => {
1751 if let Some(v) = read_text(ctx, xml, xml_tag, empty_tag, parse_string)? {
1752 draw_frame.set_desc(v);
1753 }
1754 }
1755 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"svg:title" => {}
1756 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"svg:title" => {
1757 if let Some(v) = read_text(ctx, xml, xml_tag, empty_tag, parse_string)? {
1758 draw_frame.set_title(v);
1759 }
1760 }
1761 Event::Eof => {
1762 break;
1763 }
1764 _ => {
1765 unused_event("read_draw_frame", &evt)?;
1766 }
1767 }
1768
1769 buf.clear();
1770 }
1771 ctx.push_buf(buf);
1772
1773 Ok(draw_frame)
1774}
1775
1776fn read_image(
1777 ctx: &mut OdsContext,
1778 xml: &mut OdsXmlReader<'_>,
1779 super_tag: &BytesStart<'_>,
1780 empty_tag: bool,
1781) -> Result<DrawImage, OdsError> {
1782 let mut draw_image = DrawImage::new();
1783
1784 copy_attr2(ctx, draw_image.attrmap_mut(), super_tag)?;
1785
1786 if !empty_tag {
1787 let mut buf = ctx.pop_buf();
1788 loop {
1789 let evt = xml.read_event_into(&mut buf)?;
1790 let empty_tag = matches!(evt, Event::Empty(_));
1791 if cfg!(feature = "dump_xml") {
1792 println!("read_image {:?}", evt);
1793 }
1794 match &evt {
1795 Event::End(xml_tag) if xml_tag.name().as_ref() == b"draw:image" => {
1796 break;
1797 }
1798
1799 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:binary-data" => {
1800 if let Some(v) = read_text(ctx, xml, xml_tag, empty_tag, parse_string)? {
1801 draw_image.set_binary_base64(v);
1802 }
1803 }
1804 Event::Start(xml_tag) | Event::Empty(xml_tag)
1805 if xml_tag.name().as_ref() == b"text:list"
1806 || xml_tag.name().as_ref() == b"text:p" =>
1807 {
1808 draw_image.push_text(read_xml(ctx, xml, xml_tag, empty_tag)?);
1809 }
1810
1811 Event::Eof => {
1812 break;
1813 }
1814 _ => {
1815 unused_event("read_image", &evt)?;
1816 }
1817 }
1818
1819 buf.clear();
1820 }
1821 ctx.push_buf(buf);
1822 }
1823
1824 Ok(draw_image)
1825}
1826
1827fn read_scripts(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
1828 let mut buf = ctx.pop_buf();
1829 loop {
1830 let evt = xml.read_event_into(&mut buf)?;
1831 if cfg!(feature = "dump_xml") {
1832 println!("read_scripts {:?}", evt);
1833 }
1834 match &evt {
1835 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:scripts" => {
1836 break;
1837 }
1838
1839 Event::Start(xml_tag) | Event::Empty(xml_tag)
1840 if xml_tag.name().as_ref() == b"office:script" =>
1841 {
1842 let script = read_script(ctx, xml, xml_tag)?;
1843 ctx.book.add_script(script);
1844 }
1845
1846 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:event-listeners" => {}
1847 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:event-listeners" => {}
1848
1849 Event::Start(xml_tag) | Event::Empty(xml_tag)
1850 if xml_tag.name().as_ref() == b"script:event-listener" =>
1851 {
1852 let evt_listener = read_event_listener(ctx, xml_tag)?;
1853 ctx.book.add_event_listener(evt_listener);
1854 }
1855 Event::End(xml_tag) if xml_tag.name().as_ref() == b"script:event-listener" => {}
1856
1857 Event::Eof => {
1858 break;
1859 }
1860 _ => {
1861 unused_event("read_scripts", &evt)?;
1862 }
1863 }
1864
1865 buf.clear();
1866 }
1867 ctx.push_buf(buf);
1868
1869 Ok(())
1870}
1871
1872fn read_script(
1873 ctx: &mut OdsContext,
1874 xml: &mut OdsXmlReader<'_>,
1875 super_tag: &BytesStart<'_>,
1876) -> Result<Script, OdsError> {
1877 let v = read_xml(ctx, xml, super_tag, false)?;
1878 let script: Script = Script {
1879 script_lang: v
1880 .get_attr("script:language")
1881 .map(|v| v.to_string())
1882 .unwrap_or_default(),
1883 script: v.into_mixed_vec(),
1884 };
1885 Ok(script)
1886}
1887
1888fn read_event_listener(
1890 ctx: &mut OdsContext,
1891 super_tag: &BytesStart<'_>,
1892) -> Result<EventListener, OdsError> {
1893 let mut evt = EventListener::new();
1894 for attr in super_tag.attributes().with_checks(false) {
1895 match attr? {
1896 attr if attr.key.as_ref() == b"script:event-name" => {
1897 evt.event_name = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
1898 }
1899 attr if attr.key.as_ref() == b"script:language" => {
1900 evt.script_lang = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
1901 }
1902 attr if attr.key.as_ref() == b"script:macro-name" => {
1903 evt.macro_name = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
1904 }
1905 attr if attr.key.as_ref() == b"xlink:actuate" => {
1906 evt.actuate =
1907 parse_xlink_actuate(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
1908 }
1909 attr if attr.key.as_ref() == b"xlink:href" => {
1910 evt.href = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
1911 }
1912 attr if attr.key.as_ref() == b"xlink:type" => {
1913 evt.link_type =
1914 parse_xlink_type(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
1915 }
1916 attr => {
1917 unused_attr("read_event_listener", super_tag.name().as_ref(), &attr)?;
1918 }
1919 }
1920 }
1921 Ok(evt)
1922}
1923
1924fn read_office_font_face_decls(
1926 ctx: &mut OdsContext,
1927 xml: &mut OdsXmlReader<'_>,
1928 origin: StyleOrigin,
1929) -> Result<(), OdsError> {
1930 let mut font: FontFaceDecl = FontFaceDecl::new_empty();
1931 font.set_origin(origin);
1932
1933 let mut buf = ctx.pop_buf();
1934 loop {
1935 let evt = xml.read_event_into(&mut buf)?;
1936 if cfg!(feature = "dump_xml") {
1937 println!(" read_fonts {:?}", evt);
1938 }
1939 match &evt {
1940 Event::Start(xml_tag) | Event::Empty(xml_tag)
1941 if xml_tag.name().as_ref() == b"style:font-face" =>
1942 {
1943 let name = copy_style_attr(ctx, font.attrmap_mut(), xml_tag)?;
1944 font.set_name(name);
1945 ctx.book.add_font(font);
1946
1947 font = FontFaceDecl::new_empty();
1948 font.set_origin(StyleOrigin::Content);
1949 }
1950 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:font-face-decls" => {
1951 break;
1952 }
1953 Event::Eof => {
1954 break;
1955 }
1956 _ => {
1957 unused_event("read_fonts", &evt)?;
1958 }
1959 }
1960
1961 buf.clear();
1962 }
1963 ctx.push_buf(buf);
1964
1965 Ok(())
1966}
1967
1968fn read_page_style(
1970 ctx: &mut OdsContext,
1971 xml: &mut OdsXmlReader<'_>,
1972 super_tag: &BytesStart<'_>,
1973) -> Result<(), OdsError> {
1974 let mut pl = PageStyle::new_empty();
1975 for attr in super_tag.attributes().with_checks(false) {
1976 match attr? {
1977 attr if attr.key.as_ref() == b"style:name" => {
1978 let value = attr.decode_and_unescape_value(ctx.decoder)?;
1979 pl.set_name(value);
1980 }
1981 attr if attr.key.as_ref() == b"style:page-usage" => {
1982 let value = attr.decode_and_unescape_value(ctx.decoder)?;
1983 pl.master_page_usage = Some(value.to_string());
1984 }
1985 attr => {
1986 unused_attr("read_page_style", super_tag.name().as_ref(), &attr)?;
1987 }
1988 }
1989 }
1990
1991 let mut headerstyle = false;
1992 let mut footerstyle = false;
1993
1994 let mut buf = ctx.pop_buf();
1995 loop {
1996 let evt = xml.read_event_into(&mut buf)?;
1997 if cfg!(feature = "dump_xml") {
1998 println!(" read_page_layout {:?}", evt);
1999 }
2000 match &evt {
2001 Event::Start(xml_tag) | Event::Empty(xml_tag)
2002 if xml_tag.name().as_ref() == b"style:page-layout-properties" =>
2003 {
2004 copy_attr2(ctx, pl.style_mut(), xml_tag)?;
2005 }
2006 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:page-layout-properties" => {}
2007
2008 Event::Start(xml_tag) | Event::Empty(xml_tag)
2009 if xml_tag.name().as_ref() == b"style:header-style" =>
2010 {
2011 headerstyle = true;
2012 }
2013 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:header-style" => {
2014 headerstyle = false;
2015 }
2016
2017 Event::Start(xml_tag) | Event::Empty(xml_tag)
2018 if xml_tag.name().as_ref() == b"style:footer-style" =>
2019 {
2020 footerstyle = true;
2021 }
2022 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:footer-style" => {
2023 footerstyle = false;
2024 }
2025
2026 Event::Start(xml_tag) | Event::Empty(xml_tag)
2027 if xml_tag.name().as_ref() == b"style:header-footer-properties" =>
2028 {
2029 if headerstyle {
2030 copy_attr2(ctx, pl.headerstyle_mut().style_mut(), xml_tag)?;
2031 }
2032 if footerstyle {
2033 copy_attr2(ctx, pl.footerstyle_mut().style_mut(), xml_tag)?;
2034 }
2035 }
2036 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:header-footer-properties" => {
2037 }
2038
2039 Event::Start(xml_tag) | Event::Empty(xml_tag)
2040 if xml_tag.name().as_ref() == b"style:background-image" =>
2041 {
2042 }
2044
2045 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:page-layout" => {
2046 break;
2047 }
2048 Event::Text(_) => (),
2049 Event::Eof => break,
2050 _ => {
2051 unused_event("read_page_layout", &evt)?;
2052 }
2053 }
2054
2055 buf.clear();
2056 }
2057 ctx.push_buf(buf);
2058
2059 ctx.book.add_pagestyle(pl);
2060
2061 Ok(())
2062}
2063
2064fn read_validations(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
2065 let mut valid = Validation::new();
2066
2067 let mut buf = ctx.pop_buf();
2068 loop {
2069 let evt = xml.read_event_into(&mut buf)?;
2070 let empty_tag = matches!(evt, Event::Empty(_));
2071 if cfg!(feature = "dump_xml") {
2072 println!(" read_validations {:?}", evt);
2073 }
2074 match &evt {
2075 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:content-validation" => {
2076 read_validation(ctx, &mut valid, xml_tag)?;
2077 ctx.book.add_validation(valid);
2078 valid = Validation::new();
2079 }
2080 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"table:content-validation" => {
2081 read_validation(ctx, &mut valid, xml_tag)?;
2082 }
2083 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:content-validation" => {
2084 ctx.book.add_validation(valid);
2085 valid = Validation::new();
2086 }
2087
2088 Event::Start(xml_tag) | Event::Empty(xml_tag)
2089 if xml_tag.name().as_ref() == b"table:error-message" =>
2090 {
2091 read_validation_error(ctx, xml, &mut valid, xml_tag, empty_tag)?;
2092 }
2093
2094 Event::Start(xml_tag) | Event::Empty(xml_tag)
2095 if xml_tag.name().as_ref() == b"table:help-message" =>
2096 {
2097 read_validation_help(ctx, xml, &mut valid, xml_tag, empty_tag)?;
2098 }
2099
2100 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:content-validations" => {
2101 break;
2102 }
2103
2104 Event::Text(_) => (),
2105 Event::Eof => break,
2106 _ => {
2107 unused_event("read_validations", &evt)?;
2108 }
2109 }
2110 }
2111 ctx.push_buf(buf);
2112
2113 Ok(())
2114}
2115
2116fn read_validation_help(
2117 ctx: &mut OdsContext,
2118 xml: &mut OdsXmlReader<'_>,
2119 valid: &mut Validation,
2120 super_tag: &BytesStart<'_>,
2121 empty_tag: bool,
2122) -> Result<(), OdsError> {
2123 let mut vh = ValidationHelp::new();
2124
2125 for attr in super_tag.attributes().with_checks(false) {
2126 match attr? {
2127 attr if attr.key.as_ref() == b"table:display" => {
2128 vh.set_display(parse_bool(&attr.value)?);
2129 }
2130 attr if attr.key.as_ref() == b"table:title" => {
2131 vh.set_title(Some(
2132 attr.decode_and_unescape_value(ctx.decoder)?.to_string(),
2133 ));
2134 }
2135 attr => {
2136 unused_attr("read_validations", super_tag.name().as_ref(), &attr)?;
2137 }
2138 }
2139 }
2140 let txt = read_text_or_tag(ctx, xml, super_tag, empty_tag)?;
2141 match txt {
2142 TextContent::Empty => {}
2143 TextContent::Xml(txt) => {
2144 vh.set_text(Some(txt));
2145 }
2146 _ => {
2147 return Err(OdsError::Ods(format!(
2148 "table:help-message invalid {:?}",
2149 txt
2150 )));
2151 }
2152 }
2153
2154 valid.set_help(Some(vh));
2155 Ok(())
2156}
2157
2158fn read_validation_error(
2159 ctx: &mut OdsContext,
2160 xml: &mut OdsXmlReader<'_>,
2161 valid: &mut Validation,
2162 super_tag: &BytesStart<'_>,
2163 empty_tag: bool,
2164) -> Result<(), OdsError> {
2165 let mut ve = ValidationError::new();
2166
2167 for attr in super_tag.attributes().with_checks(false) {
2168 match attr? {
2169 attr if attr.key.as_ref() == b"table:display" => {
2170 ve.set_display(parse_bool(&attr.value)?);
2171 }
2172 attr if attr.key.as_ref() == b"table:message-type" => {
2173 let mt = match attr.value.as_ref() {
2174 b"stop" => MessageType::Error,
2175 b"warning" => MessageType::Warning,
2176 b"information" => MessageType::Info,
2177 _ => {
2178 return Err(OdsError::Parse(
2179 "unknown message-type",
2180 Some(attr.decode_and_unescape_value(ctx.decoder)?.into()),
2181 ));
2182 }
2183 };
2184 ve.set_msg_type(mt);
2185 }
2186 attr if attr.key.as_ref() == b"table:title" => {
2187 ve.set_title(Some(
2188 attr.decode_and_unescape_value(ctx.decoder)?.to_string(),
2189 ));
2190 }
2191 attr => {
2192 unused_attr("read_validations", super_tag.name().as_ref(), &attr)?;
2193 }
2194 }
2195 }
2196 let txt = read_text_or_tag(ctx, xml, super_tag, empty_tag)?;
2197 match txt {
2198 TextContent::Empty => {}
2199 TextContent::Xml(txt) => {
2200 ve.set_text(Some(txt));
2201 }
2202 _ => {
2203 return Err(OdsError::Ods(format!(
2204 "table:error-message invalid {:?}",
2205 txt
2206 )));
2207 }
2208 }
2209
2210 valid.set_err(Some(ve));
2211
2212 Ok(())
2213}
2214
2215fn read_validation(
2216 ctx: &mut OdsContext,
2217 valid: &mut Validation,
2218 super_tag: &BytesStart<'_>,
2219) -> Result<(), OdsError> {
2220 for attr in super_tag.attributes().with_checks(false) {
2221 match attr? {
2222 attr if attr.key.as_ref() == b"table:name" => {
2223 valid.set_name(attr.decode_and_unescape_value(ctx.decoder)?);
2224 }
2225 attr if attr.key.as_ref() == b"table:condition" => {
2226 let v = attr.decode_and_unescape_value(ctx.decoder)?;
2228 valid.set_condition(Condition::new(v.split_at(3).1));
2229 }
2230 attr if attr.key.as_ref() == b"table:allow-empty-cell" => {
2231 valid.set_allow_empty(parse_bool(&attr.value)?);
2232 }
2233 attr if attr.key.as_ref() == b"table:base-cell-address" => {
2234 let v = attr.decode_and_unescape_value(ctx.decoder)?;
2235 valid.set_base_cell(parse_cellref(&v)?);
2236 }
2237 attr if attr.key.as_ref() == b"table:display-list" => {
2238 valid.set_display(attr.value.as_ref().try_into()?);
2239 }
2240 attr => {
2241 unused_attr("read_validation", super_tag.name().as_ref(), &attr)?;
2242 }
2243 }
2244 }
2245 Ok(())
2246}
2247
2248fn read_office_master_styles(
2250 ctx: &mut OdsContext,
2251 xml: &mut OdsXmlReader<'_>,
2252 origin: StyleOrigin,
2253) -> Result<(), OdsError> {
2254 let mut buf = ctx.pop_buf();
2255 loop {
2256 let evt = xml.read_event_into(&mut buf)?;
2257 if cfg!(feature = "dump_xml") {
2258 println!(" read_master_styles {:?}", evt);
2259 }
2260 match &evt {
2261 Event::Start(xml_tag) | Event::Empty(xml_tag)
2262 if xml_tag.name().as_ref() == b"style:master-page" =>
2263 {
2264 read_master_page(ctx, xml, origin, xml_tag)?;
2265 }
2266 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:master-styles" => {
2267 break;
2268 }
2269 Event::Text(_) => (),
2270 Event::Eof => break,
2271 _ => {
2272 unused_event("read_master_styles", &evt)?;
2273 }
2274 }
2275
2276 buf.clear();
2277 }
2278 ctx.push_buf(buf);
2279
2280 Ok(())
2281}
2282
2283fn read_master_page(
2285 ctx: &mut OdsContext,
2286 xml: &mut OdsXmlReader<'_>,
2287 _origin: StyleOrigin,
2288 super_tag: &BytesStart<'_>,
2289) -> Result<(), OdsError> {
2290 let mut masterpage = MasterPage::new_empty();
2291
2292 for attr in super_tag.attributes().with_checks(false) {
2293 match attr? {
2294 attr if attr.key.as_ref() == b"style:name" => {
2295 masterpage.set_name(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
2296 }
2297 attr if attr.key.as_ref() == b"style:page-layout-name" => {
2298 masterpage
2299 .set_pagestyle(&attr.decode_and_unescape_value(ctx.decoder)?.as_ref().into());
2300 }
2301 attr if attr.key.as_ref() == b"style:display-name" => {
2302 masterpage
2303 .set_display_name(attr.decode_and_unescape_value(ctx.decoder)?.as_ref().into());
2304 }
2305 attr if attr.key.as_ref() == b"style:next-style-name" => {
2306 let v = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
2307 masterpage.set_next_masterpage(&MasterPageRef::from(v));
2308 }
2309 attr => {
2310 unused_attr("read_master_page", super_tag.name().as_ref(), &attr)?;
2311 }
2312 }
2313 }
2314
2315 let mut buf = ctx.pop_buf();
2316 loop {
2317 let evt = xml.read_event_into(&mut buf)?;
2318 if cfg!(feature = "dump_xml") {
2319 println!(" read_master_page {:?}", evt);
2320 }
2321 match &evt {
2322 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:header" => {}
2323 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:header" => {
2324 masterpage.set_header(read_headerfooter(ctx, xml, xml_tag)?);
2325 }
2326 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:header-first" => {}
2327 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:header-first" => {
2328 masterpage.set_header_first(read_headerfooter(ctx, xml, xml_tag)?);
2329 }
2330 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:header-left" => {}
2331 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:header-left" => {
2332 masterpage.set_header_left(read_headerfooter(ctx, xml, xml_tag)?);
2333 }
2334 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:footer" => {}
2335 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:footer" => {
2336 masterpage.set_footer(read_headerfooter(ctx, xml, xml_tag)?);
2337 }
2338 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:footer-first" => {}
2339 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:footer-first" => {
2340 masterpage.set_footer_first(read_headerfooter(ctx, xml, xml_tag)?);
2341 }
2342 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"style:footer-left" => {}
2343 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"style:footer-left" => {
2344 masterpage.set_footer_left(read_headerfooter(ctx, xml, xml_tag)?);
2345 }
2346 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:master-page" => {
2347 break;
2348 }
2349 Event::Eof => break,
2350 _ => {
2351 unused_event("read_master_page", &evt)?;
2352 }
2353 }
2354
2355 buf.clear();
2356 }
2357 ctx.push_buf(buf);
2358
2359 ctx.book.add_masterpage(masterpage);
2360
2361 Ok(())
2362}
2363
2364fn read_headerfooter(
2366 ctx: &mut OdsContext,
2367 xml: &mut OdsXmlReader<'_>,
2368 super_tag: &BytesStart<'_>,
2369) -> Result<HeaderFooter, OdsError> {
2370 let mut hf = HeaderFooter::new();
2371 let mut content = TextContent::Empty;
2372
2373 for attr in super_tag.attributes().with_checks(false) {
2374 match attr? {
2375 attr if attr.key.as_ref() == b"style:display" => {
2376 hf.set_display(parse_bool(&attr.value)?);
2377 }
2378 attr => {
2379 unused_attr("read_headerfooter", super_tag.name().as_ref(), &attr)?;
2380 }
2381 }
2382 }
2383
2384 let mut buf = ctx.pop_buf();
2385 loop {
2386 let evt = xml.read_event_into(&mut buf)?;
2387 let empty_tag = matches!(evt, Event::Empty(_));
2388 if cfg!(feature = "dump_xml") {
2389 println!(" read_headerfooter {:?}", evt);
2390 }
2391 match &evt {
2392 Event::Start(xml_tag) | Event::Empty(xml_tag)
2393 if xml_tag.name().as_ref() == b"style:region-left" =>
2394 {
2395 let reg = read_xml(ctx, xml, xml_tag, empty_tag)?;
2396 hf.set_left(reg.into_vec()?);
2397 }
2398 Event::Start(xml_tag) | Event::Empty(xml_tag)
2399 if xml_tag.name().as_ref() == b"style:region-center" =>
2400 {
2401 let reg = read_xml(ctx, xml, xml_tag, empty_tag)?;
2402 hf.set_center(reg.into_vec()?);
2403 }
2404 Event::Start(xml_tag) | Event::Empty(xml_tag)
2405 if xml_tag.name().as_ref() == b"style:region-right" =>
2406 {
2407 let reg = read_xml(ctx, xml, xml_tag, empty_tag)?;
2408 hf.set_right(reg.into_vec()?);
2409 }
2410
2411 Event::Start(xml_tag) | Event::Empty(xml_tag)
2412 if xml_tag.name().as_ref() == b"text:p" =>
2413 {
2414 let new_txt = read_text_or_tag(ctx, xml, xml_tag, empty_tag)?;
2415 content = append_text(new_txt, content);
2416 }
2417 Event::Start(xml_tag) | Event::Empty(xml_tag)
2418 if xml_tag.name().as_ref() == b"text:h" =>
2419 {
2420 let new_txt = read_text_or_tag(ctx, xml, xml_tag, empty_tag)?;
2421 content = append_text(new_txt, content);
2422 }
2423 Event::Text(_) => (),
2425 Event::End(xml_tag) => {
2426 if xml_tag.name() == super_tag.name() {
2427 hf.set_content(match content {
2428 TextContent::Empty => Vec::new(),
2429 TextContent::Text(v) => vec![TextP::new().text(v).into()],
2430 TextContent::Xml(v) => vec![v],
2431 TextContent::XmlVec(v) => v,
2432 });
2433 break;
2434 }
2435 }
2436 Event::Eof => break,
2437 _ => {
2438 unused_event("read_headerfooter", &evt)?;
2439 }
2440 }
2441
2442 buf.clear();
2443 }
2444 ctx.push_buf(buf);
2445
2446 Ok(hf)
2447}
2448
2449fn read_office_styles(
2451 ctx: &mut OdsContext,
2452 xml: &mut OdsXmlReader<'_>,
2453 origin: StyleOrigin,
2454) -> Result<(), OdsError> {
2455 let mut buf = ctx.pop_buf();
2456 loop {
2457 let evt = xml.read_event_into(&mut buf)?;
2458 let empty_tag = matches!(evt, Event::Empty(_));
2459 if cfg!(feature = "dump_xml") {
2460 println!(" read_styles_tag {:?}", evt);
2461 }
2462 match &evt {
2463 Event::Start(xml_tag) | Event::Empty(xml_tag)
2464 if xml_tag.name().as_ref() == b"style:style" =>
2465 {
2466 read_style_style(ctx, xml, origin, StyleUse::Named, xml_tag, empty_tag)?;
2467 }
2468 Event::Start(xml_tag) | Event::Empty(xml_tag)
2469 if xml_tag.name().as_ref() == b"style:default-style" =>
2470 {
2471 read_style_style(ctx, xml, origin, StyleUse::Default, xml_tag, empty_tag)?;
2472 }
2473 Event::Start(xml_tag) | Event::Empty(xml_tag)
2474 if xml_tag.name().as_ref() == b"number:boolean-style"
2475 || xml_tag.name().as_ref() == b"number:date-style"
2476 || xml_tag.name().as_ref() == b"number:time-style"
2477 || xml_tag.name().as_ref() == b"number:number-style"
2478 || xml_tag.name().as_ref() == b"number:currency-style"
2479 || xml_tag.name().as_ref() == b"number:percentage-style"
2480 || xml_tag.name().as_ref() == b"number:text-style" =>
2481 {
2482 read_value_format(ctx, xml, origin, StyleUse::Named, xml_tag)?;
2483 }
2484 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:styles" => {
2485 break;
2486 }
2487 Event::Text(_) => (),
2488 Event::Eof => break,
2489 _ => {
2490 unused_event("read_styles_tag", &evt)?;
2491 }
2492 }
2493
2494 buf.clear();
2495 }
2496 ctx.push_buf(buf);
2497
2498 Ok(())
2499}
2500
2501fn read_office_automatic_styles(
2503 ctx: &mut OdsContext,
2504 xml: &mut OdsXmlReader<'_>,
2505 origin: StyleOrigin,
2506) -> Result<(), OdsError> {
2507 let mut buf = ctx.pop_buf();
2508 loop {
2509 let evt = xml.read_event_into(&mut buf)?;
2510 let empty_tag = matches!(evt, Event::Empty(_));
2511 if cfg!(feature = "dump_xml") {
2512 println!(" read_auto_styles {:?}", evt);
2513 }
2514 match &evt {
2515 Event::Start(xml_tag) | Event::Empty(xml_tag)
2516 if xml_tag.name().as_ref() == b"style:style" =>
2517 {
2518 read_style_style(ctx, xml, origin, StyleUse::Automatic, xml_tag, empty_tag)?;
2519 }
2520 Event::Start(xml_tag) | Event::Empty(xml_tag)
2521 if xml_tag.name().as_ref() == b"number:boolean-style"
2522 || xml_tag.name().as_ref() == b"number:date-style"
2523 || xml_tag.name().as_ref() == b"number:time-style"
2524 || xml_tag.name().as_ref() == b"number:number-style"
2525 || xml_tag.name().as_ref() == b"number:currency-style"
2526 || xml_tag.name().as_ref() == b"number:percentage-style"
2527 || xml_tag.name().as_ref() == b"number:text-style" =>
2528 {
2529 read_value_format(ctx, xml, origin, StyleUse::Automatic, xml_tag)?;
2530 }
2531
2532 Event::Start(xml_tag) | Event::Empty(xml_tag)
2533 if xml_tag.name().as_ref() == b"style:page-layout" =>
2534 {
2535 read_page_style(ctx, xml, xml_tag)?;
2536 }
2537
2538 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:automatic-styles" => {
2539 break;
2540 }
2541 Event::Text(_) => (),
2542 Event::Eof => break,
2543 _ => {
2544 unused_event("read_auto_styles", &evt)?;
2545 }
2546 }
2547
2548 buf.clear();
2549 }
2550 ctx.push_buf(buf);
2551
2552 Ok(())
2553}
2554
2555fn read_value_format(
2557 ctx: &mut OdsContext,
2558 xml: &mut OdsXmlReader<'_>,
2559 origin: StyleOrigin,
2560 styleuse: StyleUse,
2561 super_tag: &BytesStart<'_>,
2562) -> Result<(), OdsError> {
2563 match super_tag.name().as_ref() {
2564 b"number:boolean-style" => {
2565 let mut valuestyle = ValueFormatBoolean::new_empty();
2566 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2567 ctx.book.add_boolean_format(valuestyle);
2568 }
2569 b"number:date-style" => {
2570 let mut valuestyle = ValueFormatDateTime::new_empty();
2571 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2572 ctx.book.add_datetime_format(valuestyle);
2573 }
2574 b"number:time-style" => {
2575 let mut valuestyle = ValueFormatTimeDuration::new_empty();
2576 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2577 ctx.book.add_timeduration_format(valuestyle);
2578 }
2579 b"number:number-style" => {
2580 let mut valuestyle = ValueFormatNumber::new_empty();
2581 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2582 ctx.book.add_number_format(valuestyle);
2583 }
2584 b"number:currency-style" => {
2585 let mut valuestyle = ValueFormatCurrency::new_empty();
2586 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2587 ctx.book.add_currency_format(valuestyle);
2588 }
2589 b"number:percentage-style" => {
2590 let mut valuestyle = ValueFormatPercentage::new_empty();
2591 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2592 ctx.book.add_percentage_format(valuestyle);
2593 }
2594 b"number:text-style" => {
2595 let mut valuestyle = ValueFormatText::new_empty();
2596 read_value_format_parts(ctx, xml, origin, styleuse, &mut valuestyle, super_tag)?;
2597 ctx.book.add_text_format(valuestyle);
2598 }
2599 _ => {
2600 if cfg!(feature = "dump_unused") {
2601 println!(
2602 " read_value_format unused {}",
2603 from_utf8(super_tag.name().as_ref())?
2604 );
2605 }
2606 }
2607 }
2608
2609 Ok(())
2610}
2611
2612fn read_value_format_parts<T: ValueFormatTrait>(
2614 ctx: &mut OdsContext,
2615 xml: &mut OdsXmlReader<'_>,
2616 origin: StyleOrigin,
2617 styleuse: StyleUse,
2618 valuestyle: &mut T,
2619 super_tag: &BytesStart<'_>,
2620) -> Result<(), OdsError> {
2621 valuestyle.set_origin(origin);
2623 valuestyle.set_styleuse(styleuse);
2624 let name = copy_style_attr(ctx, valuestyle.attrmap_mut(), super_tag)?;
2625 valuestyle.set_name(name.as_str());
2626
2627 let mut buf = ctx.pop_buf();
2628 loop {
2629 let evt = xml.read_event_into(&mut buf)?;
2630 let empty_tag = matches!(evt, Event::Empty(_));
2631 if cfg!(feature = "dump_xml") {
2632 println!(" read_value_format_parts {:?}", evt);
2633 }
2634 match &evt {
2635 Event::Start(xml_tag) | Event::Empty(xml_tag)
2636 if xml_tag.name().as_ref() == b"number:boolean" =>
2637 {
2638 valuestyle.push_part(read_part(
2639 ctx,
2640 xml,
2641 xml_tag,
2642 empty_tag,
2643 FormatPartType::Boolean,
2644 )?);
2645 }
2646 Event::Start(xml_tag) | Event::Empty(xml_tag)
2647 if xml_tag.name().as_ref() == b"number:number" =>
2648 {
2649 valuestyle.push_part(read_part_number(
2650 ctx,
2651 xml,
2652 xml_tag,
2653 empty_tag,
2654 FormatPartType::Number,
2655 )?);
2656 }
2657 Event::Start(xml_tag) | Event::Empty(xml_tag)
2658 if xml_tag.name().as_ref() == b"number:fraction" =>
2659 {
2660 valuestyle.push_part(read_part(
2661 ctx,
2662 xml,
2663 xml_tag,
2664 empty_tag,
2665 FormatPartType::Fraction,
2666 )?);
2667 }
2668 Event::Start(xml_tag) | Event::Empty(xml_tag)
2669 if xml_tag.name().as_ref() == b"number:scientific-number" =>
2670 {
2671 valuestyle.push_part(read_part(
2672 ctx,
2673 xml,
2674 xml_tag,
2675 empty_tag,
2676 FormatPartType::ScientificNumber,
2677 )?);
2678 }
2679 Event::Start(xml_tag) | Event::Empty(xml_tag)
2680 if xml_tag.name().as_ref() == b"number:text"
2681 || xml_tag.name().as_ref() == b"loext:text" =>
2682 {
2683 valuestyle.push_part(read_part_text(
2684 ctx,
2685 xml,
2686 xml_tag,
2687 empty_tag,
2688 FormatPartType::Text,
2689 )?);
2690 }
2691
2692 Event::Start(xml_tag) | Event::Empty(xml_tag)
2693 if xml_tag.name().as_ref() == b"number:am-pm" =>
2694 {
2695 valuestyle.push_part(read_part(
2696 ctx,
2697 xml,
2698 xml_tag,
2699 empty_tag,
2700 FormatPartType::AmPm,
2701 )?);
2702 }
2703 Event::Start(xml_tag) | Event::Empty(xml_tag)
2704 if xml_tag.name().as_ref() == b"number:day" =>
2705 {
2706 valuestyle.push_part(read_part(
2707 ctx,
2708 xml,
2709 xml_tag,
2710 empty_tag,
2711 FormatPartType::Day,
2712 )?);
2713 }
2714 Event::Start(xml_tag) | Event::Empty(xml_tag)
2715 if xml_tag.name().as_ref() == b"number:day-of-week" =>
2716 {
2717 valuestyle.push_part(read_part(
2718 ctx,
2719 xml,
2720 xml_tag,
2721 empty_tag,
2722 FormatPartType::DayOfWeek,
2723 )?);
2724 }
2725 Event::Start(xml_tag) | Event::Empty(xml_tag)
2726 if xml_tag.name().as_ref() == b"number:era" =>
2727 {
2728 valuestyle.push_part(read_part(
2729 ctx,
2730 xml,
2731 xml_tag,
2732 empty_tag,
2733 FormatPartType::Era,
2734 )?);
2735 }
2736 Event::Start(xml_tag) | Event::Empty(xml_tag)
2737 if xml_tag.name().as_ref() == b"number:hours" =>
2738 {
2739 valuestyle.push_part(read_part(
2740 ctx,
2741 xml,
2742 xml_tag,
2743 empty_tag,
2744 FormatPartType::Hours,
2745 )?);
2746 }
2747 Event::Start(xml_tag) | Event::Empty(xml_tag)
2748 if xml_tag.name().as_ref() == b"number:minutes" =>
2749 {
2750 valuestyle.push_part(read_part(
2751 ctx,
2752 xml,
2753 xml_tag,
2754 empty_tag,
2755 FormatPartType::Minutes,
2756 )?);
2757 }
2758 Event::Start(xml_tag) | Event::Empty(xml_tag)
2759 if xml_tag.name().as_ref() == b"number:month" =>
2760 {
2761 valuestyle.push_part(read_part(
2762 ctx,
2763 xml,
2764 xml_tag,
2765 empty_tag,
2766 FormatPartType::Month,
2767 )?);
2768 }
2769 Event::Start(xml_tag) | Event::Empty(xml_tag)
2770 if xml_tag.name().as_ref() == b"number:quarter" =>
2771 {
2772 valuestyle.push_part(read_part(
2773 ctx,
2774 xml,
2775 xml_tag,
2776 empty_tag,
2777 FormatPartType::Quarter,
2778 )?);
2779 }
2780 Event::Start(xml_tag) | Event::Empty(xml_tag)
2781 if xml_tag.name().as_ref() == b"number:seconds" =>
2782 {
2783 valuestyle.push_part(read_part(
2784 ctx,
2785 xml,
2786 xml_tag,
2787 empty_tag,
2788 FormatPartType::Seconds,
2789 )?);
2790 }
2791 Event::Start(xml_tag) | Event::Empty(xml_tag)
2792 if xml_tag.name().as_ref() == b"number:week-of-year" =>
2793 {
2794 valuestyle.push_part(read_part(
2795 ctx,
2796 xml,
2797 xml_tag,
2798 empty_tag,
2799 FormatPartType::WeekOfYear,
2800 )?);
2801 }
2802 Event::Start(xml_tag) | Event::Empty(xml_tag)
2803 if xml_tag.name().as_ref() == b"number:year" =>
2804 {
2805 valuestyle.push_part(read_part(
2806 ctx,
2807 xml,
2808 xml_tag,
2809 empty_tag,
2810 FormatPartType::Year,
2811 )?);
2812 }
2813
2814 Event::Start(xml_tag) | Event::Empty(xml_tag)
2815 if xml_tag.name().as_ref() == b"number:currency-symbol" =>
2816 {
2817 valuestyle.push_part(read_part_text(
2818 ctx,
2819 xml,
2820 xml_tag,
2821 empty_tag,
2822 FormatPartType::CurrencySymbol,
2823 )?);
2824 }
2825 Event::Start(xml_tag) | Event::Empty(xml_tag)
2826 if xml_tag.name().as_ref() == b"number:fill-character"
2827 || xml_tag.name().as_ref() == b"loext:fill-character" =>
2828 {
2829 valuestyle.push_part(read_part_text(
2830 ctx,
2831 xml,
2832 xml_tag,
2833 empty_tag,
2834 FormatPartType::FillCharacter,
2835 )?);
2836 }
2837 Event::Start(xml_tag) | Event::Empty(xml_tag)
2838 if xml_tag.name().as_ref() == b"number:text-content" =>
2839 {
2840 valuestyle.push_part(read_part(
2841 ctx,
2842 xml,
2843 xml_tag,
2844 empty_tag,
2845 FormatPartType::TextContent,
2846 )?);
2847 }
2848
2849 Event::Start(xml_tag) | Event::Empty(xml_tag)
2850 if xml_tag.name().as_ref() == b"style:map" =>
2851 {
2852 valuestyle.push_stylemap(read_value_stylemap(ctx, xml_tag)?);
2853 }
2854 Event::Start(xml_tag) | Event::Empty(xml_tag)
2855 if xml_tag.name().as_ref() == b"style:text-properties" =>
2856 {
2857 copy_attr2(ctx, valuestyle.textstyle_mut(), xml_tag)?;
2858 }
2859 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
2860 break;
2861 }
2862 Event::Eof => break,
2863 _ => {
2864 unused_event("read_value_format_parts", &evt)?;
2865 }
2866 }
2867
2868 buf.clear();
2869 }
2870 ctx.push_buf(buf);
2871
2872 Ok(())
2873}
2874
2875fn read_part(
2876 ctx: &mut OdsContext,
2877 xml: &mut OdsXmlReader<'_>,
2878 super_tag: &BytesStart<'_>,
2879 empty_tag: bool,
2880 part_type: FormatPartType,
2881) -> Result<FormatPart, OdsError> {
2882 let mut part = FormatPart::new(part_type);
2883 copy_attr2(ctx, part.attrmap_mut(), super_tag)?;
2884
2885 if !empty_tag {
2886 let mut buf = ctx.pop_buf();
2887 loop {
2888 let evt = xml.read_event_into(&mut buf)?;
2889 if cfg!(feature = "dump_xml") {
2890 println!(" read_part {:?}", evt);
2891 }
2892 match &evt {
2893 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
2894 break;
2895 }
2896 Event::Eof => {
2897 break;
2898 }
2899 _ => {
2900 unused_event("read_part", &evt)?;
2901 }
2902 }
2903 }
2904 ctx.push_buf(buf);
2905 }
2906
2907 Ok(part)
2908}
2909
2910fn read_part_text(
2912 ctx: &mut OdsContext,
2913 xml: &mut OdsXmlReader<'_>,
2914 super_tag: &BytesStart<'_>,
2915 empty_tag: bool,
2916 part_type: FormatPartType,
2917) -> Result<FormatPart, OdsError> {
2918 let mut part = FormatPart::new(part_type);
2919 copy_attr2(ctx, part.attrmap_mut(), super_tag)?;
2920
2921 if !empty_tag {
2922 let mut buf = ctx.pop_buf();
2923 loop {
2924 let evt = xml.read_event_into(&mut buf)?;
2925 if cfg!(feature = "dump_xml") {
2926 println!(" read_part_text {:?}", evt);
2927 }
2928 match &evt {
2929 Event::GeneralRef(xml_ref) => {
2930 part.append_content(entity(xml_ref)?);
2931 }
2932 Event::Text(xml_text) => {
2933 part.append_content(xml_text.decode()?);
2934 }
2935 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
2936 break;
2937 }
2938 Event::Eof => {
2939 break;
2940 }
2941 _ => {
2942 unused_event("read_part_text", &evt)?;
2943 }
2944 }
2945 }
2946 ctx.push_buf(buf);
2947 }
2948
2949 Ok(part)
2950}
2951
2952fn read_part_number(
2953 ctx: &mut OdsContext,
2954 xml: &mut OdsXmlReader<'_>,
2955 super_tag: &BytesStart<'_>,
2956 empty_tag: bool,
2957 part_type: FormatPartType,
2958) -> Result<FormatPart, OdsError> {
2959 let mut part = FormatPart::new(part_type);
2960 copy_attr2(ctx, part.attrmap_mut(), super_tag)?;
2961
2962 if !empty_tag {
2963 let mut buf = ctx.pop_buf();
2964 loop {
2965 let evt = xml.read_event_into(&mut buf)?;
2966 if cfg!(feature = "dump_xml") {
2967 println!(" read_part_embedded_text {:?}", evt);
2968 }
2969 match &evt {
2970 Event::Start(xml_tag) | Event::Empty(xml_tag)
2971 if xml_tag.name().as_ref() == b"number:embedded-text" =>
2972 {
2973 for attr in xml_tag.attributes().with_checks(false) {
2974 let attr = attr?;
2975 match attr.key.as_ref() {
2976 b"number:position" => {
2977 part.set_position(parse_i32(&attr.value)?);
2978 }
2979 _ => {
2980 unused_attr(
2981 "read_part_embedded_text",
2982 xml_tag.name().as_ref(),
2983 &attr,
2984 )?;
2985 }
2986 }
2987 }
2988 }
2989 Event::End(xml_tag) if xml_tag.name().as_ref() == b"number:embedded-text" => {}
2990 Event::Text(xml_text) => {
2991 part.set_content(parse_string(xml_text.as_ref())?);
2992 }
2993 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
2994 break;
2995 }
2996 Event::Eof => {
2997 break;
2998 }
2999 _ => {
3000 unused_event("read_part_embedded_text", &evt)?;
3001 }
3002 }
3003 }
3004 ctx.push_buf(buf);
3005 }
3006
3007 Ok(part)
3008}
3009
3010#[allow(clippy::too_many_arguments)]
3012fn read_style_style(
3013 ctx: &mut OdsContext,
3014 xml: &mut OdsXmlReader<'_>,
3015 origin: StyleOrigin,
3016 style_use: StyleUse,
3017 super_tag: &BytesStart<'_>,
3018 empty_tag: bool,
3019) -> Result<(), OdsError> {
3020 for attr in super_tag.attributes().with_checks(false) {
3021 match attr? {
3022 attr if attr.key.as_ref() == b"style:family" => {
3023 match attr.value.as_ref() {
3024 b"table" => read_tablestyle(ctx, xml, origin, style_use, super_tag, empty_tag)?,
3025 b"table-column" => {
3026 read_colstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?
3027 }
3028 b"table-row" => {
3029 read_rowstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?
3030 }
3031 b"table-cell" => {
3032 read_cellstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?
3033 }
3034 b"graphic" => {
3035 read_graphicstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?
3036 }
3037 b"paragraph" => {
3038 read_paragraphstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?
3039 }
3040 b"text" => read_textstyle(ctx, xml, origin, style_use, super_tag, empty_tag)?,
3041 b"ruby" => read_rubystyle(ctx, xml, origin, style_use, super_tag, empty_tag)?,
3042 value => {
3043 return Err(OdsError::Ods(format!(
3044 "style:family unknown {} ",
3045 from_utf8(value)?
3046 )));
3047 }
3048 };
3049 }
3050 _ => {
3051 }
3053 }
3054 }
3055
3056 Ok(())
3057}
3058
3059#[allow(clippy::collapsible_else_if)]
3061#[allow(clippy::too_many_arguments)]
3062fn read_tablestyle(
3063 ctx: &mut OdsContext,
3064 xml: &mut OdsXmlReader<'_>,
3065 origin: StyleOrigin,
3066 style_use: StyleUse,
3067 super_tag: &BytesStart<'_>,
3068 empty_tag: bool,
3069) -> Result<(), OdsError> {
3070 let mut style = TableStyle::new_empty();
3071 style.set_origin(origin);
3072 style.set_styleuse(style_use);
3073 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3074 style.set_name(name);
3075
3076 if empty_tag {
3078 ctx.book.add_tablestyle(style);
3079 } else {
3080 let mut buf = ctx.pop_buf();
3081 loop {
3082 let evt = xml.read_event_into(&mut buf)?;
3083 if cfg!(feature = "dump_xml") {
3084 println!(" read_table_style {:?}", evt);
3085 }
3086 match &evt {
3087 Event::Start(xml_tag) | Event::Empty(xml_tag) => match xml_tag.name().as_ref() {
3088 b"style:table-properties" => copy_attr2(ctx, style.tablestyle_mut(), xml_tag)?,
3089 _ => {
3090 unused_event("read_table_style", &evt)?;
3091 }
3092 },
3093 Event::Text(_) => (),
3094 Event::End(xml_tag) => {
3095 if xml_tag.name().as_ref() == super_tag.name().as_ref() {
3096 ctx.book.add_tablestyle(style);
3097 break;
3098 } else {
3099 unused_event("read_table_style", &evt)?;
3100 }
3101 }
3102 Event::Eof => break,
3103 _ => {
3104 unused_event("read_table_style", &evt)?;
3105 }
3106 }
3107 }
3108
3109 ctx.push_buf(buf);
3110 }
3111
3112 Ok(())
3113}
3114
3115#[allow(clippy::collapsible_else_if)]
3117#[allow(clippy::too_many_arguments)]
3118fn read_rowstyle(
3119 ctx: &mut OdsContext,
3120 xml: &mut OdsXmlReader<'_>,
3121 origin: StyleOrigin,
3122 style_use: StyleUse,
3123 super_tag: &BytesStart<'_>,
3124 empty_tag: bool,
3125) -> Result<(), OdsError> {
3126 let mut style = RowStyle::new_empty();
3127 style.set_origin(origin);
3128 style.set_styleuse(style_use);
3129 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3130 style.set_name(name);
3131
3132 if empty_tag {
3134 ctx.book.add_rowstyle(style);
3135 } else {
3136 let mut buf = ctx.pop_buf();
3137 loop {
3138 let evt = xml.read_event_into(&mut buf)?;
3139 if cfg!(feature = "dump_xml") {
3140 println!(" read_rowstyle {:?}", evt);
3141 }
3142 match &evt {
3143 Event::Start(xml_tag) | Event::Empty(xml_tag) => match xml_tag.name().as_ref() {
3144 b"style:table-row-properties" => {
3145 copy_attr2(ctx, style.rowstyle_mut(), xml_tag)?
3146 }
3147 _ => {
3148 unused_event("read_rowstyle", &evt)?;
3149 }
3150 },
3151 Event::Text(_) => (),
3152 Event::End(xml_tag) => {
3153 if xml_tag.name() == super_tag.name() {
3154 ctx.book.add_rowstyle(style);
3155 break;
3156 } else {
3157 unused_event("read_rowstyle", &evt)?;
3158 }
3159 }
3160 Event::Eof => break,
3161 _ => {
3162 unused_event("read_rowstyle", &evt)?;
3163 }
3164 }
3165 }
3166 ctx.push_buf(buf);
3167 }
3168
3169 Ok(())
3170}
3171
3172#[allow(clippy::collapsible_else_if)]
3174#[allow(clippy::too_many_arguments)]
3175fn read_colstyle(
3176 ctx: &mut OdsContext,
3177 xml: &mut OdsXmlReader<'_>,
3178 origin: StyleOrigin,
3179 style_use: StyleUse,
3180 super_tag: &BytesStart<'_>,
3181 empty_tag: bool,
3182) -> Result<(), OdsError> {
3183 let mut style = ColStyle::new_empty();
3184 style.set_origin(origin);
3185 style.set_styleuse(style_use);
3186 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3187 style.set_name(name);
3188
3189 if empty_tag {
3191 ctx.book.add_colstyle(style);
3192 } else {
3193 let mut buf = ctx.pop_buf();
3194 loop {
3195 let evt = xml.read_event_into(&mut buf)?;
3196 if cfg!(feature = "dump_xml") {
3197 println!(" read_colstyle {:?}", evt);
3198 }
3199 match &evt {
3200 Event::Start(xml_tag) | Event::Empty(xml_tag) => match xml_tag.name().as_ref() {
3201 b"style:table-column-properties" => {
3202 copy_attr2(ctx, style.colstyle_mut(), xml_tag)?
3203 }
3204 _ => {
3205 unused_event("read_colstyle", &evt)?;
3206 }
3207 },
3208 Event::Text(_) => (),
3209 Event::End(xml_tag) => {
3210 if xml_tag.name() == super_tag.name() {
3211 ctx.book.add_colstyle(style);
3212 break;
3213 } else {
3214 unused_event("read_colstyle", &evt)?;
3215 }
3216 }
3217 Event::Eof => break,
3218 _ => {
3219 unused_event("read_colstyle", &evt)?;
3220 }
3221 }
3222 }
3223
3224 ctx.push_buf(buf);
3225 }
3226 Ok(())
3227}
3228
3229#[allow(clippy::collapsible_else_if)]
3231#[allow(clippy::too_many_arguments)]
3232fn read_cellstyle(
3233 ctx: &mut OdsContext,
3234 xml: &mut OdsXmlReader<'_>,
3235 origin: StyleOrigin,
3236 style_use: StyleUse,
3237 super_tag: &BytesStart<'_>,
3238 empty_tag: bool,
3239) -> Result<(), OdsError> {
3240 let mut style = CellStyle::new_empty();
3241 style.set_origin(origin);
3242 style.set_styleuse(style_use);
3243 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3244 style.set_name(name);
3245
3246 if empty_tag {
3248 ctx.book.add_cellstyle(style);
3249 } else {
3250 let mut buf = ctx.pop_buf();
3251 loop {
3252 let evt = xml.read_event_into(&mut buf)?;
3253 if cfg!(feature = "dump_xml") {
3254 println!(" read_cellstyle {:?}", evt);
3255 }
3256 match &evt {
3257 Event::Start(xml_tag) | Event::Empty(xml_tag)
3258 if xml_tag.name().as_ref() == b"style:table-cell-properties" =>
3259 {
3260 copy_attr2(ctx, style.cellstyle_mut(), xml_tag)?;
3261 }
3262 Event::Start(xml_tag) | Event::Empty(xml_tag)
3263 if xml_tag.name().as_ref() == b"style:text-properties" =>
3264 {
3265 copy_attr2(ctx, style.textstyle_mut(), xml_tag)?;
3266 }
3267 Event::Start(xml_tag) | Event::Empty(xml_tag)
3268 if xml_tag.name().as_ref() == b"style:paragraph-properties" =>
3269 {
3270 copy_attr2(ctx, style.paragraphstyle_mut(), xml_tag)?;
3271 }
3272 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:paragraph-properties" => {
3273 }
3274 Event::Start(xml_tag) | Event::Empty(xml_tag)
3280 if xml_tag.name().as_ref() == b"style:map" =>
3281 {
3282 style.push_stylemap(read_stylemap(ctx, xml_tag)?);
3283 }
3284 Event::Text(_) => (),
3292 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
3293 ctx.book.add_cellstyle(style);
3294 break;
3295 }
3296 Event::Eof => break,
3297 _ => {
3298 unused_event("read_cellstyle", &evt)?;
3299 }
3300 }
3301 }
3302 ctx.push_buf(buf);
3303 }
3304
3305 Ok(())
3306}
3307
3308#[allow(clippy::collapsible_else_if)]
3310#[allow(clippy::too_many_arguments)]
3311fn read_paragraphstyle(
3312 ctx: &mut OdsContext,
3313 xml: &mut OdsXmlReader<'_>,
3314 origin: StyleOrigin,
3315 style_use: StyleUse,
3316 super_tag: &BytesStart<'_>,
3317 empty_tag: bool,
3318) -> Result<(), OdsError> {
3319 let mut style = ParagraphStyle::new_empty();
3320 style.set_origin(origin);
3321 style.set_styleuse(style_use);
3322 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3323 style.set_name(name);
3324
3325 if empty_tag {
3327 ctx.book.add_paragraphstyle(style);
3328 } else {
3329 let mut buf = ctx.pop_buf();
3330 loop {
3331 let evt = xml.read_event_into(&mut buf)?;
3332 if cfg!(feature = "dump_xml") {
3333 println!(" read_paragraphstyle {:?}", evt);
3334 }
3335 match &evt {
3336 Event::Start(xml_tag) | Event::Empty(xml_tag)
3337 if xml_tag.name().as_ref() == b"style:text-properties" =>
3338 {
3339 copy_attr2(ctx, style.textstyle_mut(), xml_tag)?;
3340 }
3341 Event::Start(xml_tag) | Event::Empty(xml_tag)
3342 if xml_tag.name().as_ref() == b"style:paragraph-properties" =>
3343 {
3344 copy_attr2(ctx, style.paragraphstyle_mut(), xml_tag)?;
3345 }
3346 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:paragraph-properties" => {
3347 }
3348 Event::Start(xml_tag) | Event::Empty(xml_tag)
3351 if xml_tag.name().as_ref() == b"style:tab-stops" => {}
3352 Event::End(xml_tag) if xml_tag.name().as_ref() == b"style:tab-stops" => {}
3353 Event::Start(xml_tag) | Event::Empty(xml_tag)
3354 if xml_tag.name().as_ref() == b"style:tab-stop" =>
3355 {
3356 let mut ts = TabStop::new();
3357 copy_attr2(ctx, ts.attrmap_mut(), xml_tag)?;
3358 style.add_tabstop(ts);
3359 }
3360
3361 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
3362 ctx.book.add_paragraphstyle(style);
3363 break;
3364 }
3365
3366 Event::Text(_) => (),
3367 Event::Eof => break,
3368 _ => {
3369 unused_event("read_paragraphstyle", &evt)?;
3370 }
3371 }
3372 }
3373 ctx.push_buf(buf);
3374 }
3375
3376 Ok(())
3377}
3378
3379#[allow(clippy::collapsible_else_if)]
3381#[allow(clippy::too_many_arguments)]
3382fn read_textstyle(
3383 ctx: &mut OdsContext,
3384 xml: &mut OdsXmlReader<'_>,
3385 origin: StyleOrigin,
3386 style_use: StyleUse,
3387 super_tag: &BytesStart<'_>,
3388 empty_tag: bool,
3389) -> Result<(), OdsError> {
3390 let mut style = TextStyle::new_empty();
3391 style.set_origin(origin);
3392 style.set_styleuse(style_use);
3393 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3394 style.set_name(name);
3395
3396 if empty_tag {
3398 ctx.book.add_textstyle(style);
3399 } else {
3400 let mut buf = ctx.pop_buf();
3401 loop {
3402 let evt = xml.read_event_into(&mut buf)?;
3403 if cfg!(feature = "dump_xml") {
3404 println!(" read_textstyle {:?}", evt);
3405 }
3406 match &evt {
3407 Event::Start(xml_tag) | Event::Empty(xml_tag)
3408 if xml_tag.name().as_ref() == b"style:text-properties" =>
3409 {
3410 copy_attr2(ctx, style.textstyle_mut(), xml_tag)?;
3411 }
3412 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
3413 ctx.book.add_textstyle(style);
3414 break;
3415 }
3416 Event::Text(_) => (),
3417 Event::Eof => break,
3418 _ => {
3419 unused_event("read_textstyle", &evt)?;
3420 }
3421 }
3422 }
3423 ctx.push_buf(buf);
3424 }
3425
3426 Ok(())
3427}
3428
3429#[allow(clippy::collapsible_else_if)]
3431#[allow(clippy::too_many_arguments)]
3432fn read_rubystyle(
3433 ctx: &mut OdsContext,
3434 xml: &mut OdsXmlReader<'_>,
3435 origin: StyleOrigin,
3436 style_use: StyleUse,
3437 super_tag: &BytesStart<'_>,
3438 empty_tag: bool,
3439) -> Result<(), OdsError> {
3440 let mut style = RubyStyle::new_empty();
3441 style.set_origin(origin);
3442 style.set_styleuse(style_use);
3443 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3444 style.set_name(name);
3445
3446 if empty_tag {
3448 ctx.book.add_rubystyle(style);
3449 } else {
3450 let mut buf = ctx.pop_buf();
3451 loop {
3452 let evt = xml.read_event_into(&mut buf)?;
3453 if cfg!(feature = "dump_xml") {
3454 println!(" read_rubystyle {:?}", evt);
3455 }
3456 match &evt {
3457 Event::Start(xml_tag) | Event::Empty(xml_tag)
3458 if xml_tag.name().as_ref() == b"style:ruby-properties" =>
3459 {
3460 copy_attr2(ctx, style.rubystyle_mut(), xml_tag)?;
3461 }
3462 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
3463 ctx.book.add_rubystyle(style);
3464 break;
3465 }
3466 Event::Text(_) => (),
3467 Event::Eof => break,
3468 _ => {
3469 unused_event("read_rubystyle", &evt)?;
3470 }
3471 }
3472 }
3473 ctx.push_buf(buf);
3474 }
3475
3476 Ok(())
3477}
3478
3479#[allow(clippy::collapsible_else_if)]
3481#[allow(clippy::too_many_arguments)]
3482fn read_graphicstyle(
3483 ctx: &mut OdsContext,
3484 xml: &mut OdsXmlReader<'_>,
3485 origin: StyleOrigin,
3486 style_use: StyleUse,
3487 super_tag: &BytesStart<'_>,
3488 empty_tag: bool,
3489) -> Result<(), OdsError> {
3490 let mut style = GraphicStyle::new_empty();
3491 style.set_origin(origin);
3492 style.set_styleuse(style_use);
3493 let name = copy_style_attr(ctx, style.attrmap_mut(), super_tag)?;
3494 style.set_name(name);
3495
3496 if empty_tag {
3498 ctx.book.add_graphicstyle(style);
3499 } else {
3500 let mut buf = ctx.pop_buf();
3501 loop {
3502 let evt = xml.read_event_into(&mut buf)?;
3503 if cfg!(feature = "dump_xml") {
3504 println!(" read_graphicstyle {:?}", evt);
3505 }
3506 match &evt {
3507 Event::Start(xml_tag) | Event::Empty(xml_tag)
3508 if xml_tag.name().as_ref() == b"style:graphic-properties" =>
3509 {
3510 copy_attr2(ctx, style.graphicstyle_mut(), xml_tag)?;
3511 }
3512 Event::Start(xml_tag) | Event::Empty(xml_tag)
3513 if xml_tag.name().as_ref() == b"style:paragraph-properties" =>
3514 {
3515 copy_attr2(ctx, style.paragraphstyle_mut(), xml_tag)?;
3516 }
3517 Event::Start(xml_tag) | Event::Empty(xml_tag)
3518 if xml_tag.name().as_ref() == b"style:text-properties" =>
3519 {
3520 copy_attr2(ctx, style.textstyle_mut(), xml_tag)?;
3521 }
3522 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
3523 ctx.book.add_graphicstyle(style);
3524 break;
3525 }
3526 Event::Text(_) => (),
3527 Event::Eof => break,
3528 _ => {
3529 unused_event("read_graphicstyle", &evt)?;
3530 }
3531 }
3532 }
3533 ctx.push_buf(buf);
3534 }
3535
3536 Ok(())
3537}
3538
3539fn read_value_stylemap(
3541 ctx: &mut OdsContext,
3542 super_tag: &BytesStart<'_>,
3543) -> Result<ValueStyleMap, OdsError> {
3544 let mut sm = ValueStyleMap::default();
3545 for attr in super_tag.attributes().with_checks(false) {
3546 match attr? {
3547 attr if attr.key.as_ref() == b"style:condition" => {
3548 sm.set_condition(ValueCondition::new(
3549 attr.decode_and_unescape_value(ctx.decoder)?.to_string(),
3550 ));
3551 }
3552 attr if attr.key.as_ref() == b"style:apply-style-name" => {
3553 sm.set_applied_style(attr.decode_and_unescape_value(ctx.decoder)?);
3554 }
3555 attr => {
3556 unused_attr("read_value_stylemap", super_tag.name().as_ref(), &attr)?;
3557 }
3558 }
3559 }
3560
3561 Ok(sm)
3562}
3563
3564fn read_stylemap(ctx: &mut OdsContext, super_tag: &BytesStart<'_>) -> Result<StyleMap, OdsError> {
3565 let mut sm = StyleMap::new_empty();
3566 for attr in super_tag.attributes().with_checks(false) {
3567 match attr? {
3568 attr if attr.key.as_ref() == b"style:condition" => {
3569 sm.set_condition(Condition::new(
3570 attr.decode_and_unescape_value(ctx.decoder)?.to_string(),
3571 ));
3572 }
3573 attr if attr.key.as_ref() == b"style:apply-style-name" => {
3574 let name = attr.decode_and_unescape_value(ctx.decoder)?;
3575 sm.set_applied_style(AnyStyleRef::from(name.as_ref()));
3576 }
3577 attr if attr.key.as_ref() == b"style:base-cell-address" => {
3578 let v = attr.decode_and_unescape_value(ctx.decoder)?;
3579 sm.set_base_cell(Some(parse_cellref(v.as_ref())?));
3580 }
3581 attr => {
3582 unused_attr("read_stylemap", super_tag.name().as_ref(), &attr)?;
3583 }
3584 }
3585 }
3586
3587 Ok(sm)
3588}
3589
3590fn copy_style_attr(
3592 ctx: &mut OdsContext,
3593 attrmap: &mut AttrMap2,
3594 super_tag: &BytesStart<'_>,
3595) -> Result<String, OdsError> {
3596 let mut name = None;
3597
3598 for attr in super_tag.attributes().with_checks(false) {
3599 match attr? {
3600 attr if attr.key.as_ref() == b"style:name" => {
3601 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
3602 }
3603 attr => {
3604 let k = from_utf8(attr.key.as_ref())?;
3605 let v = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
3606 attrmap.push_attr(k, v);
3607 }
3608 }
3609 }
3610
3611 Ok(name.unwrap_or_default())
3612}
3613
3614fn copy_attr2(
3616 ctx: &mut OdsContext,
3617 attrmap: &mut AttrMap2,
3618 super_tag: &BytesStart<'_>,
3619) -> Result<(), OdsError> {
3620 for attr in super_tag.attributes().with_checks(false) {
3621 let attr = attr?;
3622
3623 let k = from_utf8(attr.key.as_ref())?;
3624 let v = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
3625 attrmap.push_attr(k, v);
3626 }
3627
3628 Ok(())
3629}
3630
3631fn read_ods_styles(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
3632 let mut buf = ctx.pop_buf();
3633 loop {
3634 let evt = xml.read_event_into(&mut buf)?;
3635 if cfg!(feature = "dump_xml") {
3636 println!(" read_styles {:?}", evt);
3637 }
3638 match &evt {
3639 Event::Decl(_) => {}
3640 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:document-styles" => {
3641 let (_, xmlns) = read_namespaces_and_version(ctx, xml_tag)?;
3642 ctx.book.xmlns.insert("styles.xml".to_string(), xmlns);
3643 }
3644 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:document-styles" => {
3645 }
3647 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:font-face-decls" => {
3648 read_office_font_face_decls(ctx, xml, StyleOrigin::Styles)?
3649 }
3650 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:styles" => {
3651 read_office_styles(ctx, xml, StyleOrigin::Styles)?
3652 }
3653 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:automatic-styles" => {
3654 read_office_automatic_styles(ctx, xml, StyleOrigin::Styles)?
3655 }
3656 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:master-styles" => {
3657 read_office_master_styles(ctx, xml, StyleOrigin::Styles)?
3658 }
3659 Event::Eof => {
3660 break;
3661 }
3662 _ => {
3663 unused_event("read_styles", &evt)?;
3664 }
3665 }
3666
3667 buf.clear();
3668 }
3669 ctx.push_buf(buf);
3670
3671 Ok(())
3672}
3673
3674#[allow(unused_variables)]
3675pub(crate) fn default_settings() -> Detach<Config> {
3676 let mut dc = Detach::new(Config::new());
3677 let p0 = dc.create_path(&[("ooo:view-settings", ConfigItemType::Set)]);
3678 p0.insert("VisibleAreaTop", 0);
3679 p0.insert("VisibleAreaLeft", 0);
3680 p0.insert("VisibleAreaWidth", 2540);
3681 p0.insert("VisibleAreaHeight", 1270);
3682
3683 let p0 = dc.create_path(&[
3684 ("ooo:view-settings", ConfigItemType::Set),
3685 ("Views", ConfigItemType::Vec),
3686 ("0", ConfigItemType::Entry),
3687 ]);
3688 p0.insert("ViewId", "view1");
3689 let p0 = dc.create_path(&[
3690 ("ooo:view-settings", ConfigItemType::Set),
3691 ("Views", ConfigItemType::Vec),
3692 ("0", ConfigItemType::Entry),
3693 ("Tables", ConfigItemType::Map),
3694 ]);
3695 let p0 = dc.create_path(&[
3696 ("ooo:view-settings", ConfigItemType::Set),
3697 ("Views", ConfigItemType::Vec),
3698 ("0", ConfigItemType::Entry),
3699 ]);
3700 p0.insert("ActiveTable", "");
3701 p0.insert("HorizontalScrollbarWidth", 702);
3702 p0.insert("ZoomType", 0i16);
3703 p0.insert("ZoomValue", 100);
3704 p0.insert("PageViewZoomValue", 60);
3705 p0.insert("ShowPageBreakPreview", false);
3706 p0.insert("ShowZeroValues", true);
3707 p0.insert("ShowNotes", true);
3708 p0.insert("ShowGrid", true);
3709 p0.insert("GridColor", 12632256);
3710 p0.insert("ShowPageBreaks", false);
3711 p0.insert("HasColumnRowHeaders", true);
3712 p0.insert("HasSheetTabs", true);
3713 p0.insert("IsOutlineSymbolsSet", true);
3714 p0.insert("IsValueHighlightingEnabled", false);
3715 p0.insert("IsSnapToRaster", false);
3716 p0.insert("RasterIsVisible", false);
3717 p0.insert("RasterResolutionX", 1000);
3718 p0.insert("RasterResolutionY", 1000);
3719 p0.insert("RasterSubdivisionX", 1);
3720 p0.insert("RasterSubdivisionY", 1);
3721 p0.insert("IsRasterAxisSynchronized", true);
3722 p0.insert("AnchoredTextOverflowLegacy", false);
3723
3724 let p0 = dc.create_path(&[("ooo:configuration-settings", ConfigItemType::Set)]);
3725 p0.insert("HasSheetTabs", true);
3726 p0.insert("ShowNotes", true);
3727 p0.insert("EmbedComplexScriptFonts", true);
3728 p0.insert("ShowZeroValues", true);
3729 p0.insert("ShowGrid", true);
3730 p0.insert("GridColor", 12632256);
3731 p0.insert("ShowPageBreaks", false);
3732 p0.insert("IsKernAsianPunctuation", false);
3733 p0.insert("LinkUpdateMode", 3i16);
3734 p0.insert("HasColumnRowHeaders", true);
3735 p0.insert("EmbedLatinScriptFonts", true);
3736 p0.insert("IsOutlineSymbolsSet", true);
3737 p0.insert("EmbedLatinScriptFonts", true);
3738 p0.insert("IsOutlineSymbolsSet", true);
3739 p0.insert("IsSnapToRaster", false);
3740 p0.insert("RasterIsVisible", false);
3741 p0.insert("RasterResolutionX", 1000);
3742 p0.insert("RasterResolutionY", 1000);
3743 p0.insert("RasterSubdivisionX", 1);
3744 p0.insert("RasterSubdivisionY", 1);
3745 p0.insert("IsRasterAxisSynchronized", true);
3746 p0.insert("AutoCalculate", true);
3747 p0.insert("ApplyUserData", true);
3748 p0.insert("PrinterName", "");
3749 p0.insert("PrinterSetup", ConfigValue::Base64Binary("".to_string()));
3750 p0.insert("SaveThumbnail", true);
3751 p0.insert("CharacterCompressionType", 0i16);
3752 p0.insert("SaveVersionOnClose", false);
3753 p0.insert("UpdateFromTemplate", true);
3754 p0.insert("AllowPrintJobCancel", true);
3755 p0.insert("LoadReadonly", false);
3756 p0.insert("IsDocumentShared", false);
3757 p0.insert("EmbedFonts", false);
3758 p0.insert("EmbedOnlyUsedFonts", false);
3759 p0.insert("EmbedAsianScriptFonts", true);
3760 p0.insert("SyntaxStringRef", 7i16);
3761
3762 dc
3763}
3764
3765fn read_ods_metadata(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
3766 let mut buf = ctx.pop_buf();
3767
3768 loop {
3769 let evt = xml.read_event_into(&mut buf)?;
3770 if cfg!(feature = "dump_xml") {
3771 println!("read_ods_metadata {:?}", evt);
3772 }
3773
3774 match &evt {
3775 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:document-meta" => {
3776 let (_, xmlns) = read_namespaces_and_version(ctx, xml_tag)?;
3777 ctx.book.xmlns.insert("meta.xml".to_string(), xmlns);
3778 }
3779 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:document-meta" => {}
3780
3781 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:meta" => {
3782 read_office_meta(ctx, xml)?;
3783 }
3784
3785 Event::Decl(_) => {}
3786 Event::Eof => {
3787 break;
3788 }
3789 _ => {
3790 unused_event("read_ods_metadata", &evt)?;
3791 }
3792 }
3793
3794 buf.clear();
3795 }
3796 ctx.push_buf(buf);
3797
3798 Ok(())
3799}
3800
3801fn read_office_meta(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
3802 let mut buf = ctx.pop_buf();
3803
3804 loop {
3805 let evt = xml.read_event_into(&mut buf)?;
3806 if cfg!(feature = "dump_xml") {
3807 println!("read_metadata {:?}", evt);
3808 }
3809
3810 match &evt {
3811 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:meta" => {
3812 break;
3813 }
3814
3815 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:generator" => {
3816 ctx.book.metadata.generator = read_metadata_value(
3817 ctx,
3818 xml,
3819 xml_tag,
3820 |v| Ok(from_utf8(v)?.to_string()),
3821 String::new,
3822 )?;
3823 }
3824 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:title" => {
3825 ctx.book.metadata.title = read_metadata_value(
3826 ctx,
3827 xml,
3828 xml_tag,
3829 |v| Ok(from_utf8(v)?.to_string()),
3830 String::new,
3831 )?;
3832 }
3833 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:description" => {
3834 ctx.book.metadata.description = read_metadata_value(
3835 ctx,
3836 xml,
3837 xml_tag,
3838 |v| Ok(from_utf8(v)?.to_string()),
3839 String::new,
3840 )?;
3841 }
3842 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:subject" => {
3843 ctx.book.metadata.subject = read_metadata_value(
3844 ctx,
3845 xml,
3846 xml_tag,
3847 |v| Ok(from_utf8(v)?.to_string()),
3848 String::new,
3849 )?;
3850 }
3851 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:keyword" => {
3852 ctx.book.metadata.keyword = read_metadata_value(
3853 ctx,
3854 xml,
3855 xml_tag,
3856 |v| Ok(from_utf8(v)?.to_string()),
3857 String::new,
3858 )?;
3859 }
3860 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:initial-creator" => {
3861 ctx.book.metadata.initial_creator = read_metadata_value(
3862 ctx,
3863 xml,
3864 xml_tag,
3865 |v| Ok(from_utf8(v)?.to_string()),
3866 String::new,
3867 )?;
3868 }
3869 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:creator" => {
3870 ctx.book.metadata.creator = read_metadata_value(
3871 ctx,
3872 xml,
3873 xml_tag,
3874 |v| Ok(from_utf8(v)?.to_string()),
3875 String::new,
3876 )?;
3877 }
3878 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:printed-by" => {
3879 ctx.book.metadata.printed_by = read_metadata_value(
3880 ctx,
3881 xml,
3882 xml_tag,
3883 |v| Ok(from_utf8(v)?.to_string()),
3884 String::new,
3885 )?;
3886 }
3887 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:creation-date" => {
3888 ctx.book.metadata.creation_date = read_metadata_value(
3889 ctx,
3890 xml,
3891 xml_tag,
3892 |v| Ok(Some(parse_datetime(v)?)),
3893 || None,
3894 )?;
3895 }
3896 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:date" => {
3897 ctx.book.metadata.date = read_metadata_value(
3898 ctx,
3899 xml,
3900 xml_tag,
3901 |v| Ok(Some(parse_datetime(v)?)),
3902 || None,
3903 )?;
3904 }
3905 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:print-date" => {
3906 ctx.book.metadata.print_date = read_metadata_value(
3907 ctx,
3908 xml,
3909 xml_tag,
3910 |v| Ok(Some(parse_datetime(v)?)),
3911 || None,
3912 )?;
3913 }
3914 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"dc:language" => {
3915 ctx.book.metadata.language = read_metadata_value(
3916 ctx,
3917 xml,
3918 xml_tag,
3919 |v| Ok(from_utf8(v)?.to_string()),
3920 String::new,
3921 )?;
3922 }
3923 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:editing-cycles" => {
3924 ctx.book.metadata.editing_cycles =
3925 read_metadata_value(ctx, xml, xml_tag, parse_u32, || 0)?;
3926 }
3927 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:editing-duration" => {
3928 ctx.book.metadata.editing_duration =
3929 read_metadata_value(ctx, xml, xml_tag, parse_duration, Duration::default)?;
3930 }
3931
3932 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:template" => {
3933 ctx.book.metadata.template = read_metadata_template(ctx, xml_tag)?;
3934 }
3935 Event::End(xml_tag) if xml_tag.name().as_ref() == b"meta:template" => {}
3936
3937 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:auto-reload" => {
3938 ctx.book.metadata.auto_reload = read_metadata_auto_reload(ctx, xml_tag)?;
3939 }
3940 Event::End(xml_tag) if xml_tag.name().as_ref() == b"meta:auto-reload" => {}
3941
3942 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:hyperlink-behaviour" => {
3943 ctx.book.metadata.hyperlink_behaviour =
3944 read_metadata_hyperlink_behaviour(ctx, xml_tag)?;
3945 }
3946 Event::End(xml_tag) if xml_tag.name().as_ref() == b"meta:hyperlink-behaviour" => {}
3947
3948 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:document-statistic" => {
3949 ctx.book.metadata.document_statistics =
3950 read_metadata_document_statistics(ctx, xml_tag)?;
3951 }
3952 Event::End(xml_tag) if xml_tag.name().as_ref() == b"meta:document-statistic" => {}
3953
3954 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"meta:user-defined" => {
3955 let userdefined = read_metadata_user_defined(ctx, xml, xml_tag)?;
3956 ctx.book.metadata.user_defined.push(userdefined);
3957 }
3958
3959 Event::Empty(_) => {}
3960 Event::Text(_) => {}
3961 Event::Eof => {
3962 break;
3963 }
3964 _ => {
3965 unused_event("read_metadata", &evt)?;
3966 }
3967 }
3968
3969 buf.clear();
3970 }
3971 ctx.push_buf(buf);
3972
3973 Ok(())
3974}
3975
3976fn read_metadata_template(
3977 ctx: &mut OdsContext,
3978 tag: &BytesStart<'_>,
3979) -> Result<MetaTemplate, OdsError> {
3980 let mut template = MetaTemplate::default();
3981
3982 for attr in tag.attributes().with_checks(false) {
3983 match attr? {
3984 attr if attr.key.as_ref() == b"meta:date" => {
3985 template.date = Some(parse_datetime(
3986 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
3987 )?);
3988 }
3989 attr if attr.key.as_ref() == b"xlink:actuate" => {
3990 template.actuate = Some(parse_xlink_actuate(
3991 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
3992 )?);
3993 }
3994 attr if attr.key.as_ref() == b"xlink:href" => {
3995 template.href = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string())
3996 }
3997 attr if attr.key.as_ref() == b"xlink:title" => {
3998 template.title = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string())
3999 }
4000 attr if attr.key.as_ref() == b"xlink:type" => {
4001 template.link_type = Some(parse_xlink_type(
4002 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4003 )?);
4004 }
4005 attr => {
4006 unused_attr("read_metadata_template", tag.name().as_ref(), &attr)?;
4007 }
4008 }
4009 }
4010
4011 Ok(template)
4012}
4013
4014fn read_metadata_auto_reload(
4015 ctx: &mut OdsContext,
4016 tag: &BytesStart<'_>,
4017) -> Result<MetaAutoReload, OdsError> {
4018 let mut auto_reload = MetaAutoReload::default();
4019
4020 for attr in tag.attributes().with_checks(false) {
4021 match attr? {
4022 attr if attr.key.as_ref() == b"meta:delay" => {
4023 auto_reload.delay = Some(parse_duration(
4024 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4025 )?);
4026 }
4027 attr if attr.key.as_ref() == b"xlink:actuate" => {
4028 auto_reload.actuate = Some(parse_xlink_actuate(
4029 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4030 )?);
4031 }
4032 attr if attr.key.as_ref() == b"xlink:href" => {
4033 auto_reload.href = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string())
4034 }
4035 attr if attr.key.as_ref() == b"xlink:show" => {
4036 auto_reload.show = Some(parse_xlink_show(
4037 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4038 )?);
4039 }
4040 attr if attr.key.as_ref() == b"xlink:type" => {
4041 auto_reload.link_type = Some(parse_xlink_type(
4042 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4043 )?);
4044 }
4045 attr => {
4046 unused_attr("read_metadata_auto_reload", tag.name().as_ref(), &attr)?;
4047 }
4048 }
4049 }
4050
4051 Ok(auto_reload)
4052}
4053
4054fn read_metadata_hyperlink_behaviour(
4055 ctx: &mut OdsContext,
4056 tag: &BytesStart<'_>,
4057) -> Result<MetaHyperlinkBehaviour, OdsError> {
4058 let mut hyperlink_behaviour = MetaHyperlinkBehaviour::default();
4059
4060 for attr in tag.attributes().with_checks(false) {
4061 match attr? {
4062 attr if attr.key.as_ref() == b"office:targetframe-name" => {
4063 hyperlink_behaviour.target_frame_name =
4064 Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4065 }
4066 attr if attr.key.as_ref() == b"xlink:show" => {
4067 hyperlink_behaviour.show = Some(parse_xlink_show(
4068 attr.decode_and_unescape_value(ctx.decoder)?.as_bytes(),
4069 )?);
4070 }
4071 attr => {
4072 unused_attr(
4073 "read_metadata_hyperlink_behaviour",
4074 tag.name().as_ref(),
4075 &attr,
4076 )?;
4077 }
4078 }
4079 }
4080
4081 Ok(hyperlink_behaviour)
4082}
4083
4084fn read_metadata_document_statistics(
4085 ctx: &mut OdsContext,
4086 tag: &BytesStart<'_>,
4087) -> Result<MetaDocumentStatistics, OdsError> {
4088 let mut document_statistics = MetaDocumentStatistics::default();
4089
4090 for attr in tag.attributes().with_checks(false) {
4091 match attr? {
4092 attr if attr.key.as_ref() == b"meta:cell-count" => {
4093 document_statistics.cell_count =
4094 parse_u32(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
4095 }
4096 attr if attr.key.as_ref() == b"meta:object-count" => {
4097 document_statistics.object_count =
4098 parse_u32(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
4099 }
4100 attr if attr.key.as_ref() == b"meta:ole-object-count" => {
4101 document_statistics.ole_object_count =
4102 parse_u32(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
4103 }
4104 attr if attr.key.as_ref() == b"meta:table-count" => {
4105 document_statistics.table_count =
4106 parse_u32(attr.decode_and_unescape_value(ctx.decoder)?.as_bytes())?;
4107 }
4108 attr => {
4109 unused_attr(
4110 "read_metadata_document_statistics",
4111 tag.name().as_ref(),
4112 &attr,
4113 )?;
4114 }
4115 }
4116 }
4117
4118 Ok(document_statistics)
4119}
4120
4121fn read_metadata_user_defined(
4122 ctx: &mut OdsContext,
4123 xml: &mut OdsXmlReader<'_>,
4124 tag: &BytesStart<'_>,
4125) -> Result<MetaUserDefined, OdsError> {
4126 let mut user_defined = MetaUserDefined::default();
4127 let mut value_type = None;
4128 for attr in tag.attributes().with_checks(false) {
4129 match attr? {
4130 attr if attr.key.as_ref() == b"meta:name" => {
4131 user_defined.name = attr.decode_and_unescape_value(ctx.decoder)?.to_string();
4132 }
4133 attr if attr.key.as_ref() == b"meta:value-type" => {
4134 value_type = Some(
4135 match attr.decode_and_unescape_value(ctx.decoder)?.as_ref() {
4136 "boolean" => "boolean",
4137 "date" => "date",
4138 "float" => "float",
4139 "time" => "time",
4140 _ => "string",
4141 },
4142 );
4143 }
4144 attr => {
4145 unused_attr("read_meta_user_defined", tag.name().as_ref(), &attr)?;
4146 }
4147 }
4148 }
4149
4150 let mut buf = ctx.pop_buf();
4151 loop {
4152 let evt = xml.read_event_into(&mut buf)?;
4153 if cfg!(feature = "dump_xml") {
4154 println!("read_meta_user_defined {:?}", evt);
4155 }
4156
4157 match &evt {
4158 Event::End(xml_tag) if xml_tag.name() == tag.name() => {
4159 break;
4160 }
4161 Event::Text(xml_text) => {
4162 user_defined.value = match value_type {
4163 Some("boolean") => MetaValue::Boolean(parse_bool(xml_text)?),
4164 Some("date") => MetaValue::Datetime(parse_datetime(xml_text)?),
4165 Some("float") => MetaValue::Float(parse_f64(xml_text)?),
4166 Some("time") => MetaValue::TimeDuration(parse_duration(xml_text)?),
4167 _ => MetaValue::String(xml_text.decode()?.to_string()),
4168 };
4169 }
4170 Event::Eof => {
4171 break;
4172 }
4173 _ => {
4174 unused_event("read_meta_user_defined", &evt)?;
4175 }
4176 }
4177
4178 buf.clear();
4179 }
4180 ctx.push_buf(buf);
4181
4182 Ok(user_defined)
4183}
4184
4185fn read_metadata_value<T>(
4187 ctx: &mut OdsContext,
4188 xml: &mut OdsXmlReader<'_>,
4189 tag: &BytesStart<'_>,
4190 parse: fn(&[u8]) -> Result<T, OdsError>,
4191 default: fn() -> T,
4192) -> Result<T, OdsError> {
4193 let mut buf = ctx.pop_buf();
4194 let mut text = String::new();
4195 loop {
4196 let evt = xml.read_event_into(&mut buf)?;
4197 if cfg!(feature = "dump_xml") {
4198 println!("read_metadata_value {:?}", evt);
4199 }
4200
4201 match &evt {
4202 Event::End(xml_tag) if xml_tag.name() == tag.name() => {
4203 break;
4204 }
4205 Event::GeneralRef(xml_ref) => {
4206 text.push_str(entity(xml_ref)?.as_ref());
4207 }
4208 Event::Text(xml_text) => {
4209 text.push_str(xml_text.decode()?.as_ref());
4210 }
4211 Event::Eof => {
4212 break;
4213 }
4214 _ => {
4215 unused_event("read_metadata_value", &evt)?;
4216 }
4217 }
4218
4219 buf.clear();
4220 }
4221 ctx.push_buf(buf);
4222
4223 if !text.is_empty() {
4224 parse(text.as_bytes())
4225 } else {
4226 Ok(default())
4227 }
4228}
4229
4230fn read_ods_settings(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
4231 let mut buf = ctx.pop_buf();
4232 loop {
4233 let evt = xml.read_event_into(&mut buf)?;
4234 if cfg!(feature = "dump_xml") {
4235 println!(" read_settings {:?}", evt);
4236 }
4237
4238 match &evt {
4239 Event::Decl(_) => {}
4240
4241 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:document-settings" => {
4242 let (_, xmlns) = read_namespaces_and_version(ctx, xml_tag)?;
4243 ctx.book.xmlns.insert("settings.xml".to_string(), xmlns);
4244 }
4245 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:document-settings" => {}
4246
4247 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"office:settings" => {
4248 read_office_settings(ctx, xml)?;
4249 }
4250
4251 Event::Eof => {
4252 break;
4253 }
4254 _ => {
4255 unused_event("read_settings", &evt)?;
4256 }
4257 }
4258
4259 buf.clear();
4260 }
4261 ctx.push_buf(buf);
4262
4263 Ok(())
4264}
4265
4266fn read_office_settings(ctx: &mut OdsContext, xml: &mut OdsXmlReader<'_>) -> Result<(), OdsError> {
4268 let mut config = Config::new();
4269
4270 let mut buf = ctx.pop_buf();
4271 loop {
4272 let evt = xml.read_event_into(&mut buf)?;
4273 if cfg!(feature = "dump_xml") {
4274 println!(" read_office_settings {:?}", evt);
4275 }
4276 match &evt {
4277 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-set" => {
4278 let (name, set) = read_config_item_set(ctx, xml, xml_tag)?;
4279 config.insert(name, set);
4280 }
4281
4282 Event::End(xml_tag) if xml_tag.name().as_ref() == b"office:settings" => {
4283 break;
4284 }
4285 Event::Eof => break,
4286 _ => {
4287 unused_event("read_office_settings", &evt)?;
4288 }
4289 }
4290
4291 buf.clear();
4292 }
4293 ctx.push_buf(buf);
4294
4295 ctx.book.config = Detach::new(config);
4296
4297 Ok(())
4298}
4299
4300fn read_config_item_set(
4302 ctx: &mut OdsContext,
4303 xml: &mut OdsXmlReader<'_>,
4304 super_tag: &BytesStart<'_>,
4305) -> Result<(String, ConfigItem), OdsError> {
4306 let mut name = None;
4307 let mut config_set = ConfigItem::new_set();
4308
4309 for attr in super_tag.attributes().with_checks(false) {
4310 match attr? {
4311 attr if attr.key.as_ref() == b"config:name" => {
4312 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4313 }
4314 attr => {
4315 unused_attr("read_config_item_set", super_tag.name().as_ref(), &attr)?;
4316 }
4317 }
4318 }
4319
4320 let name = if let Some(name) = name {
4321 name
4322 } else {
4323 return Err(OdsError::Ods("config-item-set without name".to_string()));
4324 };
4325
4326 let mut buf = ctx.pop_buf();
4327 loop {
4328 let evt = xml.read_event_into(&mut buf)?;
4329 if cfg!(feature = "dump_xml") {
4330 println!(" read_office_item_set {:?}", evt);
4331 }
4332 match &evt {
4333 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"config:config-item" => {}
4334 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item" => {
4335 let (name, val) = read_config_item(ctx, xml, xml_tag)?;
4336 config_set.insert(name, val);
4337 }
4338 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-set" => {
4339 let (name, val) = read_config_item_set(ctx, xml, xml_tag)?;
4340 config_set.insert(name, val);
4341 }
4342 Event::Start(xml_tag)
4343 if xml_tag.name().as_ref() == b"config:config-item-map-indexed" =>
4344 {
4345 let (name, val) = read_config_item_map_indexed(ctx, xml, xml_tag)?;
4346 config_set.insert(name, val);
4347 }
4348 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-named" => {
4349 let (name, val) = read_config_item_map_named(ctx, xml, xml_tag)?;
4350 config_set.insert(name, val);
4351 }
4352 Event::End(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-set" => {
4353 break;
4354 }
4355 Event::Eof => break,
4356 _ => {
4357 unused_event("read_config_item_set", &evt)?;
4358 }
4359 }
4360
4361 buf.clear();
4362 }
4363 ctx.push_buf(buf);
4364
4365 Ok((name, config_set))
4366}
4367
4368fn read_config_item_map_indexed(
4370 ctx: &mut OdsContext,
4371 xml: &mut OdsXmlReader<'_>,
4372 super_tag: &BytesStart<'_>,
4373) -> Result<(String, ConfigItem), OdsError> {
4374 let mut name = None;
4375 let mut config_vec = ConfigItem::new_vec();
4376
4377 for attr in super_tag.attributes().with_checks(false) {
4378 match attr? {
4379 attr if attr.key.as_ref() == b"config:name" => {
4380 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4381 }
4382 attr => {
4383 unused_attr(
4384 "read_config_item_map_indexed",
4385 super_tag.name().as_ref(),
4386 &attr,
4387 )?;
4388 }
4389 }
4390 }
4391
4392 let name = if let Some(name) = name {
4393 name
4394 } else {
4395 return Err(OdsError::Ods(
4396 "config-item-map-indexed without name".to_string(),
4397 ));
4398 };
4399
4400 let mut index = 0;
4401
4402 let mut buf = ctx.pop_buf();
4403 loop {
4404 let evt = xml.read_event_into(&mut buf)?;
4405 if cfg!(feature = "dump_xml") {
4406 println!(" read_office_item_set {:?}", evt);
4407 }
4408 match &evt {
4409 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-entry" => {
4410 let (_, entry) = read_config_item_map_entry(ctx, xml, xml_tag)?;
4411 config_vec.insert(index.to_string(), entry);
4412 index += 1;
4413 }
4414 Event::End(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-indexed" => {
4415 break;
4416 }
4417 Event::Eof => break,
4418 _ => {
4419 unused_event("read_config_item_map_indexed", &evt)?;
4420 }
4421 }
4422
4423 buf.clear();
4424 }
4425 ctx.push_buf(buf);
4426
4427 Ok((name, config_vec))
4428}
4429
4430fn read_config_item_map_named(
4432 ctx: &mut OdsContext,
4433 xml: &mut OdsXmlReader<'_>,
4434 super_tag: &BytesStart<'_>,
4435) -> Result<(String, ConfigItem), OdsError> {
4436 let mut name = None;
4437 let mut config_map = ConfigItem::new_map();
4438
4439 for attr in super_tag.attributes().with_checks(false) {
4440 match attr? {
4441 attr if attr.key.as_ref() == b"config:name" => {
4442 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4443 }
4444 attr => {
4445 unused_attr(
4446 "read_config_item_map_named",
4447 super_tag.name().as_ref(),
4448 &attr,
4449 )?;
4450 }
4451 }
4452 }
4453
4454 let name = if let Some(name) = name {
4455 name
4456 } else {
4457 return Err(OdsError::Ods(
4458 "config-item-map-named without name".to_string(),
4459 ));
4460 };
4461
4462 let mut buf = ctx.pop_buf();
4463 loop {
4464 let evt = xml.read_event_into(&mut buf)?;
4465 if cfg!(feature = "dump_xml") {
4466 println!(" read_config_item_map_named {:?}", evt);
4467 }
4468 match &evt {
4469 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-entry" => {
4470 let (name, entry) = read_config_item_map_entry(ctx, xml, xml_tag)?;
4471
4472 let name = if let Some(name) = name {
4473 name
4474 } else {
4475 return Err(OdsError::Ods(
4476 "config-item-map-entry without name".to_string(),
4477 ));
4478 };
4479
4480 config_map.insert(name, entry);
4481 }
4482 Event::End(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-named" => {
4483 break;
4484 }
4485 Event::Eof => break,
4486 _ => {
4487 unused_event("read_config_item_map_named", &evt)?;
4488 }
4489 }
4490
4491 buf.clear();
4492 }
4493 ctx.push_buf(buf);
4494
4495 Ok((name, config_map))
4496}
4497
4498fn read_config_item_map_entry(
4500 ctx: &mut OdsContext,
4501 xml: &mut OdsXmlReader<'_>,
4502 super_tag: &BytesStart<'_>,
4503) -> Result<(Option<String>, ConfigItem), OdsError> {
4504 let mut name = None;
4505 let mut config_set = ConfigItem::new_entry();
4506
4507 for attr in super_tag.attributes().with_checks(false) {
4508 match attr? {
4509 attr if attr.key.as_ref() == b"config:name" => {
4510 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4511 }
4512 attr => {
4513 unused_attr(
4514 "read_config_item_map_entry",
4515 super_tag.name().as_ref(),
4516 &attr,
4517 )?;
4518 }
4519 }
4520 }
4521
4522 let mut buf = ctx.pop_buf();
4523 loop {
4524 let evt = xml.read_event_into(&mut buf)?;
4525 if cfg!(feature = "dump_xml") {
4526 println!(" read_config_item_map_entry {:?}", evt);
4527 }
4528 match &evt {
4529 Event::Empty(xml_tag) if xml_tag.name().as_ref() == b"config:config-item" => {}
4530 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item" => {
4531 let (name, val) = read_config_item(ctx, xml, xml_tag)?;
4532 config_set.insert(name, ConfigItem::from(val));
4533 }
4534
4535 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-set" => {
4536 let (name, val) = read_config_item_set(ctx, xml, xml_tag)?;
4537 config_set.insert(name, val);
4538 }
4539
4540 Event::Start(xml_tag)
4541 if xml_tag.name().as_ref() == b"config:config-item-map-indexed" =>
4542 {
4543 let (name, val) = read_config_item_map_indexed(ctx, xml, xml_tag)?;
4544 config_set.insert(name, val);
4545 }
4546
4547 Event::Start(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-named" => {
4548 let (name, val) = read_config_item_map_named(ctx, xml, xml_tag)?;
4549 config_set.insert(name, val);
4550 }
4551 Event::End(xml_tag) if xml_tag.name().as_ref() == b"config:config-item-map-entry" => {
4552 break;
4553 }
4554
4555 Event::Eof => break,
4556 _ => {
4557 unused_event("read_config_item_map_entry", &evt)?;
4558 }
4559 }
4560
4561 buf.clear();
4562 }
4563 ctx.push_buf(buf);
4564
4565 Ok((name, config_set))
4566}
4567
4568fn read_config_item(
4570 ctx: &mut OdsContext,
4571 xml: &mut OdsXmlReader<'_>,
4572 super_tag: &BytesStart<'_>,
4573) -> Result<(String, ConfigValue), OdsError> {
4574 #[derive(PartialEq)]
4575 enum ConfigValueType {
4576 None,
4577 Base64Binary,
4578 Boolean,
4579 DateTime,
4580 Double,
4581 Int,
4582 Long,
4583 Short,
4584 String,
4585 }
4586
4587 let mut name = None;
4588 let mut val_type = ConfigValueType::None;
4589 let mut config_val = None;
4590
4591 for attr in super_tag.attributes().with_checks(false) {
4592 match attr? {
4593 attr if attr.key.as_ref() == b"config:name" => {
4594 name = Some(attr.decode_and_unescape_value(ctx.decoder)?.to_string());
4595 }
4596 attr if attr.key.as_ref() == b"config:type" => {
4597 val_type = match attr.value.as_ref() {
4598 b"base64Binary" => ConfigValueType::Base64Binary,
4599 b"boolean" => ConfigValueType::Boolean,
4600 b"datetime" => ConfigValueType::DateTime,
4601 b"double" => ConfigValueType::Double,
4602 b"int" => ConfigValueType::Int,
4603 b"long" => ConfigValueType::Long,
4604 b"short" => ConfigValueType::Short,
4605 b"string" => ConfigValueType::String,
4606 x => {
4607 return Err(OdsError::Ods(format!(
4608 "unknown config:type {}",
4609 from_utf8(x)?
4610 )));
4611 }
4612 };
4613 }
4614 attr => {
4615 unused_attr("read_config_item", super_tag.name().as_ref(), &attr)?;
4616 }
4617 }
4618 }
4619
4620 let name = if let Some(name) = name {
4621 name
4622 } else {
4623 return Err(OdsError::Ods(
4624 "config value without config:name".to_string(),
4625 ));
4626 };
4627
4628 if val_type == ConfigValueType::None {
4629 return Err(OdsError::Ods(
4630 "config value without config:type".to_string(),
4631 ));
4632 };
4633
4634 let mut value = ctx.pop_buf();
4635 let mut buf = ctx.pop_buf();
4636 loop {
4637 let evt = xml.read_event_into(&mut buf)?;
4638 match &evt {
4639 Event::GeneralRef(xml_ref) => {
4640 value.write_all(entity(xml_ref)?.as_bytes())?;
4641 }
4642 Event::Text(xml_text) => {
4643 value.write_all(xml_text.decode()?.as_bytes())?;
4644 }
4645 Event::End(xml_tag) if xml_tag.name().as_ref() == b"config:config-item" => {
4646 let value = <Cow<'_, [u8]> as From<&Vec<u8>>>::from(value.as_ref());
4647 match val_type {
4648 ConfigValueType::None => {}
4649 ConfigValueType::Base64Binary => {
4650 config_val =
4651 Some(ConfigValue::Base64Binary(from_utf8(&value)?.to_string()));
4652 }
4653 ConfigValueType::Boolean => {
4654 config_val = Some(ConfigValue::Boolean(parse_bool(&value)?));
4655 }
4656 ConfigValueType::DateTime => {
4657 config_val = Some(ConfigValue::DateTime(parse_datetime(&value)?));
4658 }
4659 ConfigValueType::Double => {
4660 config_val = Some(ConfigValue::Double(parse_f64(&value)?));
4661 }
4662 ConfigValueType::Int => {
4663 config_val = Some(ConfigValue::Int(parse_i32(&value)?));
4664 }
4665 ConfigValueType::Long => {
4666 config_val = Some(ConfigValue::Long(parse_i64(&value)?));
4667 }
4668 ConfigValueType::Short => {
4669 config_val = Some(ConfigValue::Short(parse_i16(&value)?));
4670 }
4671 ConfigValueType::String => {
4672 config_val =
4673 Some(ConfigValue::String(from_utf8(value.as_ref())?.to_string()));
4674 }
4675 }
4676 break;
4677 }
4678 Event::Eof => {
4679 break;
4680 }
4681 _ => {
4682 unused_event("read_config_item", &evt)?;
4683 }
4684 }
4685
4686 if cfg!(feature = "dump_xml") {
4687 println!(" read_config_item {:?}", evt);
4688 }
4689 buf.clear();
4690 }
4691 ctx.push_buf(buf);
4692 ctx.push_buf(value);
4693
4694 let config_val = if let Some(config_val) = config_val {
4695 config_val
4696 } else {
4697 return Err(OdsError::Ods("config-item without value???".to_string()));
4698 };
4699
4700 Ok((name, config_val))
4701}
4702
4703fn read_xml(
4705 ctx: &mut OdsContext,
4706 xml: &mut OdsXmlReader<'_>,
4707 super_tag: &BytesStart<'_>,
4708 empty_tag: bool,
4709) -> Result<XmlTag, OdsError> {
4710 let mut stack = ctx.pop_xml_buf();
4711
4712 let mut tag = XmlTag::new(from_utf8(super_tag.name().as_ref())?);
4713 copy_attr2(ctx, tag.attrmap_mut(), super_tag)?;
4714 stack.push(tag);
4715
4716 if !empty_tag {
4717 let mut buf = ctx.pop_buf();
4718 loop {
4719 let evt = xml.read_event_into(&mut buf)?;
4720 if cfg!(feature = "dump_xml") {
4721 println!(" read_xml {:?}", evt);
4722 }
4723 match &evt {
4724 Event::Start(xml_tag) => {
4725 let mut tag = XmlTag::new(from_utf8(xml_tag.name().as_ref())?);
4726 copy_attr2(ctx, tag.attrmap_mut(), xml_tag)?;
4727 stack.push(tag);
4728 }
4729 Event::End(xml_tag) => {
4730 if xml_tag.name() == super_tag.name() {
4731 break;
4732 } else {
4733 let tag = stack.pop().expect("valid stack");
4734 if let Some(parent) = stack.last_mut() {
4735 parent.add_tag(tag);
4736 } else {
4737 unreachable!()
4738 }
4739 }
4740 }
4741 Event::Empty(xml_tag) => {
4742 let mut emptytag = XmlTag::new(from_utf8(xml_tag.name().as_ref())?);
4743 copy_attr2(ctx, emptytag.attrmap_mut(), xml_tag)?;
4744
4745 if let Some(parent) = stack.last_mut() {
4746 parent.add_tag(emptytag);
4747 } else {
4748 unreachable!()
4749 }
4750 }
4751 Event::GeneralRef(xml_ref) => {
4752 if let Some(parent) = stack.last_mut() {
4753 parent.add_text(entity(xml_ref)?.as_ref());
4754 } else {
4755 unreachable!()
4756 }
4757 }
4758 Event::Text(xml_text) => {
4759 if let Some(parent) = stack.last_mut() {
4760 parent.add_text(xml_text.decode()?.as_ref());
4761 } else {
4762 unreachable!()
4763 }
4764 }
4765 Event::Eof => {
4766 break;
4767 }
4768 _ => {
4769 unused_event("read_xml", &evt)?;
4770 }
4771 }
4772 buf.clear();
4773 }
4774
4775 ctx.push_buf(buf);
4776 }
4777
4778 let tag = stack.pop().unwrap();
4779 ctx.push_xml_buf(stack);
4780 Ok(tag)
4781}
4782
4783fn read_text_or_tag(
4784 ctx: &mut OdsContext,
4785 xml: &mut OdsXmlReader<'_>,
4786 super_tag: &BytesStart<'_>,
4787 empty_tag: bool,
4788) -> Result<TextContent, OdsError> {
4789 let mut stack = ctx.pop_xml_buf();
4790 let mut cellcontent = TextContent::Empty;
4791
4792 let create_toplevel = |ctx: &mut OdsContext, t: Option<String>| -> Result<XmlTag, OdsError> {
4796 let mut toplevel = XmlTag::new(from_utf8(super_tag.name().as_ref())?);
4798 copy_attr2(ctx, toplevel.attrmap_mut(), super_tag)?;
4799 if let Some(t) = t {
4800 toplevel.add_text(t);
4801 }
4802 Ok(toplevel)
4803 };
4804
4805 if !empty_tag {
4806 let mut buf = ctx.pop_buf();
4807 loop {
4808 let evt = xml.read_event_into(&mut buf)?;
4809 if cfg!(feature = "dump_xml") {
4810 println!(" read_xml {:?}", evt);
4811 }
4812 match &evt {
4813 Event::Start(xml_tag) => {
4814 match cellcontent {
4815 TextContent::Empty => {
4816 stack.push(create_toplevel(ctx, None)?);
4817 }
4818 TextContent::Text(old_txt) => {
4819 stack.push(create_toplevel(ctx, Some(old_txt))?);
4820 }
4821 TextContent::Xml(parent) => {
4822 stack.push(parent);
4823 }
4824 TextContent::XmlVec(_) => {
4825 unreachable!()
4826 }
4827 }
4828
4829 let mut new_tag = XmlTag::new(from_utf8(xml_tag.name().as_ref())?);
4831 copy_attr2(ctx, new_tag.attrmap_mut(), xml_tag)?;
4832 cellcontent = TextContent::Xml(new_tag)
4833 }
4834 Event::Empty(xml_tag) => {
4835 match cellcontent {
4836 TextContent::Empty => {
4837 stack.push(create_toplevel(ctx, None)?);
4838 }
4839 TextContent::Text(txt) => {
4840 stack.push(create_toplevel(ctx, Some(txt))?);
4841 }
4842 TextContent::Xml(parent) => {
4843 stack.push(parent);
4844 }
4845 TextContent::XmlVec(_) => {
4846 unreachable!()
4847 }
4848 }
4849 if let Some(mut parent) = stack.pop() {
4850 let mut emptytag = XmlTag::new(from_utf8(xml_tag.name().as_ref())?);
4852 copy_attr2(ctx, emptytag.attrmap_mut(), xml_tag)?;
4853 parent.add_tag(emptytag);
4854
4855 cellcontent = TextContent::Xml(parent);
4856 } else {
4857 unreachable!()
4858 }
4859 }
4860 Event::GeneralRef(xml_ref) => {
4861 let v = entity(xml_ref)?;
4862
4863 cellcontent = match cellcontent {
4864 TextContent::Empty => {
4865 TextContent::Text(v.to_string())
4867 }
4868 TextContent::Text(mut old_txt) => {
4869 old_txt.push_str(&v);
4871 TextContent::Text(old_txt)
4872 }
4873 TextContent::Xml(mut xml) => {
4874 xml.add_text(v);
4876 TextContent::Xml(xml)
4877 }
4878 TextContent::XmlVec(_) => {
4879 unreachable!()
4880 }
4881 };
4882 }
4883 Event::Text(xml_text) => {
4884 let v = xml_text.decode()?;
4885
4886 cellcontent = match cellcontent {
4887 TextContent::Empty => {
4888 TextContent::Text(v.to_string())
4890 }
4891 TextContent::Text(mut old_txt) => {
4892 old_txt.push_str(&v);
4894 TextContent::Text(old_txt)
4895 }
4896 TextContent::Xml(mut xml) => {
4897 xml.add_text(v);
4899 TextContent::Xml(xml)
4900 }
4901 TextContent::XmlVec(_) => {
4902 unreachable!()
4903 }
4904 };
4905 }
4906 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
4907 if !stack.is_empty() {
4908 return Err(OdsError::Ods(format!(
4909 "XML corrupted. Endtag {} occured before all elements are closed: {:?}",
4910 from_utf8(super_tag.name().as_ref())?,
4911 stack
4912 )));
4913 }
4914 break;
4915 }
4916 Event::End(xml_tag) => {
4917 cellcontent = match cellcontent {
4918 TextContent::Empty | TextContent::Text(_) => {
4919 return Err(OdsError::Ods(format!(
4920 "XML corrupted. Endtag {} occured without start tag",
4921 from_utf8(xml_tag.name().as_ref())?
4922 )));
4923 }
4924 TextContent::Xml(tag) => {
4925 if let Some(mut parent) = stack.pop() {
4926 parent.add_tag(tag);
4927 TextContent::Xml(parent)
4928 } else {
4929 return Err(OdsError::Ods(format!(
4930 "XML corrupted. Endtag {} occured without start tag",
4931 from_utf8(xml_tag.name().as_ref())?
4932 )));
4933 }
4934 }
4935 TextContent::XmlVec(_) => {
4936 unreachable!()
4937 }
4938 }
4939 }
4940
4941 Event::Eof => {
4942 break;
4943 }
4944
4945 _ => {
4946 unused_event("read_text_or_tag", &evt)?;
4947 }
4948 }
4949 }
4950 ctx.push_buf(buf);
4951 }
4952
4953 ctx.push_xml_buf(stack);
4954
4955 Ok(cellcontent)
4956}
4957
4958fn read_text<T, E>(
4961 ctx: &mut OdsContext,
4962 xml: &mut OdsXmlReader<'_>,
4963 super_tag: &BytesStart<'_>,
4964 empty_tag: bool,
4965 parse: fn(&[u8]) -> Result<T, E>,
4966) -> Result<Option<T>, OdsError>
4967where
4968 OdsError: From<E>,
4969{
4970 if empty_tag {
4971 Ok(None)
4972 } else {
4973 let mut result_buf = ctx.pop_buf();
4974 let mut buf = ctx.pop_buf();
4975 loop {
4976 let evt = xml.read_event_into(&mut buf)?;
4977 if cfg!(feature = "dump_xml") {
4978 println!(" read_text {:?}", evt);
4979 }
4980 match &evt {
4981 Event::GeneralRef(xml_ref) => {
4982 result_buf.extend_from_slice(entity(xml_ref)?.as_bytes());
4983 }
4984 Event::Text(xml_text) => {
4985 result_buf.extend_from_slice(xml_text.as_ref());
4986 }
4987 Event::End(xml_tag) if xml_tag.name() == super_tag.name() => {
4988 break;
4989 }
4990 Event::Empty(xml_tag) | Event::Start(xml_tag) => {
4991 return Err(OdsError::Ods(from_utf8(xml_tag.as_ref())?.to_string()));
4992 }
4993 Event::End(xml_tag) => {
4994 return Err(OdsError::Ods(from_utf8(xml_tag.as_ref())?.to_string()));
4995 }
4996 Event::Eof => {
4997 break;
4998 }
4999 _ => {
5000 unused_event("read_text", &evt)?;
5001 }
5002 }
5003 }
5004 ctx.push_buf(buf);
5005
5006 let result = parse(&result_buf)?;
5007 ctx.push_buf(result_buf);
5008
5009 Ok(Some(result))
5010 }
5011}
5012
5013fn entity(xml_ref: &BytesRef) -> Result<Cow<'static, str>, quick_xml::Error> {
5014 if let Some(cc) = xml_ref.resolve_char_ref()? {
5015 Ok(Cow::Owned(format!("{}", cc)))
5016 } else {
5017 let xml_ref = xml_ref.decode()?;
5018 match xml_ref.as_ref() {
5019 "lt" => Ok(Cow::Borrowed("<")),
5020 "gt" => Ok(Cow::Borrowed(">")),
5021 "amp" => Ok(Cow::Borrowed("&")),
5022 "apos" => Ok(Cow::Borrowed("'")),
5023 "quot" => Ok(Cow::Borrowed("\"")),
5024 other => Ok(Cow::Owned(format!("&{};", other))),
5025 }
5026 }
5027}
5028
5029#[inline(always)]
5030fn unused_attr(func: &str, tag: &[u8], attr: &Attribute<'_>) -> Result<(), OdsError> {
5031 if cfg!(feature = "dump_unused") {
5032 let tag = from_utf8(tag)?;
5033 let key = from_utf8(attr.key.as_ref())?;
5034 let value = from_utf8(attr.value.as_ref())?;
5035 println!("unused attr: {} '{}' ({}:{})", func, tag, key, value);
5036 }
5037 Ok(())
5038}
5039
5040#[inline(always)]
5041fn unused_event(func: &str, evt: &Event<'_>) -> Result<(), OdsError> {
5042 if cfg!(feature = "dump_unused") {
5043 match &evt {
5044 Event::Text(xml_text) => {
5045 if !xml_text.decode()?.trim().is_empty() {
5046 println!("unused text: {} ({:?})", func, evt);
5047 }
5048 }
5049 _ => {
5050 println!("unused event: {} ({:?})", func, evt);
5051 }
5052 }
5053 }
5054 Ok(())
5055}