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#[derive(Debug, Default)]
58pub struct OdsOptions {
59 content_only: bool,
61 use_repeat_for_cells: bool,
63 ignore_empty_cells: bool,
65}
66
67impl OdsOptions {
68 pub fn content_only(mut self) -> Self {
73 self.content_only = true;
74 self
75 }
76
77 pub fn read_styles(mut self) -> Self {
83 self.content_only = false;
84 self
85 }
86
87 pub fn use_repeat_for_cells(mut self) -> Self {
94 self.use_repeat_for_cells = true;
95 self
96 }
97
98 pub fn use_clone_for_cells(mut self) -> Self {
108 self.use_repeat_for_cells = false;
109 self
110 }
111
112 pub fn ignore_empty_cells(mut self) -> Self {
117 self.ignore_empty_cells = true;
118 self
119 }
120
121 pub fn read_empty_cells(mut self) -> Self {
129 self.ignore_empty_cells = false;
130 self
131 }
132
133 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 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
153pub fn read_ods_buf(buf: &[u8]) -> Result<WorkBook, OdsError> {
155 let read = Cursor::new(buf);
156 OdsOptions::default().read_ods(read)
157}
158
159pub fn read_ods_from<T: Read + Seek>(read: T) -> Result<WorkBook, OdsError> {
161 OdsOptions::default().read_ods(read)
162}
163
164pub 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
170pub 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
176pub 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
182pub 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 fn pop_buf(&mut self) -> Vec<u8> {
242 self.buffers.pop().unwrap_or_default()
243 }
244
245 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 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 }
341 }
342 }
343 ctx.push_buf(buf);
344
345 calculations(&mut ctx)?;
346
347 Ok(ctx.book)
348}
349
350fn 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 calc_derived(&mut ctx.book)?;
400
401 Ok(ctx.book)
402}
403
404fn 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 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 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 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
487fn 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
500fn calc_repeat_sheet(sheet: &mut Sheet) -> Result<(), OdsError> {
502 let mut dropped = Vec::new();
503
504 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 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 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
540fn calc_cloned_sheet(sheet: &mut Sheet) -> Result<(), OdsError> {
542 let mut cloned = Vec::new();
543 let mut dropped = Vec::new();
544
545 for (_row, rh) in sheet.row_header.iter_mut().rev().take(5) {
549 if rh.repeat > 1000 {
550 rh.repeat = 1;
551 }
552 }
553 for (row, rh) in sheet.row_header.iter().filter(|(_, v)| v.repeat > 1) {
555 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 for (_row, rh) in sheet.row_header.iter_mut() {
569 mem::swap(&mut rh.repeat, &mut rh.span);
570 }
571
572 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 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
609fn 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 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 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
724fn 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
779fn 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 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 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 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 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
902fn 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 let mut row: u32 = 0;
914 let mut col: u32 = 0;
915 let mut col_data: bool = false;
916
917 let mut col_range_from = 0;
919 let mut col_group = ctx.pop_colgroup_buf();
920
921 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 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 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 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 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 }
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 }
1039 Event::End(xml_tag) if xml_tag.name().as_ref() == b"table:table-rows" => {
1040 }
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 sheet.set_row_repeat(row, row_repeat);
1050 }
1051 row += row_repeat;
1052 row_repeat = 1;
1053 col_data = false;
1054 }
1055
1056 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
1085fn 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
1119fn 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 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
1163fn 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
1192fn 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
1218fn 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 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 }
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 set_value(tc, &mut cell)?;
1467
1468 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 content = match content {
1502 TextContent::Empty => new_txt,
1503 TextContent::Text(txt) => {
1504 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 }
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 }
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
1875fn 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
1909fn 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
1953fn 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 }
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 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
2229fn 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
2264fn 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
2343fn 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 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
2428fn 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
2480fn 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
2534fn 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
2591fn 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 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
2889fn 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#[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 }
3029 }
3030 }
3031
3032 Ok(())
3033}
3034
3035#[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 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#[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 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#[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 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#[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 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)
3256 if xml_tag.name().as_ref() == b"style:map" =>
3257 {
3258 style.push_stylemap(read_stylemap(xml, xml_tag)?);
3259 }
3260 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#[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 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 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#[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 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#[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 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#[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 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
3515fn 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
3569fn 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
3593fn 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 }
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
4170fn 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
4244fn 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
4278fn 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
4346fn 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
4408fn 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
4476fn 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
4546fn 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
4678fn 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 let create_toplevel =
4764 |xml: &mut OdsXmlReader<'_>, t: Option<String>| -> Result<XmlTag, OdsError> {
4765 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 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 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 TextContent::Text(v.to_string())
4836 }
4837 TextContent::Text(mut old_txt) => {
4838 old_txt.push_str(&v);
4840 TextContent::Text(old_txt)
4841 }
4842 TextContent::Xml(mut xml) => {
4843 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
4906fn 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}