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