spreadsheet_ods/io/
read.rs

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