1use std::{
2 collections::{HashMap, HashSet},
3 str::FromStr,
4};
5
6mod bookmark_id;
7mod build_xml;
8mod comments;
9mod comments_extended;
10mod content_types;
11mod custom_item;
12mod custom_item_property;
13mod custom_item_rels;
14mod doc_props;
15mod document;
16mod document_rels;
17mod elements;
18mod font_table;
19mod footer;
20mod footer_id;
21mod footer_rels;
22mod footnote_id;
23mod footnotes;
24mod header;
25mod header_id;
26mod header_rels;
27mod history_id;
28mod hyperlink_id;
29mod image_collector;
30mod numberings;
31mod paragraph_id;
32mod paragraph_property_change_id;
33mod pic_id;
34mod preset_styles;
35mod rels;
36mod settings;
37mod styles;
38mod taskpanes;
39mod taskpanes_rels;
40mod theme;
41mod toc_key;
42mod web_settings;
43mod webextension;
44mod xml_docx;
45
46pub use build_xml::BuildXML;
47pub(crate) use history_id::HistoryId;
48pub(crate) use hyperlink_id::*;
49pub(crate) use paragraph_id::*;
50pub(crate) use paragraph_property_change_id::ParagraphPropertyChangeId;
51pub(crate) use pic_id::*;
52
53pub use bookmark_id::*;
54pub use comments::*;
55pub use comments_extended::*;
56pub use content_types::*;
57pub use custom_item::*;
58pub use custom_item_property::*;
59pub use custom_item_rels::*;
60pub use doc_props::*;
61pub use document::*;
62pub use document_rels::*;
63pub use elements::*;
64pub use font_table::*;
65pub use footer::*;
66pub use footer_id::*;
67pub use footer_rels::*;
68pub use footnotes::*;
69pub use header::*;
70pub use header_id::*;
71pub use header_rels::*;
72pub use numberings::*;
73pub use rels::*;
74pub use settings::*;
75pub use styles::*;
76pub use taskpanes::*;
77pub use taskpanes_rels::*;
78pub use theme::*;
79pub use toc_key::*;
80pub use web_settings::*;
81pub use webextension::*;
82pub use xml_docx::*;
83
84use base64::Engine;
85use serde::{ser, Serialize};
86
87use self::image_collector::{collect_images_from_paragraph, collect_images_from_table};
88
89#[derive(Debug, Clone)]
90pub struct Image(pub Vec<u8>);
91
92#[derive(Debug, Clone)]
100pub struct Png(pub Vec<u8>);
101
102pub type ImageIdAndPath = (String, String);
103pub type ImageIdAndBuf = (String, Vec<u8>);
104
105fn is_emf(path: &str, buf: &[u8]) -> bool {
106 if path.to_ascii_lowercase().ends_with(".emf") {
107 return true;
108 }
109 buf.len() >= 44
113 && buf[0..4] == [0x01, 0x00, 0x00, 0x00]
114 && buf[40..44] == [0x20, 0x45, 0x4D, 0x46]
115}
116
117impl ser::Serialize for Image {
118 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119 where
120 S: ser::Serializer,
121 {
122 let base64 = base64::engine::general_purpose::STANDARD.encode(&self.0);
123 serializer.collect_str(&base64)
124 }
125}
126
127impl ser::Serialize for Png {
128 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
129 where
130 S: ser::Serializer,
131 {
132 let base64 = base64::engine::general_purpose::STANDARD.encode(&self.0);
133 serializer.collect_str(&base64)
134 }
135}
136
137#[derive(Debug, Clone, Serialize)]
138#[serde(rename_all = "camelCase")]
139pub struct Docx {
140 pub content_type: ContentTypes,
141 pub rels: Rels,
142 pub document_rels: DocumentRels,
143 pub doc_props: DocProps,
144 pub styles: Styles,
145 pub document: Document,
146 pub comments: Comments,
147 pub numberings: Numberings,
148 pub settings: Settings,
149 pub font_table: FontTable,
150 pub media: Vec<(String, Vec<u8>)>,
151 pub comments_extended: CommentsExtended,
152 pub web_settings: WebSettings,
153 pub taskpanes: Option<Taskpanes>,
154 pub taskpanes_rels: TaskpanesRels,
155 pub web_extensions: Vec<WebExtension>,
156 pub custom_items: Vec<CustomItem>,
157 pub custom_item_props: Vec<CustomItemProperty>,
158 pub custom_item_rels: Vec<CustomItemRels>,
159 pub themes: Vec<Theme>,
161 pub images: Vec<(String, String, Image, Png)>,
168 pub hyperlinks: Vec<(String, String, String)>,
170 pub footnotes: Footnotes,
171}
172
173impl Default for Docx {
174 fn default() -> Self {
175 let content_type = ContentTypes::new().set_default();
176 let rels = Rels::new().set_default();
177 let doc_props = DocProps::new(CorePropsConfig::new());
178 let styles = Styles::new();
179 let document = Document::new();
180 let document_rels = DocumentRels::new();
181 let settings = Settings::new();
182 let font_table = FontTable::new();
183 let comments = Comments::new();
184 let numberings = Numberings::new();
185 let media = vec![];
186 let comments_extended = CommentsExtended::new();
187 let web_settings = WebSettings::new();
188 let footnotes = Footnotes::default();
189
190 Docx {
191 content_type,
192 rels,
193 document_rels,
194 doc_props,
195 styles,
196 document,
197 comments,
198 numberings,
199 settings,
200 font_table,
201 media,
202 comments_extended,
203 web_settings,
204 taskpanes: None,
205 taskpanes_rels: TaskpanesRels::new(),
206 web_extensions: vec![],
207 custom_items: vec![],
208 custom_item_props: vec![],
209 custom_item_rels: vec![],
210 themes: vec![],
211 images: vec![],
212 hyperlinks: vec![],
213 footnotes,
214 }
215 }
216}
217
218impl Docx {
219 pub fn new() -> Docx {
220 Default::default()
221 }
222
223 pub fn document(mut self, d: Document) -> Docx {
224 for child in &self.document.children {
225 match child {
226 DocumentChild::Paragraph(paragraph) => {
227 if paragraph.has_numbering {
228 self.document_rels.has_numberings = true;
229 }
230 }
231 DocumentChild::Table(table) if table.has_numbering => {
232 self.document_rels.has_numberings = true;
233 }
234 _ => {}
235 }
236 }
237 self.document = d;
238 self
239 }
240
241 pub fn styles(mut self, s: Styles) -> Self {
242 self.styles = s;
243 self
244 }
245
246 pub fn add_style(mut self, s: Style) -> Self {
247 self.styles = self.styles.add_style(s);
248 self
249 }
250
251 pub fn numberings(mut self, n: Numberings) -> Self {
252 self.numberings = n;
253 self
254 }
255
256 pub fn settings(mut self, s: Settings) -> Self {
257 self.settings = s;
258 self
259 }
260
261 pub(crate) fn web_settings(mut self, s: WebSettings) -> Self {
263 self.web_settings = s;
264 self
265 }
266
267 pub(crate) fn add_image(
269 mut self,
270 id: impl Into<String>,
271 path: impl Into<String>,
272 buf: Vec<u8>,
273 ) -> Self {
274 let path: String = path.into();
275
276 if is_emf(&path, &buf) {
277 self.images
278 .push((id.into(), path, Image(buf), Png(Vec::new())));
279 return self;
280 }
281
282 #[cfg(feature = "image")]
283 if let Ok(dimg) = image::load_from_memory(&buf) {
284 let mut png = std::io::Cursor::new(vec![]);
285 dimg.write_to(&mut png, image::ImageFormat::Png)
287 .expect("Unable to write dynamic image");
288
289 self.images
290 .push((id.into(), path, Image(buf), Png(png.into_inner())));
291 }
292 #[cfg(not(feature = "image"))]
293 if buf.starts_with(&[137, 80, 78, 71, 13, 10, 26, 10]) {
295 self.images
296 .push((id.into(), path, Image(buf.clone()), Png(buf)));
297 }
298 self
299 }
300
301 pub(crate) fn add_hyperlink(
303 mut self,
304 id: impl Into<String>,
305 path: impl Into<String>,
306 r#type: impl Into<String>,
307 ) -> Self {
308 self.hyperlinks
309 .push((id.into(), path.into(), r#type.into()));
310 self
311 }
312
313 pub fn comments(mut self, c: Comments) -> Self {
314 self.comments = c;
315 self
316 }
317
318 pub fn comments_extended(mut self, c: CommentsExtended) -> Self {
319 self.comments_extended = c;
320 self
321 }
322
323 pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
324 if p.has_numbering {
325 self.document_rels.has_numberings = true;
328 }
329 self.document = self.document.add_paragraph(p);
330 self
331 }
332
333 pub fn add_section(mut self, s: Section) -> Docx {
334 if s.has_numbering {
335 self.document_rels.has_numberings = true;
338 }
339
340 let mut new_section = s;
341
342 if let Some(header) = new_section.temp_header {
344 if header.has_numbering {
345 self.document_rels.has_numberings = true;
346 }
347 let count = self.document_rels.header_count + 1;
348 new_section = Section {
349 property: new_section
350 .property
351 .header(header, &create_header_rid(count)),
352 children: new_section.children,
353 has_numbering: new_section.has_numbering,
354 temp_header: None,
355 ..Default::default()
356 };
357 self.document_rels.header_count = count;
358 self.content_type = self.content_type.add_header();
359 }
360
361 if let Some(header) = new_section.temp_first_header {
362 if header.has_numbering {
363 self.document_rels.has_numberings = true;
364 }
365 let count = self.document_rels.header_count + 1;
366 new_section = Section {
367 property: new_section
368 .property
369 .first_header(header, &create_header_rid(count)),
370 children: new_section.children,
371 has_numbering: new_section.has_numbering,
372 temp_first_header: None,
373 ..Default::default()
374 };
375 self.document_rels.header_count = count;
376 self.content_type = self.content_type.add_header();
377 }
378
379 if let Some(header) = new_section.temp_even_header {
380 if header.has_numbering {
381 self.document_rels.has_numberings = true;
382 }
383 let count = self.document_rels.header_count + 1;
384 new_section = Section {
385 property: new_section
386 .property
387 .even_header(header, &create_header_rid(count)),
388 children: new_section.children,
389 has_numbering: new_section.has_numbering,
390 temp_even_header: None,
391 ..Default::default()
392 };
393 self.document_rels.header_count = count;
394 self.content_type = self.content_type.add_header();
395 }
396
397 if let Some(header) = new_section.temp_header {
399 if header.has_numbering {
400 self.document_rels.has_numberings = true;
401 }
402 let count = self.document_rels.header_count + 1;
403 new_section = Section {
404 property: new_section
405 .property
406 .header(header, &create_header_rid(count)),
407 children: new_section.children,
408 has_numbering: new_section.has_numbering,
409 temp_header: None,
410 ..Default::default()
411 };
412 self.document_rels.header_count = count;
413 self.content_type = self.content_type.add_header();
414 }
415
416 if let Some(header) = new_section.temp_first_header {
417 if header.has_numbering {
418 self.document_rels.has_numberings = true;
419 }
420 let count = self.document_rels.header_count + 1;
421 new_section = Section {
422 property: new_section
423 .property
424 .first_header(header, &create_header_rid(count)),
425 children: new_section.children,
426 has_numbering: new_section.has_numbering,
427 temp_first_header: None,
428 ..Default::default()
429 };
430 self.document_rels.header_count = count;
431 self.content_type = self.content_type.add_header();
432 }
433
434 if let Some(header) = new_section.temp_even_header {
435 if header.has_numbering {
436 self.document_rels.has_numberings = true;
437 }
438 let count = self.document_rels.header_count + 1;
439 new_section = Section {
440 property: new_section
441 .property
442 .even_header(header, &create_header_rid(count)),
443 children: new_section.children,
444 has_numbering: new_section.has_numbering,
445 temp_even_header: None,
446 ..Default::default()
447 };
448 self.document_rels.header_count = count;
449 self.content_type = self.content_type.add_header();
450 }
451
452 if let Some(footer) = new_section.temp_footer {
454 if footer.has_numbering {
455 self.document_rels.has_numberings = true;
456 }
457 let count = self.document_rels.footer_count + 1;
458 new_section = Section {
459 property: new_section
460 .property
461 .footer(footer, &create_footer_rid(count)),
462 children: new_section.children,
463 has_numbering: new_section.has_numbering,
464 temp_footer: None,
465 ..Default::default()
466 };
467 self.document_rels.footer_count = count;
468 self.content_type = self.content_type.add_footer();
469 }
470
471 if let Some(footer) = new_section.temp_first_footer {
472 if footer.has_numbering {
473 self.document_rels.has_numberings = true;
474 }
475 let count = self.document_rels.footer_count + 1;
476 new_section = Section {
477 property: new_section
478 .property
479 .first_footer(footer, &create_footer_rid(count)),
480 children: new_section.children,
481 has_numbering: new_section.has_numbering,
482 temp_first_footer: None,
483 ..Default::default()
484 };
485 self.document_rels.footer_count = count;
486 self.content_type = self.content_type.add_footer();
487 }
488
489 if let Some(footer) = new_section.temp_even_footer {
490 if footer.has_numbering {
491 self.document_rels.has_numberings = true;
492 }
493 let count = self.document_rels.footer_count + 1;
494 new_section = Section {
495 property: new_section
496 .property
497 .even_footer(footer, &create_footer_rid(count)),
498 children: new_section.children,
499 has_numbering: new_section.has_numbering,
500 temp_even_footer: None,
501 ..Default::default()
502 };
503 self.document_rels.footer_count = count;
504 self.content_type = self.content_type.add_footer();
505 }
506
507 self.document = self.document.add_section(new_section);
508 self
509 }
510
511 pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Docx {
512 if t.has_numbering {
513 self.document_rels.has_numberings = true;
516 }
517 self.document = self.document.add_structured_data_tag(t);
518 self
519 }
520
521 pub fn add_table_of_contents(mut self, t: TableOfContents) -> Docx {
522 self.document = self.document.add_table_of_contents(t);
523 self
524 }
525
526 pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Docx {
527 self.document = self.document.add_bookmark_start(id, name);
528 self
529 }
530
531 pub fn add_bookmark_end(mut self, id: usize) -> Docx {
532 self.document = self.document.add_bookmark_end(id);
533 self
534 }
535
536 pub fn add_table(mut self, t: Table) -> Docx {
537 if t.has_numbering {
538 self.document_rels.has_numberings = true;
541 }
542 self.document = self.document.add_table(t);
543 self
544 }
545
546 pub fn header(mut self, header: Header) -> Self {
547 if header.has_numbering {
548 self.document_rels.has_numberings = true;
549 }
550 let count = self.document_rels.header_count + 1;
551 self.document.section_property = self
552 .document
553 .section_property
554 .header(header, &create_header_rid(count));
555 self.document_rels.header_count = count;
556 self.content_type = self.content_type.add_header();
557 self
558 }
559
560 pub fn first_header(mut self, header: Header) -> Self {
561 if header.has_numbering {
562 self.document_rels.has_numberings = true;
563 }
564 let count = self.document_rels.header_count + 1;
565 self.document.section_property = self
566 .document
567 .section_property
568 .first_header(header, &create_header_rid(count));
569 self.document_rels.header_count = count;
570 self.content_type = self.content_type.add_header();
571 self
572 }
573
574 pub fn even_header(mut self, header: Header) -> Self {
575 if header.has_numbering {
576 self.document_rels.has_numberings = true;
577 }
578 let count = self.document_rels.header_count + 1;
579 self.document.section_property = self
580 .document
581 .section_property
582 .even_header(header, &create_header_rid(count));
583 self.document_rels.header_count = count;
584 self.content_type = self.content_type.add_header();
585 self.settings = self.settings.even_and_odd_headers();
586 self
587 }
588
589 pub fn footer(mut self, footer: Footer) -> Self {
590 if footer.has_numbering {
591 self.document_rels.has_numberings = true;
592 }
593 let count = self.document_rels.footer_count + 1;
594 self.document.section_property = self
595 .document
596 .section_property
597 .footer(footer, &create_footer_rid(count));
598 self.document_rels.footer_count = count;
599 self.content_type = self.content_type.add_footer();
600 self
601 }
602
603 pub fn first_footer(mut self, footer: Footer) -> Self {
604 if footer.has_numbering {
605 self.document_rels.has_numberings = true;
606 }
607 let count = self.document_rels.footer_count + 1;
608 self.document.section_property = self
609 .document
610 .section_property
611 .first_footer(footer, &create_footer_rid(count));
612 self.document_rels.footer_count = count;
613 self.content_type = self.content_type.add_footer();
614 self
615 }
616
617 pub fn even_footer(mut self, footer: Footer) -> Self {
618 if footer.has_numbering {
619 self.document_rels.has_numberings = true;
620 }
621 let count = self.document_rels.footer_count + 1;
622 self.document.section_property = self
623 .document
624 .section_property
625 .even_footer(footer, &create_footer_rid(count));
626 self.document_rels.footer_count = count;
627 self.content_type = self.content_type.add_footer();
628 self.settings = self.settings.even_and_odd_headers();
629 self
630 }
631
632 pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
633 self.numberings = self.numberings.add_abstract_numbering(num);
634 self
635 }
636
637 pub fn add_numbering(mut self, num: Numbering) -> Docx {
638 self.numberings = self.numberings.add_numbering(num);
639 self
640 }
641
642 pub fn created_at(mut self, date: &str) -> Self {
643 self.doc_props = self.doc_props.created_at(date);
644 self
645 }
646
647 pub fn updated_at(mut self, date: &str) -> Self {
648 self.doc_props = self.doc_props.updated_at(date);
649 self
650 }
651
652 pub fn custom_property(mut self, name: impl Into<String>, item: impl Into<String>) -> Self {
653 self.doc_props = self.doc_props.custom_property(name, item);
654 self
655 }
656
657 pub fn doc_id(mut self, id: &str) -> Self {
658 self.settings = self.settings.doc_id(id);
659 self
660 }
661
662 pub fn default_tab_stop(mut self, stop: usize) -> Self {
663 self.settings = self.settings.default_tab_stop(stop);
664 self
665 }
666
667 pub fn add_doc_var(mut self, name: &str, val: &str) -> Self {
668 self.settings = self.settings.add_doc_var(name, val);
669 self
670 }
671
672 pub fn title_pg(mut self) -> Self {
673 self.document = self.document.title_pg();
674 self
675 }
676
677 pub fn page_size(mut self, w: u32, h: u32) -> Self {
678 self.document = self.document.page_size(PageSize::new().size(w, h));
679 self
680 }
681
682 pub fn page_margin(mut self, margin: crate::types::PageMargin) -> Self {
683 self.document = self.document.page_margin(margin);
684 self
685 }
686
687 pub fn page_orient(mut self, o: crate::types::PageOrientationType) -> Self {
688 self.document = self.document.page_orient(o);
689 self
690 }
691
692 pub fn default_size(mut self, size: usize) -> Self {
693 self.styles = self.styles.default_size(size);
694 self
695 }
696
697 pub fn default_spacing(mut self, spacing: i32) -> Self {
698 self.styles = self.styles.default_spacing(spacing);
699 self
700 }
701
702 pub fn default_fonts(mut self, font: RunFonts) -> Self {
703 self.styles = self.styles.default_fonts(font);
704 self
705 }
706
707 pub fn default_line_spacing(mut self, spacing: LineSpacing) -> Self {
708 self.styles = self.styles.default_line_spacing(spacing);
709 self
710 }
711
712 pub fn taskpanes(mut self) -> Self {
713 self.taskpanes = Some(Taskpanes::new());
714 self.rels = self.rels.add_taskpanes_rel();
715 self.content_type = self.content_type.add_taskpanes();
716 self
717 }
718
719 pub fn web_extension(mut self, ext: WebExtension) -> Self {
720 self.web_extensions.push(ext);
721 self.taskpanes_rels = self.taskpanes_rels.add_rel();
722 self.content_type = self.content_type.add_web_extensions();
723 self
724 }
725
726 pub fn add_custom_item(mut self, id: &str, xml: &str) -> Self {
727 let x = CustomItem::from_str(xml).expect("should parse xml string");
728 self.content_type = self.content_type.add_custom_xml();
729 let rel = CustomItemRels::new().add_item();
730 self.custom_item_props.push(CustomItemProperty::new(id));
731 self.document_rels = self.document_rels.add_custom_item();
732 self.custom_item_rels.push(rel);
733 self.custom_items.push(x);
734 self
735 }
736
737 pub fn page_num_type(mut self, p: PageNumType) -> Self {
738 self.document = self.document.page_num_type(p);
739 self
740 }
741
742 pub fn build(mut self) -> XMLDocx {
743 self.reset();
744 self.refresh_duplicate_para_ids();
745
746 self.update_dependencies();
747
748 let tocs: Vec<(usize, Box<TableOfContents>)> = self
749 .document
750 .children
751 .iter()
752 .enumerate()
753 .filter_map(|(i, child)| {
754 if let DocumentChild::TableOfContents(toc) = child {
755 Some((i, toc.clone()))
756 } else {
757 None
758 }
759 })
760 .collect();
761
762 let has_toc = !tocs.is_empty();
763
764 for (i, toc) in tocs {
765 if toc.items.is_empty() && toc.auto {
766 let children =
767 update_document_by_toc(self.document.children, &self.styles, *toc, i);
768 self.document.children = children;
769 }
770 }
771
772 let (images, mut images_bufs) = self.images_in_doc();
773 let (header_images, header_images_bufs) = self.images_in_header();
774 let (footer_images, footer_images_bufs) = self.images_in_footer();
775
776 images_bufs.extend(header_images_bufs);
777 images_bufs.extend(footer_images_bufs);
778
779 let mut header_rels = vec![HeaderRels::new(); 3];
780 for (i, images) in header_images.iter().enumerate() {
781 if let Some(h) = header_rels.get_mut(i) {
782 h.set_images(images.to_owned());
783 }
784 }
785 let mut footer_rels = vec![FooterRels::new(); 3];
786 for (i, images) in footer_images.iter().enumerate() {
787 if let Some(f) = footer_rels.get_mut(i) {
788 f.set_images(images.to_owned());
789 }
790 }
791
792 let web_extensions = self.web_extensions.iter().map(|ext| ext.build()).collect();
793 let custom_items = self.custom_items.iter().map(|xml| xml.build()).collect();
794 let custom_item_props = self.custom_item_props.iter().map(|p| p.build()).collect();
795 let custom_item_rels = self
796 .custom_item_rels
797 .iter()
798 .map(|rel| rel.build())
799 .collect();
800
801 self.document_rels.images = images;
802
803 let mut headers: Vec<&(String, Header)> = self.document.section_property.get_headers();
804
805 self.document.children.iter().for_each(|child| {
806 if let DocumentChild::Section(section) = child {
807 for h in section.property.get_headers() {
808 headers.push(h);
809 }
810 }
811 });
812
813 headers.sort_by(|a, b| a.0.cmp(&b.0));
814 let headers = headers.iter().map(|h| h.1.build()).collect();
815
816 let mut footers: Vec<&(String, Footer)> = self.document.section_property.get_footers();
817
818 self.document.children.iter().for_each(|child| {
819 if let DocumentChild::Section(section) = child {
820 for h in section.property.get_footers() {
821 footers.push(h);
822 }
823 }
824 });
825
826 footers.sort_by(|a, b| a.0.cmp(&b.0));
827 let footers = footers.iter().map(|h| h.1.build()).collect();
828
829 if self.collect_footnotes() {
831 self.content_type = self.content_type.add_footnotes();
833 self.document_rels.has_footnotes = true;
834 }
835
836 if has_toc {
837 for i in 1..=9 {
838 if !self
839 .styles
840 .styles
841 .iter()
842 .any(|s| s.name == Name::new(format!("toc {i}")))
843 {
844 self.styles = self
845 .styles
846 .add_style(crate::documents::preset_styles::toc(i));
847 }
848 }
849 }
850
851 XMLDocx {
852 content_type: self.content_type.build(),
853 rels: self.rels.build(),
854 doc_props: self.doc_props.build(),
855 styles: self.styles.build(),
856 document: self.document.build(),
857 comments: self.comments.build(),
858 document_rels: self.document_rels.build(),
859 header_rels: header_rels.into_iter().map(|r| r.build()).collect(),
860 footer_rels: footer_rels.into_iter().map(|r| r.build()).collect(),
861 settings: self.settings.build(),
862 font_table: self.font_table.build(),
863 numberings: self.numberings.build(),
864 media: images_bufs,
865 headers,
866 footers,
867 comments_extended: self.comments_extended.build(),
868 taskpanes: self.taskpanes.map(|taskpanes| taskpanes.build()),
869 taskpanes_rels: self.taskpanes_rels.build(),
870 web_extensions,
871 custom_items,
872 custom_item_rels,
873 custom_item_props,
874 footnotes: self.footnotes.build(),
875 }
876 }
877
878 pub fn json(&self) -> String {
879 self.reset();
880
881 serde_json::to_string_pretty(&self).unwrap()
882 }
883
884 pub fn json_with_update_comments(&mut self) -> String {
886 self.reset();
887
888 self.update_dependencies();
889 serde_json::to_string_pretty(&self).unwrap()
890 }
891
892 pub fn comments_json(&mut self) -> String {
894 self.reset();
895 self.update_dependencies();
896 serde_json::to_string_pretty(&self.comments).unwrap()
897 }
898
899 fn reset(&self) {
900 crate::reset_para_id();
901 }
902
903 fn refresh_duplicate_para_ids(&mut self) {
904 let mut counts: HashMap<String, usize> = HashMap::new();
905 collect_para_ids_in_docx(self, &mut counts);
906
907 let mut used: HashSet<String> = counts.keys().cloned().collect();
908 let mut seen: HashSet<String> = HashSet::new();
909
910 refresh_para_ids_in_docx(self, &counts, &mut used, &mut seen);
911 }
912
913 fn insert_comment_to_map(
914 &self,
915 comment_map: &mut HashMap<usize, String>,
916 c: &CommentRangeStart,
917 ) {
918 let comment = c.get_comment_ref();
919 let comment_id = comment.id();
920 for child in &comment.children {
921 if let CommentChild::Paragraph(child) = child {
922 let para_id = child.id.clone();
923 comment_map.insert(comment_id, para_id);
924 }
925 }
927 }
928
929 fn update_dependencies(&mut self) {
931 let mut comments: Vec<Comment> = vec![];
932 let mut comments_extended: Vec<CommentExtended> = vec![];
933 let mut comment_map: HashMap<usize, String> = HashMap::new();
934
935 let mut hyperlink_map: HashMap<String, String> = HashMap::new();
936
937 for child in &self.document.children {
938 match child {
939 DocumentChild::Paragraph(paragraph) => {
940 for child in ¶graph.children {
941 if let ParagraphChild::CommentStart(c) = child {
942 self.insert_comment_to_map(&mut comment_map, c);
943 }
944 if let ParagraphChild::Hyperlink(h) = child {
945 for child in &h.children {
946 if let ParagraphChild::CommentStart(c) = child {
947 self.insert_comment_to_map(&mut comment_map, c);
948 }
949 }
950 }
951 }
952 }
953 DocumentChild::Table(table) => {
954 collect_comment_map_in_table(table, &mut comment_map);
955 }
956 DocumentChild::TableOfContents(toc) => {
957 for child in &toc.before_contents {
958 if let TocContent::Paragraph(paragraph) = child {
959 collect_comment_map_in_paragraph(paragraph, &mut comment_map);
960 }
961 if let TocContent::Table(table) = child {
962 collect_comment_map_in_table(table, &mut comment_map);
963 }
964 }
965 for child in &toc.after_contents {
966 if let TocContent::Paragraph(paragraph) = child {
967 collect_comment_map_in_paragraph(paragraph, &mut comment_map);
968 }
969 if let TocContent::Table(table) = child {
970 collect_comment_map_in_table(table, &mut comment_map);
971 }
972 }
973 }
974 _ => {}
975 }
976 }
977
978 for child in &self.document.children {
979 match child {
980 DocumentChild::Paragraph(paragraph) => {
981 for child in ¶graph.children {
982 if let ParagraphChild::CommentStart(c) = child {
983 push_comment_and_comment_extended(
984 &mut comments,
985 &mut comments_extended,
986 &comment_map,
987 c,
988 );
989 }
990 if let ParagraphChild::Hyperlink(h) = child {
991 if let HyperlinkData::External { rid, path } = &h.link {
992 hyperlink_map.insert(rid.clone(), path.clone());
993 };
994 for child in &h.children {
995 if let ParagraphChild::CommentStart(c) = child {
996 push_comment_and_comment_extended(
997 &mut comments,
998 &mut comments_extended,
999 &comment_map,
1000 c,
1001 );
1002 }
1003 }
1004 }
1005 }
1006 }
1007 DocumentChild::Table(table) => {
1008 collect_dependencies_in_table(
1009 table,
1010 &mut comments,
1011 &mut comments_extended,
1012 &mut comment_map,
1013 &mut hyperlink_map,
1014 );
1015 }
1016 DocumentChild::TableOfContents(toc) => {
1017 for child in &toc.before_contents {
1019 if let TocContent::Paragraph(paragraph) = child {
1020 for child in ¶graph.children {
1021 if let ParagraphChild::CommentStart(c) = child {
1022 push_comment_and_comment_extended(
1023 &mut comments,
1024 &mut comments_extended,
1025 &comment_map,
1026 c,
1027 );
1028 }
1029 if let ParagraphChild::Hyperlink(h) = child {
1030 if let HyperlinkData::External { rid, path } = &h.link {
1031 hyperlink_map.insert(rid.clone(), path.clone());
1032 };
1033 for child in &h.children {
1034 if let ParagraphChild::CommentStart(c) = child {
1035 push_comment_and_comment_extended(
1036 &mut comments,
1037 &mut comments_extended,
1038 &comment_map,
1039 c,
1040 );
1041 }
1042 }
1043 }
1044 }
1045 }
1046 if let TocContent::Table(table) = child {
1047 collect_dependencies_in_table(
1048 table,
1049 &mut comments,
1050 &mut comments_extended,
1051 &mut comment_map,
1052 &mut hyperlink_map,
1053 );
1054 }
1055 }
1056 for child in &toc.after_contents {
1057 if let TocContent::Paragraph(paragraph) = child {
1058 for child in ¶graph.children {
1059 if let ParagraphChild::CommentStart(c) = child {
1060 push_comment_and_comment_extended(
1061 &mut comments,
1062 &mut comments_extended,
1063 &comment_map,
1064 c,
1065 );
1066 }
1067 if let ParagraphChild::Hyperlink(h) = child {
1068 if let HyperlinkData::External { rid, path } = &h.link {
1069 hyperlink_map.insert(rid.clone(), path.clone());
1070 };
1071 for child in &h.children {
1072 if let ParagraphChild::CommentStart(c) = child {
1073 push_comment_and_comment_extended(
1074 &mut comments,
1075 &mut comments_extended,
1076 &comment_map,
1077 c,
1078 );
1079 }
1080 }
1081 }
1082 }
1083 }
1084 if let TocContent::Table(table) = child {
1085 collect_dependencies_in_table(
1086 table,
1087 &mut comments,
1088 &mut comments_extended,
1089 &mut comment_map,
1090 &mut hyperlink_map,
1091 );
1092 }
1093 }
1094 }
1095 _ => {}
1096 }
1097 }
1098 if !comments.is_empty() {
1101 self.document_rels.has_comments = true;
1102 }
1103
1104 self.comments_extended
1105 .add_comments_extended(comments_extended);
1106
1107 self.comments.add_comments(comments);
1108
1109 for (id, d) in hyperlink_map {
1110 self.document_rels
1111 .hyperlinks
1112 .push((id, d, "External".to_string())); }
1114 }
1115
1116 pub(crate) fn store_comments(&mut self, comments: &[Comment]) {
1119 for child in &mut self.document.children {
1120 match child {
1121 DocumentChild::Paragraph(paragraph) => {
1122 for child in &mut paragraph.children {
1123 if let ParagraphChild::CommentStart(ref mut c) = child {
1124 let comment_id = c.get_id();
1125 if let Some(comment) = comments.iter().find(|c| c.id() == comment_id) {
1126 let comment = comment.clone();
1127 c.as_mut().comment(comment);
1128 }
1129 }
1130 if let ParagraphChild::Insert(ref mut insert) = child {
1131 for child in &mut insert.children {
1132 if let InsertChild::CommentStart(ref mut c) = child {
1133 let comment_id = c.get_id();
1134 if let Some(comment) =
1135 comments.iter().find(|c| c.id() == comment_id)
1136 {
1137 let comment = comment.clone();
1138 c.as_mut().comment(comment);
1139 }
1140 } else if let InsertChild::Delete(ref mut d) = child {
1141 for child in &mut d.children {
1142 if let DeleteChild::CommentStart(ref mut c) = child {
1143 let comment_id = c.get_id();
1144 if let Some(comment) =
1145 comments.iter().find(|c| c.id() == comment_id)
1146 {
1147 let comment = comment.clone();
1148 c.as_mut().comment(comment);
1149 }
1150 }
1151 }
1152 }
1153 }
1154 }
1155 if let ParagraphChild::Delete(ref mut delete) = child {
1156 for child in &mut delete.children {
1157 if let DeleteChild::CommentStart(ref mut c) = child {
1158 let comment_id = c.get_id();
1159 if let Some(comment) =
1160 comments.iter().find(|c| c.id() == comment_id)
1161 {
1162 let comment = comment.clone();
1163 c.as_mut().comment(comment);
1164 }
1165 }
1166 }
1167 }
1168 }
1169 }
1170 DocumentChild::Table(table) => store_comments_in_table(table, comments),
1171 _ => {}
1172 }
1173 }
1174
1175 if !comments.is_empty() {
1176 self.document_rels.has_comments = true;
1177 }
1178 }
1179
1180 fn images_in_doc(&mut self) -> (Vec<ImageIdAndPath>, Vec<ImageIdAndBuf>) {
1182 let mut images: Vec<(String, String)> = vec![];
1183 let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
1184
1185 for child in &mut self.document.children {
1186 match child {
1187 DocumentChild::Paragraph(paragraph) => {
1188 collect_images_from_paragraph(paragraph, &mut images, &mut image_bufs, None);
1189 }
1190 DocumentChild::Table(table) => {
1191 collect_images_from_table(table, &mut images, &mut image_bufs, None);
1192 }
1193 _ => {}
1194 }
1195 }
1196 (images, image_bufs)
1197 }
1198
1199 fn images_in_header(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
1200 let mut header_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
1201 let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
1202
1203 if let Some((_, header)) = &mut self.document.section_property.header.as_mut() {
1204 let mut images: Vec<ImageIdAndPath> = vec![];
1205 for child in header.children.iter_mut() {
1206 match child {
1207 HeaderChild::Paragraph(paragraph) => {
1208 collect_images_from_paragraph(
1209 paragraph,
1210 &mut images,
1211 &mut image_bufs,
1212 Some("header"),
1213 );
1214 }
1215 HeaderChild::Table(table) => {
1216 collect_images_from_table(
1217 table,
1218 &mut images,
1219 &mut image_bufs,
1220 Some("header"),
1221 );
1222 }
1223 HeaderChild::StructuredDataTag(tag) => {
1224 for child in tag.children.iter_mut() {
1225 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1226 collect_images_from_paragraph(
1227 paragraph,
1228 &mut images,
1229 &mut image_bufs,
1230 Some("header"),
1231 );
1232 }
1233 if let StructuredDataTagChild::Table(table) = child {
1234 collect_images_from_table(
1235 table,
1236 &mut images,
1237 &mut image_bufs,
1238 Some("header"),
1239 );
1240 }
1241 }
1242 }
1243 }
1244 }
1245 header_images[0] = images;
1246 }
1247
1248 if let Some((_, header)) = &mut self.document.section_property.first_header.as_mut() {
1249 let mut images: Vec<ImageIdAndPath> = vec![];
1250 for child in header.children.iter_mut() {
1251 match child {
1252 HeaderChild::Paragraph(paragraph) => {
1253 collect_images_from_paragraph(
1254 paragraph,
1255 &mut images,
1256 &mut image_bufs,
1257 Some("header"),
1258 );
1259 }
1260 HeaderChild::Table(table) => {
1261 collect_images_from_table(
1262 table,
1263 &mut images,
1264 &mut image_bufs,
1265 Some("header"),
1266 );
1267 }
1268 HeaderChild::StructuredDataTag(tag) => {
1269 for child in tag.children.iter_mut() {
1270 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1271 collect_images_from_paragraph(
1272 paragraph,
1273 &mut images,
1274 &mut image_bufs,
1275 Some("header"),
1276 );
1277 }
1278 if let StructuredDataTagChild::Table(table) = child {
1279 collect_images_from_table(
1280 table,
1281 &mut images,
1282 &mut image_bufs,
1283 Some("header"),
1284 );
1285 }
1286 }
1287 }
1288 }
1289 }
1290 header_images[1] = images;
1291 }
1292
1293 if let Some((_, header)) = &mut self.document.section_property.even_header.as_mut() {
1294 let mut images: Vec<ImageIdAndPath> = vec![];
1295 for child in header.children.iter_mut() {
1296 match child {
1297 HeaderChild::Paragraph(paragraph) => {
1298 collect_images_from_paragraph(
1299 paragraph,
1300 &mut images,
1301 &mut image_bufs,
1302 Some("header"),
1303 );
1304 }
1305 HeaderChild::Table(table) => {
1306 collect_images_from_table(
1307 table,
1308 &mut images,
1309 &mut image_bufs,
1310 Some("header"),
1311 );
1312 }
1313 HeaderChild::StructuredDataTag(tag) => {
1314 for child in tag.children.iter_mut() {
1315 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1316 collect_images_from_paragraph(
1317 paragraph,
1318 &mut images,
1319 &mut image_bufs,
1320 Some("header"),
1321 );
1322 }
1323 if let StructuredDataTagChild::Table(table) = child {
1324 collect_images_from_table(
1325 table,
1326 &mut images,
1327 &mut image_bufs,
1328 Some("header"),
1329 );
1330 }
1331 }
1332 }
1333 }
1334 }
1335 header_images[2] = images;
1336 }
1337 (header_images, image_bufs)
1338 }
1339
1340 fn images_in_footer(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
1342 let mut footer_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
1343 let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
1344
1345 if let Some((_, footer)) = &mut self.document.section_property.footer.as_mut() {
1346 let mut images: Vec<ImageIdAndPath> = vec![];
1347 for child in footer.children.iter_mut() {
1348 match child {
1349 FooterChild::Paragraph(paragraph) => {
1350 collect_images_from_paragraph(
1351 paragraph,
1352 &mut images,
1353 &mut image_bufs,
1354 Some("footer"),
1355 );
1356 }
1357 FooterChild::Table(table) => {
1358 collect_images_from_table(
1359 table,
1360 &mut images,
1361 &mut image_bufs,
1362 Some("footer"),
1363 );
1364 }
1365 FooterChild::StructuredDataTag(tag) => {
1366 for child in tag.children.iter_mut() {
1367 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1368 collect_images_from_paragraph(
1369 paragraph,
1370 &mut images,
1371 &mut image_bufs,
1372 Some("header"),
1373 );
1374 }
1375 if let StructuredDataTagChild::Table(table) = child {
1376 collect_images_from_table(
1377 table,
1378 &mut images,
1379 &mut image_bufs,
1380 Some("header"),
1381 );
1382 }
1383 }
1384 }
1385 }
1386 }
1387 footer_images[0] = images;
1388 }
1389
1390 if let Some((_, footer)) = &mut self.document.section_property.first_footer.as_mut() {
1391 let mut images: Vec<ImageIdAndPath> = vec![];
1392 for child in footer.children.iter_mut() {
1393 match child {
1394 FooterChild::Paragraph(paragraph) => {
1395 collect_images_from_paragraph(
1396 paragraph,
1397 &mut images,
1398 &mut image_bufs,
1399 Some("footer"),
1400 );
1401 }
1402 FooterChild::Table(table) => {
1403 collect_images_from_table(
1404 table,
1405 &mut images,
1406 &mut image_bufs,
1407 Some("footer"),
1408 );
1409 }
1410 FooterChild::StructuredDataTag(tag) => {
1411 for child in tag.children.iter_mut() {
1412 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1413 collect_images_from_paragraph(
1414 paragraph,
1415 &mut images,
1416 &mut image_bufs,
1417 Some("header"),
1418 );
1419 }
1420 if let StructuredDataTagChild::Table(table) = child {
1421 collect_images_from_table(
1422 table,
1423 &mut images,
1424 &mut image_bufs,
1425 Some("header"),
1426 );
1427 }
1428 }
1429 }
1430 }
1431 }
1432 footer_images[1] = images;
1433 }
1434
1435 if let Some((_, footer)) = &mut self.document.section_property.even_footer.as_mut() {
1436 let mut images: Vec<ImageIdAndPath> = vec![];
1437 for child in footer.children.iter_mut() {
1438 match child {
1439 FooterChild::Paragraph(paragraph) => {
1440 collect_images_from_paragraph(
1441 paragraph,
1442 &mut images,
1443 &mut image_bufs,
1444 Some("footer"),
1445 );
1446 }
1447 FooterChild::Table(table) => {
1448 collect_images_from_table(
1449 table,
1450 &mut images,
1451 &mut image_bufs,
1452 Some("footer"),
1453 );
1454 }
1455 FooterChild::StructuredDataTag(tag) => {
1456 for child in tag.children.iter_mut() {
1457 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1458 collect_images_from_paragraph(
1459 paragraph,
1460 &mut images,
1461 &mut image_bufs,
1462 Some("header"),
1463 );
1464 }
1465 if let StructuredDataTagChild::Table(table) = child {
1466 collect_images_from_table(
1467 table,
1468 &mut images,
1469 &mut image_bufs,
1470 Some("header"),
1471 );
1472 }
1473 }
1474 }
1475 }
1476 }
1477 footer_images[2] = images;
1478 }
1479 (footer_images, image_bufs)
1480 }
1481
1482 pub fn collect_footnotes(&mut self) -> bool {
1484 let footnotes: Vec<Footnote> = self
1485 .document
1486 .children
1487 .iter()
1488 .filter_map(|child| match child {
1489 DocumentChild::Paragraph(paragraph) => Some(¶graph.children),
1490 _ => None,
1491 })
1492 .flat_map(|children| children.iter())
1493 .filter_map(|para_child| match para_child {
1494 ParagraphChild::Run(run) => Some(&run.children),
1495 _ => None,
1496 })
1497 .flat_map(|children| children.iter())
1498 .filter_map(|run_child| match run_child {
1499 RunChild::FootnoteReference(footnote_ref) => Some(footnote_ref),
1500 _ => None,
1501 })
1502 .map(Into::<Footnote>::into)
1503 .collect();
1504 let is_footnotes = !footnotes.is_empty();
1505 self.footnotes.add(footnotes);
1506 is_footnotes
1507 }
1508}
1509
1510fn collect_dependencies_in_paragraph(
1511 paragraph: &Paragraph,
1512 comments: &mut Vec<Comment>,
1513 comments_extended: &mut Vec<CommentExtended>,
1514 comment_map: &mut HashMap<usize, String>,
1515 hyperlink_map: &mut HashMap<String, String>,
1516) {
1517 for child in ¶graph.children {
1518 if let ParagraphChild::CommentStart(c) = child {
1519 push_comment_and_comment_extended(comments, comments_extended, comment_map, c);
1520 }
1521 if let ParagraphChild::Hyperlink(h) = child {
1522 if let HyperlinkData::External { rid, path } = &h.link {
1523 hyperlink_map.insert(rid.clone(), path.clone());
1524 };
1525 for child in &h.children {
1526 if let ParagraphChild::CommentStart(c) = child {
1527 push_comment_and_comment_extended(comments, comments_extended, comment_map, c);
1528 }
1529 }
1530 }
1531 }
1532}
1533
1534fn collect_comment_map_in_paragraph(
1535 paragraph: &Paragraph,
1536 comment_map: &mut HashMap<usize, String>,
1537) {
1538 for child in ¶graph.children {
1539 if let ParagraphChild::CommentStart(c) = child {
1540 let comment = c.get_comment_ref();
1541 let comment_id = comment.id();
1542 for child in &comment.children {
1543 if let CommentChild::Paragraph(child) = child {
1544 comment_map.insert(comment_id, child.id.clone());
1545 }
1546 }
1547 }
1548 if let ParagraphChild::Hyperlink(h) = child {
1549 for child in &h.children {
1550 if let ParagraphChild::CommentStart(c) = child {
1551 let comment = c.get_comment_ref();
1552 let comment_id = comment.id();
1553 for child in &comment.children {
1554 if let CommentChild::Paragraph(child) = child {
1555 comment_map.insert(comment_id, child.id.clone());
1556 }
1557 }
1558 }
1559 }
1560 }
1561 }
1562}
1563
1564fn collect_comment_map_in_table(table: &Table, comment_map: &mut HashMap<usize, String>) {
1565 for TableChild::TableRow(row) in &table.rows {
1566 for TableRowChild::TableCell(cell) in &row.cells {
1567 for content in &cell.children {
1568 match content {
1569 TableCellContent::Paragraph(paragraph) => {
1570 collect_comment_map_in_paragraph(paragraph, comment_map);
1571 }
1572 TableCellContent::Table(table) => {
1573 collect_comment_map_in_table(table, comment_map)
1574 }
1575 TableCellContent::StructuredDataTag(tag) => {
1576 for child in &tag.children {
1577 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1578 collect_comment_map_in_paragraph(paragraph, comment_map);
1579 }
1580 if let StructuredDataTagChild::Table(table) = child {
1581 collect_comment_map_in_table(table, comment_map);
1582 }
1583 }
1584 }
1585 TableCellContent::TableOfContents(t) => {
1586 for child in &t.before_contents {
1587 if let TocContent::Paragraph(paragraph) = child {
1588 collect_comment_map_in_paragraph(paragraph, comment_map);
1589 }
1590 if let TocContent::Table(table) = child {
1591 collect_comment_map_in_table(table, comment_map);
1592 }
1593 }
1594 for child in &t.after_contents {
1595 if let TocContent::Paragraph(paragraph) = child {
1596 collect_comment_map_in_paragraph(paragraph, comment_map);
1597 }
1598 if let TocContent::Table(table) = child {
1599 collect_comment_map_in_table(table, comment_map);
1600 }
1601 }
1602 }
1603 }
1604 }
1605 }
1606 }
1607}
1608
1609fn collect_dependencies_in_table(
1610 table: &Table,
1611 comments: &mut Vec<Comment>,
1612 comments_extended: &mut Vec<CommentExtended>,
1613 comment_map: &mut HashMap<usize, String>,
1614 hyperlink_map: &mut HashMap<String, String>,
1615) {
1616 for TableChild::TableRow(row) in &table.rows {
1617 for TableRowChild::TableCell(cell) in &row.cells {
1618 for content in &cell.children {
1619 match content {
1620 TableCellContent::Paragraph(paragraph) => {
1621 collect_dependencies_in_paragraph(
1622 paragraph,
1623 comments,
1624 comments_extended,
1625 comment_map,
1626 hyperlink_map,
1627 );
1628 }
1629 TableCellContent::Table(table) => collect_dependencies_in_table(
1630 table,
1631 comments,
1632 comments_extended,
1633 comment_map,
1634 hyperlink_map,
1635 ),
1636 TableCellContent::StructuredDataTag(tag) => {
1637 for child in &tag.children {
1638 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1639 collect_dependencies_in_paragraph(
1640 paragraph,
1641 comments,
1642 comments_extended,
1643 comment_map,
1644 hyperlink_map,
1645 );
1646 }
1647 if let StructuredDataTagChild::Table(table) = child {
1648 collect_dependencies_in_table(
1649 table,
1650 comments,
1651 comments_extended,
1652 comment_map,
1653 hyperlink_map,
1654 );
1655 }
1656 }
1657 }
1658 TableCellContent::TableOfContents(t) => {
1659 for child in &t.before_contents {
1660 if let TocContent::Paragraph(paragraph) = child {
1661 collect_dependencies_in_paragraph(
1662 paragraph,
1663 comments,
1664 comments_extended,
1665 comment_map,
1666 hyperlink_map,
1667 );
1668 }
1669 if let TocContent::Table(table) = child {
1670 collect_dependencies_in_table(
1671 table,
1672 comments,
1673 comments_extended,
1674 comment_map,
1675 hyperlink_map,
1676 );
1677 }
1678 }
1679
1680 for child in &t.after_contents {
1681 if let TocContent::Paragraph(paragraph) = child {
1682 collect_dependencies_in_paragraph(
1683 paragraph,
1684 comments,
1685 comments_extended,
1686 comment_map,
1687 hyperlink_map,
1688 );
1689 }
1690 if let TocContent::Table(table) = child {
1691 collect_dependencies_in_table(
1692 table,
1693 comments,
1694 comments_extended,
1695 comment_map,
1696 hyperlink_map,
1697 );
1698 }
1699 }
1700 }
1701 }
1702 }
1703 }
1704 }
1705}
1706
1707fn store_comments_in_paragraph(paragraph: &mut Paragraph, comments: &[Comment]) {
1708 for child in &mut paragraph.children {
1709 if let ParagraphChild::CommentStart(ref mut c) = child {
1710 let comment_id = c.get_id();
1711 if let Some(comment) = comments.iter().find(|c| c.id() == comment_id) {
1712 let comment = comment.clone();
1713 c.as_mut().comment(comment);
1714 }
1715 }
1716 if let ParagraphChild::Insert(ref mut insert) = child {
1717 for child in &mut insert.children {
1718 if let InsertChild::CommentStart(ref mut c) = child {
1719 let comment_id = c.get_id();
1720 if let Some(comment) = comments.iter().find(|c| c.id() == comment_id) {
1721 let comment = comment.clone();
1722 c.as_mut().comment(comment);
1723 }
1724 }
1725 }
1726 }
1727 if let ParagraphChild::Delete(ref mut delete) = child {
1728 for child in &mut delete.children {
1729 if let DeleteChild::CommentStart(ref mut c) = child {
1730 let comment_id = c.get_id();
1731 if let Some(comment) = comments.iter().find(|c| c.id() == comment_id) {
1732 let comment = comment.clone();
1733 c.as_mut().comment(comment);
1734 }
1735 }
1736 }
1737 }
1738 }
1739}
1740
1741fn store_comments_in_table(table: &mut Table, comments: &[Comment]) {
1742 for TableChild::TableRow(row) in &mut table.rows {
1743 for TableRowChild::TableCell(cell) in &mut row.cells {
1744 for content in &mut cell.children {
1745 match content {
1746 TableCellContent::Paragraph(paragraph) => {
1747 store_comments_in_paragraph(paragraph, comments)
1748 }
1749 TableCellContent::Table(ref mut table) => {
1750 store_comments_in_table(table, comments);
1751 }
1752 TableCellContent::StructuredDataTag(ref mut tag) => {
1753 for child in &mut tag.children {
1754 if let StructuredDataTagChild::Paragraph(paragraph) = child {
1755 store_comments_in_paragraph(paragraph, comments);
1756 }
1757 if let StructuredDataTagChild::Table(table) = child {
1758 store_comments_in_table(table, comments);
1759 }
1760 }
1761 }
1762 TableCellContent::TableOfContents(ref mut t) => {
1763 for child in &mut t.before_contents {
1764 if let TocContent::Paragraph(paragraph) = child {
1765 store_comments_in_paragraph(paragraph, comments);
1766 }
1767 if let TocContent::Table(table) = child {
1768 store_comments_in_table(table, comments);
1769 }
1770 }
1771
1772 for child in &mut t.after_contents {
1773 if let TocContent::Paragraph(paragraph) = child {
1774 store_comments_in_paragraph(paragraph, comments);
1775 }
1776 if let TocContent::Table(table) = child {
1777 store_comments_in_table(table, comments);
1778 }
1779 }
1780 }
1781 }
1782 }
1783 }
1784 }
1785}
1786
1787fn collect_para_ids_in_docx(docx: &Docx, counts: &mut HashMap<String, usize>) {
1788 for child in &docx.document.children {
1789 collect_para_ids_in_document_child(child, counts);
1790 }
1791 collect_para_ids_in_section_property(&docx.document.section_property, counts);
1792
1793 for comment in &docx.comments.comments {
1794 collect_para_ids_in_comment(comment, counts);
1795 }
1796
1797 for footnote in &docx.footnotes.footnotes {
1798 for paragraph in &footnote.content {
1799 collect_para_ids_in_paragraph(paragraph, counts);
1800 }
1801 }
1802}
1803
1804fn collect_para_ids_in_document_child(child: &DocumentChild, counts: &mut HashMap<String, usize>) {
1805 match child {
1806 DocumentChild::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1807 DocumentChild::Table(table) => collect_para_ids_in_table(table, counts),
1808 DocumentChild::StructuredDataTag(tag) => {
1809 collect_para_ids_in_structured_data_tag(tag, counts)
1810 }
1811 DocumentChild::TableOfContents(toc) => collect_para_ids_in_toc(toc, counts),
1812 DocumentChild::Section(section) => collect_para_ids_in_section(section, counts),
1813 _ => {}
1814 }
1815}
1816
1817fn collect_para_ids_in_section(section: &Section, counts: &mut HashMap<String, usize>) {
1818 for child in §ion.children {
1819 match child {
1820 SectionChild::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1821 SectionChild::Table(table) => collect_para_ids_in_table(table, counts),
1822 SectionChild::StructuredDataTag(tag) => {
1823 collect_para_ids_in_structured_data_tag(tag, counts)
1824 }
1825 SectionChild::TableOfContents(toc) => collect_para_ids_in_toc(toc, counts),
1826 _ => {}
1827 }
1828 }
1829 collect_para_ids_in_section_property(§ion.property, counts);
1830}
1831
1832fn collect_para_ids_in_section_property(
1833 property: &SectionProperty,
1834 counts: &mut HashMap<String, usize>,
1835) {
1836 if let Some((_, header)) = property.header.as_ref() {
1837 collect_para_ids_in_header(header, counts);
1838 }
1839 if let Some((_, header)) = property.first_header.as_ref() {
1840 collect_para_ids_in_header(header, counts);
1841 }
1842 if let Some((_, header)) = property.even_header.as_ref() {
1843 collect_para_ids_in_header(header, counts);
1844 }
1845 if let Some((_, footer)) = property.footer.as_ref() {
1846 collect_para_ids_in_footer(footer, counts);
1847 }
1848 if let Some((_, footer)) = property.first_footer.as_ref() {
1849 collect_para_ids_in_footer(footer, counts);
1850 }
1851 if let Some((_, footer)) = property.even_footer.as_ref() {
1852 collect_para_ids_in_footer(footer, counts);
1853 }
1854}
1855
1856fn collect_para_ids_in_header(header: &Header, counts: &mut HashMap<String, usize>) {
1857 for child in &header.children {
1858 match child {
1859 HeaderChild::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1860 HeaderChild::Table(table) => collect_para_ids_in_table(table, counts),
1861 HeaderChild::StructuredDataTag(tag) => {
1862 collect_para_ids_in_structured_data_tag(tag, counts)
1863 }
1864 }
1865 }
1866}
1867
1868fn collect_para_ids_in_footer(footer: &Footer, counts: &mut HashMap<String, usize>) {
1869 for child in &footer.children {
1870 match child {
1871 FooterChild::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1872 FooterChild::Table(table) => collect_para_ids_in_table(table, counts),
1873 FooterChild::StructuredDataTag(tag) => {
1874 collect_para_ids_in_structured_data_tag(tag, counts)
1875 }
1876 }
1877 }
1878}
1879
1880fn collect_para_ids_in_toc(toc: &TableOfContents, counts: &mut HashMap<String, usize>) {
1881 for child in &toc.before_contents {
1882 match child {
1883 TocContent::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1884 TocContent::Table(table) => collect_para_ids_in_table(table, counts),
1885 }
1886 }
1887 for child in &toc.after_contents {
1888 match child {
1889 TocContent::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1890 TocContent::Table(table) => collect_para_ids_in_table(table, counts),
1891 }
1892 }
1893}
1894
1895fn collect_para_ids_in_table(table: &Table, counts: &mut HashMap<String, usize>) {
1896 for TableChild::TableRow(row) in &table.rows {
1897 for TableRowChild::TableCell(cell) in &row.cells {
1898 for content in &cell.children {
1899 match content {
1900 TableCellContent::Paragraph(paragraph) => {
1901 collect_para_ids_in_paragraph(paragraph, counts)
1902 }
1903 TableCellContent::Table(table) => collect_para_ids_in_table(table, counts),
1904 TableCellContent::StructuredDataTag(tag) => {
1905 collect_para_ids_in_structured_data_tag(tag, counts)
1906 }
1907 TableCellContent::TableOfContents(toc) => collect_para_ids_in_toc(toc, counts),
1908 }
1909 }
1910 }
1911 }
1912}
1913
1914fn collect_para_ids_in_paragraph(paragraph: &Paragraph, counts: &mut HashMap<String, usize>) {
1915 *counts.entry(paragraph.id.clone()).or_insert(0) += 1;
1916
1917 for child in ¶graph.children {
1918 match child {
1919 ParagraphChild::CommentStart(c) => collect_para_ids_in_comment(&c.comment, counts),
1920 ParagraphChild::Insert(insert) => collect_para_ids_in_insert(insert, counts),
1921 ParagraphChild::Delete(delete) => collect_para_ids_in_delete(delete, counts),
1922 ParagraphChild::Hyperlink(hyperlink) => {
1923 collect_para_ids_in_hyperlink(hyperlink, counts)
1924 }
1925 ParagraphChild::StructuredDataTag(tag) => {
1926 collect_para_ids_in_structured_data_tag(tag, counts)
1927 }
1928 _ => {}
1929 }
1930 }
1931}
1932
1933fn collect_para_ids_in_hyperlink(hyperlink: &Hyperlink, counts: &mut HashMap<String, usize>) {
1934 for child in &hyperlink.children {
1935 match child {
1936 ParagraphChild::CommentStart(c) => collect_para_ids_in_comment(&c.comment, counts),
1937 ParagraphChild::Insert(insert) => collect_para_ids_in_insert(insert, counts),
1938 ParagraphChild::Delete(delete) => collect_para_ids_in_delete(delete, counts),
1939 ParagraphChild::StructuredDataTag(tag) => {
1940 collect_para_ids_in_structured_data_tag(tag, counts)
1941 }
1942 _ => {}
1943 }
1944 }
1945}
1946
1947fn collect_para_ids_in_insert(insert: &Insert, counts: &mut HashMap<String, usize>) {
1948 for child in &insert.children {
1949 match child {
1950 InsertChild::CommentStart(c) => collect_para_ids_in_comment(&c.comment, counts),
1951 InsertChild::Delete(delete) => collect_para_ids_in_delete(delete, counts),
1952 _ => {}
1953 }
1954 }
1955}
1956
1957fn collect_para_ids_in_delete(delete: &Delete, counts: &mut HashMap<String, usize>) {
1958 for child in &delete.children {
1959 if let DeleteChild::CommentStart(c) = child {
1960 collect_para_ids_in_comment(&c.comment, counts);
1961 }
1962 }
1963}
1964
1965fn collect_para_ids_in_structured_data_tag(
1966 tag: &StructuredDataTag,
1967 counts: &mut HashMap<String, usize>,
1968) {
1969 for child in &tag.children {
1970 match child {
1971 StructuredDataTagChild::Paragraph(paragraph) => {
1972 collect_para_ids_in_paragraph(paragraph, counts)
1973 }
1974 StructuredDataTagChild::Table(table) => collect_para_ids_in_table(table, counts),
1975 StructuredDataTagChild::CommentStart(c) => {
1976 collect_para_ids_in_comment(&c.comment, counts)
1977 }
1978 StructuredDataTagChild::StructuredDataTag(inner) => {
1979 collect_para_ids_in_structured_data_tag(inner, counts)
1980 }
1981 _ => {}
1982 }
1983 }
1984}
1985
1986fn collect_para_ids_in_comment(comment: &Comment, counts: &mut HashMap<String, usize>) {
1987 for child in &comment.children {
1988 match child {
1989 CommentChild::Paragraph(paragraph) => collect_para_ids_in_paragraph(paragraph, counts),
1990 CommentChild::Table(table) => collect_para_ids_in_table(table, counts),
1991 }
1992 }
1993}
1994
1995fn refresh_para_ids_in_docx(
1996 docx: &mut Docx,
1997 counts: &HashMap<String, usize>,
1998 used: &mut HashSet<String>,
1999 seen: &mut HashSet<String>,
2000) {
2001 for child in &mut docx.document.children {
2002 refresh_para_ids_in_document_child(child, counts, used, seen);
2003 }
2004 refresh_para_ids_in_section_property(&mut docx.document.section_property, counts, used, seen);
2005
2006 for comment in &mut docx.comments.comments {
2007 refresh_para_ids_in_comment(comment, counts, used, seen);
2008 }
2009
2010 for footnote in &mut docx.footnotes.footnotes {
2011 for paragraph in &mut footnote.content {
2012 refresh_para_ids_in_paragraph(paragraph, counts, used, seen);
2013 }
2014 }
2015}
2016
2017fn refresh_para_ids_in_document_child(
2018 child: &mut DocumentChild,
2019 counts: &HashMap<String, usize>,
2020 used: &mut HashSet<String>,
2021 seen: &mut HashSet<String>,
2022) {
2023 match child {
2024 DocumentChild::Paragraph(paragraph) => {
2025 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2026 }
2027 DocumentChild::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2028 DocumentChild::StructuredDataTag(tag) => {
2029 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2030 }
2031 DocumentChild::TableOfContents(toc) => refresh_para_ids_in_toc(toc, counts, used, seen),
2032 DocumentChild::Section(section) => refresh_para_ids_in_section(section, counts, used, seen),
2033 _ => {}
2034 }
2035}
2036
2037fn refresh_para_ids_in_section(
2038 section: &mut Section,
2039 counts: &HashMap<String, usize>,
2040 used: &mut HashSet<String>,
2041 seen: &mut HashSet<String>,
2042) {
2043 for child in &mut section.children {
2044 match child {
2045 SectionChild::Paragraph(paragraph) => {
2046 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2047 }
2048 SectionChild::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2049 SectionChild::StructuredDataTag(tag) => {
2050 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2051 }
2052 SectionChild::TableOfContents(toc) => refresh_para_ids_in_toc(toc, counts, used, seen),
2053 _ => {}
2054 }
2055 }
2056 refresh_para_ids_in_section_property(&mut section.property, counts, used, seen);
2057}
2058
2059fn refresh_para_ids_in_section_property(
2060 property: &mut SectionProperty,
2061 counts: &HashMap<String, usize>,
2062 used: &mut HashSet<String>,
2063 seen: &mut HashSet<String>,
2064) {
2065 if let Some((_, header)) = property.header.as_mut() {
2066 refresh_para_ids_in_header(header, counts, used, seen);
2067 }
2068 if let Some((_, header)) = property.first_header.as_mut() {
2069 refresh_para_ids_in_header(header, counts, used, seen);
2070 }
2071 if let Some((_, header)) = property.even_header.as_mut() {
2072 refresh_para_ids_in_header(header, counts, used, seen);
2073 }
2074 if let Some((_, footer)) = property.footer.as_mut() {
2075 refresh_para_ids_in_footer(footer, counts, used, seen);
2076 }
2077 if let Some((_, footer)) = property.first_footer.as_mut() {
2078 refresh_para_ids_in_footer(footer, counts, used, seen);
2079 }
2080 if let Some((_, footer)) = property.even_footer.as_mut() {
2081 refresh_para_ids_in_footer(footer, counts, used, seen);
2082 }
2083}
2084
2085fn refresh_para_ids_in_header(
2086 header: &mut Header,
2087 counts: &HashMap<String, usize>,
2088 used: &mut HashSet<String>,
2089 seen: &mut HashSet<String>,
2090) {
2091 for child in &mut header.children {
2092 match child {
2093 HeaderChild::Paragraph(paragraph) => {
2094 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2095 }
2096 HeaderChild::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2097 HeaderChild::StructuredDataTag(tag) => {
2098 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2099 }
2100 }
2101 }
2102}
2103
2104fn refresh_para_ids_in_footer(
2105 footer: &mut Footer,
2106 counts: &HashMap<String, usize>,
2107 used: &mut HashSet<String>,
2108 seen: &mut HashSet<String>,
2109) {
2110 for child in &mut footer.children {
2111 match child {
2112 FooterChild::Paragraph(paragraph) => {
2113 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2114 }
2115 FooterChild::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2116 FooterChild::StructuredDataTag(tag) => {
2117 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2118 }
2119 }
2120 }
2121}
2122
2123fn refresh_para_ids_in_toc(
2124 toc: &mut TableOfContents,
2125 counts: &HashMap<String, usize>,
2126 used: &mut HashSet<String>,
2127 seen: &mut HashSet<String>,
2128) {
2129 for child in &mut toc.before_contents {
2130 match child {
2131 TocContent::Paragraph(paragraph) => {
2132 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2133 }
2134 TocContent::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2135 }
2136 }
2137 for child in &mut toc.after_contents {
2138 match child {
2139 TocContent::Paragraph(paragraph) => {
2140 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2141 }
2142 TocContent::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2143 }
2144 }
2145}
2146
2147fn refresh_para_ids_in_table(
2148 table: &mut Table,
2149 counts: &HashMap<String, usize>,
2150 used: &mut HashSet<String>,
2151 seen: &mut HashSet<String>,
2152) {
2153 for TableChild::TableRow(row) in &mut table.rows {
2154 for TableRowChild::TableCell(cell) in &mut row.cells {
2155 for content in &mut cell.children {
2156 match content {
2157 TableCellContent::Paragraph(paragraph) => {
2158 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2159 }
2160 TableCellContent::Table(table) => {
2161 refresh_para_ids_in_table(table, counts, used, seen)
2162 }
2163 TableCellContent::StructuredDataTag(tag) => {
2164 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2165 }
2166 TableCellContent::TableOfContents(toc) => {
2167 refresh_para_ids_in_toc(toc, counts, used, seen)
2168 }
2169 }
2170 }
2171 }
2172 }
2173}
2174
2175fn refresh_para_ids_in_paragraph(
2176 paragraph: &mut Paragraph,
2177 counts: &HashMap<String, usize>,
2178 used: &mut HashSet<String>,
2179 seen: &mut HashSet<String>,
2180) {
2181 ensure_unique_paragraph_id(paragraph, counts, used, seen);
2182
2183 for child in &mut paragraph.children {
2184 match child {
2185 ParagraphChild::CommentStart(c) => {
2186 refresh_para_ids_in_comment(&mut c.comment, counts, used, seen)
2187 }
2188 ParagraphChild::Insert(insert) => {
2189 refresh_para_ids_in_insert(insert, counts, used, seen)
2190 }
2191 ParagraphChild::Delete(delete) => {
2192 refresh_para_ids_in_delete(delete, counts, used, seen)
2193 }
2194 ParagraphChild::Hyperlink(hyperlink) => {
2195 refresh_para_ids_in_hyperlink(hyperlink, counts, used, seen)
2196 }
2197 ParagraphChild::StructuredDataTag(tag) => {
2198 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2199 }
2200 _ => {}
2201 }
2202 }
2203}
2204
2205fn refresh_para_ids_in_hyperlink(
2206 hyperlink: &mut Hyperlink,
2207 counts: &HashMap<String, usize>,
2208 used: &mut HashSet<String>,
2209 seen: &mut HashSet<String>,
2210) {
2211 for child in &mut hyperlink.children {
2212 match child {
2213 ParagraphChild::CommentStart(c) => {
2214 refresh_para_ids_in_comment(&mut c.comment, counts, used, seen)
2215 }
2216 ParagraphChild::Insert(insert) => {
2217 refresh_para_ids_in_insert(insert, counts, used, seen)
2218 }
2219 ParagraphChild::Delete(delete) => {
2220 refresh_para_ids_in_delete(delete, counts, used, seen)
2221 }
2222 ParagraphChild::StructuredDataTag(tag) => {
2223 refresh_para_ids_in_structured_data_tag(tag, counts, used, seen)
2224 }
2225 _ => {}
2226 }
2227 }
2228}
2229
2230fn refresh_para_ids_in_insert(
2231 insert: &mut Insert,
2232 counts: &HashMap<String, usize>,
2233 used: &mut HashSet<String>,
2234 seen: &mut HashSet<String>,
2235) {
2236 for child in &mut insert.children {
2237 match child {
2238 InsertChild::CommentStart(c) => {
2239 refresh_para_ids_in_comment(&mut c.comment, counts, used, seen)
2240 }
2241 InsertChild::Delete(delete) => refresh_para_ids_in_delete(delete, counts, used, seen),
2242 _ => {}
2243 }
2244 }
2245}
2246
2247fn refresh_para_ids_in_delete(
2248 delete: &mut Delete,
2249 counts: &HashMap<String, usize>,
2250 used: &mut HashSet<String>,
2251 seen: &mut HashSet<String>,
2252) {
2253 for child in &mut delete.children {
2254 if let DeleteChild::CommentStart(c) = child {
2255 refresh_para_ids_in_comment(&mut c.comment, counts, used, seen);
2256 }
2257 }
2258}
2259
2260fn refresh_para_ids_in_structured_data_tag(
2261 tag: &mut StructuredDataTag,
2262 counts: &HashMap<String, usize>,
2263 used: &mut HashSet<String>,
2264 seen: &mut HashSet<String>,
2265) {
2266 for child in &mut tag.children {
2267 match child {
2268 StructuredDataTagChild::Paragraph(paragraph) => {
2269 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2270 }
2271 StructuredDataTagChild::Table(table) => {
2272 refresh_para_ids_in_table(table, counts, used, seen)
2273 }
2274 StructuredDataTagChild::CommentStart(c) => {
2275 refresh_para_ids_in_comment(&mut c.comment, counts, used, seen)
2276 }
2277 StructuredDataTagChild::StructuredDataTag(inner) => {
2278 refresh_para_ids_in_structured_data_tag(inner, counts, used, seen)
2279 }
2280 _ => {}
2281 }
2282 }
2283}
2284
2285fn refresh_para_ids_in_comment(
2286 comment: &mut Comment,
2287 counts: &HashMap<String, usize>,
2288 used: &mut HashSet<String>,
2289 seen: &mut HashSet<String>,
2290) {
2291 for child in &mut comment.children {
2292 match child {
2293 CommentChild::Paragraph(paragraph) => {
2294 refresh_para_ids_in_paragraph(paragraph, counts, used, seen)
2295 }
2296 CommentChild::Table(table) => refresh_para_ids_in_table(table, counts, used, seen),
2297 }
2298 }
2299}
2300
2301fn ensure_unique_paragraph_id(
2302 paragraph: &mut Paragraph,
2303 counts: &HashMap<String, usize>,
2304 used: &mut HashSet<String>,
2305 seen: &mut HashSet<String>,
2306) {
2307 let id = paragraph.id.clone();
2308 let count = counts.get(&id).copied().unwrap_or(0);
2309
2310 if !id.is_empty() && count <= 1 {
2311 return;
2312 }
2313 if !id.is_empty() && count > 1 && !seen.contains(&id) {
2314 seen.insert(id);
2315 return;
2316 }
2317
2318 let mut new_id = crate::generate_para_id();
2319 while used.contains(&new_id) {
2320 new_id = crate::generate_para_id();
2321 }
2322 paragraph.id = new_id.clone();
2323 used.insert(new_id);
2324}
2325
2326fn push_comment_and_comment_extended(
2327 comments: &mut Vec<Comment>,
2328 comments_extended: &mut Vec<CommentExtended>,
2329 comment_map: &HashMap<usize, String>,
2330 c: &CommentRangeStart,
2331) {
2332 let comment = c.get_comment_ref();
2333 for child in &comment.children {
2334 if let CommentChild::Paragraph(child) = child {
2335 let para_id = child.id.clone();
2336 comments.push(comment.clone());
2337 let comment_extended = CommentExtended::new(para_id);
2338 if let Some(parent_comment_id) = comment.parent_comment_id {
2339 if let Some(parent_para_id) = comment_map.get(&parent_comment_id) {
2340 comments_extended
2341 .push(comment_extended.parent_paragraph_id(parent_para_id.clone()));
2342 }
2343 } else {
2344 comments_extended.push(comment_extended);
2345 }
2346 }
2347 }
2349}
2350
2351fn update_document_by_toc(
2352 document_children: Vec<DocumentChild>,
2353 styles: &Styles,
2354 toc: TableOfContents,
2355 toc_index: usize,
2356) -> Vec<DocumentChild> {
2357 let heading_map = styles.create_heading_style_map();
2358 let mut items = vec![];
2359 let mut children = vec![];
2360 let style_map: std::collections::HashMap<String, usize> = toc
2361 .instr
2362 .styles_with_levels
2363 .iter()
2364 .map(|sl| sl.0.clone())
2365 .collect();
2366
2367 if toc.instr.heading_styles_range.is_none() && !toc.instr.styles_with_levels.is_empty() {
2368 return document_children;
2370 }
2371
2372 let (min, max) = toc.instr.heading_styles_range.unwrap_or((0, 9));
2373
2374 for child in document_children.into_iter() {
2375 match child {
2376 DocumentChild::Paragraph(mut paragraph) => {
2377 if let Some(heading_level) = paragraph
2378 .property
2379 .style
2380 .as_ref()
2381 .map(|p| p.val.to_string())
2382 .and_then(|sid| heading_map.get(&sid))
2383 {
2384 if min <= *heading_level && max >= *heading_level {
2385 let toc_key = TocKey::generate();
2386 items.push(
2387 TableOfContentsItem::new()
2388 .text(paragraph.raw_text())
2389 .toc_key(&toc_key)
2390 .level(*heading_level),
2391 );
2392 paragraph =
2393 Box::new(paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key));
2394 }
2395
2396 if let Some((_min, _max)) = toc.instr.tc_field_level_range {
2397 }
2399 }
2400
2401 if let Some(level) = paragraph
2403 .property
2404 .style
2405 .as_ref()
2406 .and_then(|s| style_map.get(&s.val))
2407 {
2408 if min <= *level && max >= *level {
2409 let toc_key = TocKey::generate();
2410 items.push(
2411 TableOfContentsItem::new()
2412 .text(paragraph.raw_text())
2413 .toc_key(&toc_key)
2414 .level(*level),
2415 );
2416 paragraph =
2417 Box::new(paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key));
2418 }
2419 }
2420
2421 children.push(DocumentChild::Paragraph(paragraph));
2422 }
2423 DocumentChild::Table(ref _table) => {
2424 children.push(child);
2438 }
2439 _ => {
2440 children.push(child);
2441 }
2442 }
2443 }
2444
2445 let mut toc = toc;
2446 toc.items = items;
2447 children[toc_index] = DocumentChild::TableOfContents(Box::new(toc));
2448 children
2449}
2450
2451#[cfg(test)]
2452mod emf_tests {
2453 use super::*;
2454
2455 pub(super) fn minimal_valid_emf() -> Vec<u8> {
2458 let mut buf = Vec::<u8>::with_capacity(108);
2459
2460 buf.extend_from_slice(&1u32.to_le_bytes()); buf.extend_from_slice(&88u32.to_le_bytes()); buf.extend_from_slice(&0i32.to_le_bytes());
2465 buf.extend_from_slice(&0i32.to_le_bytes());
2466 buf.extend_from_slice(&100i32.to_le_bytes());
2467 buf.extend_from_slice(&100i32.to_le_bytes());
2468 buf.extend_from_slice(&0i32.to_le_bytes());
2470 buf.extend_from_slice(&0i32.to_le_bytes());
2471 buf.extend_from_slice(&2540i32.to_le_bytes());
2472 buf.extend_from_slice(&2540i32.to_le_bytes());
2473 buf.extend_from_slice(&0x464D_4520u32.to_le_bytes());
2475 buf.extend_from_slice(&0x0001_0000u32.to_le_bytes());
2476 buf.extend_from_slice(&108u32.to_le_bytes());
2477 buf.extend_from_slice(&2u32.to_le_bytes());
2478 buf.extend_from_slice(&0u16.to_le_bytes());
2480 buf.extend_from_slice(&0u16.to_le_bytes());
2481 buf.extend_from_slice(&0u32.to_le_bytes());
2482 buf.extend_from_slice(&0u32.to_le_bytes());
2483 buf.extend_from_slice(&0u32.to_le_bytes());
2484 buf.extend_from_slice(&1024i32.to_le_bytes());
2486 buf.extend_from_slice(&768i32.to_le_bytes());
2487 buf.extend_from_slice(&320i32.to_le_bytes());
2489 buf.extend_from_slice(&240i32.to_le_bytes());
2490 debug_assert_eq!(buf.len(), 88);
2491
2492 buf.extend_from_slice(&14u32.to_le_bytes()); buf.extend_from_slice(&20u32.to_le_bytes()); buf.extend_from_slice(&0u32.to_le_bytes()); buf.extend_from_slice(&0u32.to_le_bytes()); buf.extend_from_slice(&20u32.to_le_bytes()); buf
2500 }
2501
2502 fn corrupt_emf_header() -> Vec<u8> {
2506 let mut buf = vec![0u8; 44];
2507 buf[0..4].copy_from_slice(&[0x01, 0x00, 0x00, 0x00]);
2508 buf[4..8].copy_from_slice(&[0x2C, 0x00, 0x00, 0x00]);
2509 buf[40..44].copy_from_slice(&[0x20, 0x45, 0x4D, 0x46]);
2510 buf
2511 }
2512
2513 fn png_signature_bytes() -> Vec<u8> {
2514 let mut buf = vec![137, 80, 78, 71, 13, 10, 26, 10];
2517 buf.resize(64, 0);
2518 buf
2519 }
2520
2521 #[test]
2524 fn is_emf_detects_lowercase_extension() {
2525 assert!(is_emf("word/media/image1.emf", &[]));
2526 }
2527
2528 #[test]
2529 fn is_emf_detects_uppercase_extension() {
2530 assert!(is_emf("word/media/IMAGE1.EMF", &[]));
2531 }
2532
2533 #[test]
2534 fn is_emf_rejects_png_extension() {
2535 assert!(!is_emf("word/media/image1.png", &png_signature_bytes()));
2536 }
2537
2538 #[test]
2539 fn is_emf_rejects_empty_buffer_with_unrelated_extension() {
2540 assert!(!is_emf("word/media/image1.bin", &[]));
2541 }
2542
2543 #[test]
2544 fn is_emf_detects_magic_bytes_without_extension() {
2545 let buf = minimal_valid_emf();
2546 assert!(is_emf("word/media/image1.bin", &buf));
2547 }
2548
2549 #[test]
2550 fn is_emf_rejects_buffer_too_short_for_signature() {
2551 let buf = vec![0x01, 0x00, 0x00, 0x00];
2554 assert!(!is_emf("x.bin", &buf));
2555 }
2556
2557 #[test]
2558 fn is_emf_rejects_wrong_signature() {
2559 let mut buf = vec![0u8; 44];
2561 buf[0..4].copy_from_slice(&[0x01, 0x00, 0x00, 0x00]);
2562 buf[40..44].copy_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
2563 assert!(!is_emf("x.bin", &buf));
2564 }
2565
2566 #[test]
2569 fn add_image_routes_valid_emf_into_images_with_empty_preview() {
2570 let buf = minimal_valid_emf();
2571 let docx = Docx::new().add_image("rId1", "word/media/image1.emf", buf.clone());
2572
2573 assert_eq!(
2574 docx.images.len(),
2575 1,
2576 "EMF should land in the unified `images` vector"
2577 );
2578 let (id, path, original, preview) = &docx.images[0];
2579 assert_eq!(id, "rId1");
2580 assert_eq!(path, "word/media/image1.emf");
2581 assert_eq!(original.0, buf);
2582 assert!(preview.0.is_empty());
2583 }
2584
2585 #[test]
2586 fn add_image_preserves_emf_detected_by_magic_bytes() {
2587 let buf = corrupt_emf_header();
2588 let docx = Docx::new().add_image("rId1", "word/media/image1.bin", buf.clone());
2589 assert_eq!(docx.images.len(), 1);
2590 let (_, _, original, preview) = &docx.images[0];
2591 assert_eq!(original.0, buf);
2592 assert!(preview.0.is_empty());
2593 }
2594
2595 #[test]
2596 fn add_image_routes_png_as_png_preview() {
2597 let png_bytes = {
2599 let img = image::RgbImage::from_pixel(1, 1, image::Rgb([0, 0, 0]));
2600 let mut cursor = std::io::Cursor::new(Vec::new());
2601 image::DynamicImage::ImageRgb8(img)
2602 .write_to(&mut cursor, image::ImageFormat::Png)
2603 .unwrap();
2604 cursor.into_inner()
2605 };
2606 let _ = png_signature_bytes(); let docx = Docx::new().add_image("rId1", "word/media/image1.png", png_bytes);
2608 assert_eq!(docx.images.len(), 1);
2609 let (_, _, _, preview) = &docx.images[0];
2610 assert_eq!(&preview.0[..8], &[137, 80, 78, 71, 13, 10, 26, 10]);
2612 }
2613
2614 #[test]
2617 fn docx_serializes_emf_under_images_field() {
2618 let docx = Docx::new().add_image("rId1", "word/media/image1.emf", minimal_valid_emf());
2619 let json = serde_json::to_string(&docx).expect("should serialize");
2620 assert!(json.contains("\"images\""));
2623 assert!(
2624 !json.contains("imagesEmf"),
2625 "EMF is unified into `images`; no separate `imagesEmf` key"
2626 );
2627 use base64::Engine;
2629 let b64 = base64::engine::general_purpose::STANDARD.encode(minimal_valid_emf());
2630 assert!(json.contains(&b64));
2631 }
2632}
2633
2634#[cfg(test)]
2638mod emf_reader_tests {
2639 use super::emf_tests::minimal_valid_emf;
2640 use std::io::Write;
2641
2642 fn build_docx_with_emf() -> Vec<u8> {
2647 let buf = std::io::Cursor::new(Vec::<u8>::new());
2648 let mut zip = zip::ZipWriter::new(buf);
2649 let opts: zip::write::FileOptions<'_, ()> =
2650 zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated);
2651
2652 let content_types = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2653<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
2654 <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
2655 <Default Extension="xml" ContentType="application/xml"/>
2656 <Default Extension="emf" ContentType="image/x-emf"/>
2657 <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
2658</Types>"#;
2659 let root_rels = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2660<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
2661 <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
2662</Relationships>"#;
2663 let doc_rels = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2664<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
2665 <Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.emf"/>
2666</Relationships>"#;
2667 let document = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2668<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
2669 <w:body>
2670 <w:p><w:r><w:t>hello</w:t></w:r></w:p>
2671 </w:body>
2672</w:document>"#;
2673
2674 for (path, body) in [
2675 ("[Content_Types].xml", content_types),
2676 ("_rels/.rels", root_rels),
2677 ("word/_rels/document.xml.rels", doc_rels),
2678 ("word/document.xml", document),
2679 ] {
2680 zip.start_file(path, opts).unwrap();
2681 zip.write_all(body.as_bytes()).unwrap();
2682 }
2683 zip.start_file("word/media/image1.emf", opts).unwrap();
2684 zip.write_all(&minimal_valid_emf()).unwrap();
2685
2686 zip.finish().unwrap().into_inner()
2687 }
2688
2689 #[test]
2690 fn read_docx_routes_emf_media_to_images_with_empty_preview() {
2691 let docx_bytes = build_docx_with_emf();
2692 let docx = crate::reader::read_docx(&docx_bytes).expect("should read docx");
2693
2694 assert_eq!(
2695 docx.images.len(),
2696 1,
2697 "EMF media should be routed into the unified `images` vector"
2698 );
2699 let (id, path, original, preview) = &docx.images[0];
2700 assert_eq!(id, "rId10");
2701 assert!(path.ends_with("image1.emf"));
2702 assert_eq!(original.0, minimal_valid_emf());
2703 assert!(preview.0.is_empty());
2704 }
2705}