diff --git a/docx-core/examples/reader.rs b/docx-core/examples/reader.rs index 00da286..bf09166 100644 --- a/docx-core/examples/reader.rs +++ b/docx-core/examples/reader.rs @@ -3,7 +3,7 @@ use std::fs::*; use std::io::Read; pub fn main() { - let mut file = File::open("./1.docx").unwrap(); + let mut file = File::open("./fixtures/image_node_docx/image.docx").unwrap(); let mut buf = vec![]; file.read_to_end(&mut buf).unwrap(); dbg!(read_docx(&buf).unwrap().json()); diff --git a/docx-core/src/documents/elements/a_graphic.rs b/docx-core/src/documents/elements/a_graphic.rs new file mode 100644 index 0000000..c6efcf0 --- /dev/null +++ b/docx-core/src/documents/elements/a_graphic.rs @@ -0,0 +1,65 @@ +use super::*; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct AGraphic { + pub children: Vec, +} + +impl AGraphic { + pub fn new() -> AGraphic { + Default::default() + } + + pub fn add_graphic_data(mut self, g: AGraphicData) -> Self { + self.children.push(g); + self + } +} + +impl Default for AGraphic { + fn default() -> Self { + Self { children: vec![] } + } +} + +impl BuildXML for AGraphic { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_graphic("http://schemas.openxmlformats.org/drawingml/2006/main"); + for child in &self.children { + b = b.add_child(child); + } + b.close().build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + + #[test] + fn test_a_graphic_with_textbox_json() { + let graphic = + AGraphic::new().add_graphic_data( + AGraphicData::new(GraphicDataType::WpShape).add_shape( + WpsShape::new().add_text_box(WpsTextBox::new().add_content( + TextBoxContent::new().add_paragraph( + Paragraph::new().add_run(Run::new().add_text("pattern1")), + ), + )), + ), + ); + assert_eq!( + serde_json::to_string(&graphic).unwrap(), + r#"{"children":[{"dataType":"wpShape","children":[{"type":"shape","data":{"children":[{"type":"textbox","data":{"children":[{"children":[{"type":"paragraph","data":{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"pattern1"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":"Normal","numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}}],"has_numbering":false}],"hasNumbering":false}}]}}]}]}"# + ); + } +} diff --git a/docx-core/src/documents/elements/a_graphic_data.rs b/docx-core/src/documents/elements/a_graphic_data.rs new file mode 100644 index 0000000..ace4eae --- /dev/null +++ b/docx-core/src/documents/elements/a_graphic_data.rs @@ -0,0 +1,101 @@ +use super::*; +use serde::ser::{SerializeStruct, Serializer}; +use serde::Serialize; +use std::str::FromStr; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +/* + 20.1.2.2.17 + graphicData (Graphic Object Data) + This element specifies the reference to a graphic object within the document. This graphic object is provided + entirely by the document authors who choose to persist this data within the document. +*/ +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct AGraphicData { + pub data_type: GraphicDataType, + pub children: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum GraphicDataChild { + Shape(WpsShape), +} + +impl Serialize for GraphicDataChild { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + GraphicDataChild::Shape(ref s) => { + let mut t = serializer.serialize_struct("Shape", 2)?; + t.serialize_field("type", "shape")?; + t.serialize_field("data", s)?; + t.end() + } + } + } +} + +impl GraphicDataType { + fn to_uri(&self) -> &str { + match *self { + GraphicDataType::Picture => "http://schemas.openxmlformats.org/drawingml/2006/picture", + GraphicDataType::WpShape => { + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" + } + _ => "", + } + } +} + +impl FromStr for GraphicDataType { + type Err = (); + fn from_str(s: &str) -> Result { + if s.ends_with("picture") { + return Ok(GraphicDataType::Picture); + } + if s.ends_with("wordprocessingShape") { + return Ok(GraphicDataType::WpShape); + } + Ok(GraphicDataType::Unsupported) + } +} + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum GraphicDataType { + Picture, + WpShape, + Unsupported, +} + +impl AGraphicData { + pub fn new(data_type: GraphicDataType) -> AGraphicData { + AGraphicData { + data_type, + children: vec![], + } + } + + pub fn add_shape(mut self, shape: WpsShape) -> Self { + self.children.push(GraphicDataChild::Shape(shape)); + self + } +} + +impl BuildXML for AGraphicData { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_graphic_data(self.data_type.to_uri()); + for c in &self.children { + match c { + GraphicDataChild::Shape(t) => b = b.add_child(t), + } + } + b.close().build() + } +} diff --git a/docx-core/src/documents/elements/drawing.rs b/docx-core/src/documents/elements/drawing.rs new file mode 100644 index 0000000..fe45435 --- /dev/null +++ b/docx-core/src/documents/elements/drawing.rs @@ -0,0 +1,64 @@ +use super::*; +use serde::ser::{SerializeStruct, Serializer}; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +pub struct Drawing { + pub children: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum DrawingChild { + WpAnchor(WpAnchor), +} + +impl Serialize for DrawingChild { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + DrawingChild::WpAnchor(ref s) => { + let mut t = serializer.serialize_struct("WpAnchor", 2)?; + t.serialize_field("type", "anchor")?; + t.serialize_field("data", s)?; + t.end() + } + } + } +} + +impl Drawing { + pub fn new() -> Drawing { + Default::default() + } + + pub fn add_anchor(mut self, a: WpAnchor) -> Drawing { + self.children.push(DrawingChild::WpAnchor(a)); + self + } +} + +impl Default for Drawing { + fn default() -> Self { + Drawing { children: vec![] } + } +} + +impl BuildXML for Drawing { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_drawing(); + for child in &self.children { + match child { + DrawingChild::WpAnchor(a) => { + b = b.add_child(a); + } + } + } + b.close().build() + } +} diff --git a/docx-core/src/documents/elements/mc_fallback.rs b/docx-core/src/documents/elements/mc_fallback.rs new file mode 100644 index 0000000..94c57c0 --- /dev/null +++ b/docx-core/src/documents/elements/mc_fallback.rs @@ -0,0 +1,27 @@ +// use super::*; +use serde::Serialize; + +use crate::documents::BuildXML; +// use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +pub struct McFallback {} + +impl McFallback { + pub fn new() -> McFallback { + Default::default() + } +} + +impl Default for McFallback { + fn default() -> Self { + McFallback {} + } +} + +impl BuildXML for McFallback { + fn build(&self) -> Vec { + // Ignore for now + vec![] + } +} diff --git a/docx-core/src/documents/elements/mod.rs b/docx-core/src/documents/elements/mod.rs index 623dcc5..da050a8 100644 --- a/docx-core/src/documents/elements/mod.rs +++ b/docx-core/src/documents/elements/mod.rs @@ -1,3 +1,5 @@ +mod a_graphic; +mod a_graphic_data; mod abstract_numbering; mod based_on; mod bold; @@ -13,6 +15,7 @@ mod default_tab_stop; mod delete; mod delete_text; mod doc_defaults; +mod drawing; mod font; mod grid_span; mod highlight; @@ -25,6 +28,7 @@ mod justification; mod level; mod level_jc; mod level_text; +mod mc_fallback; mod name; mod next; mod number_format; @@ -60,12 +64,18 @@ mod table_row; mod table_row_property; mod table_width; mod text; +mod text_box_content; mod underline; mod vanish; mod vertical_align; mod vertical_merge; +mod wp_anchor; +mod wps_shape; +mod wps_text_box; mod zoom; +pub use a_graphic::*; +pub use a_graphic_data::*; pub use abstract_numbering::*; pub use based_on::*; pub use bold::*; @@ -81,6 +91,7 @@ pub use default_tab_stop::*; pub use delete::*; pub use delete_text::*; pub use doc_defaults::*; +pub use drawing::*; pub use font::*; pub use grid_span::*; pub use highlight::*; @@ -93,6 +104,7 @@ pub use justification::*; pub use level::*; pub use level_jc::*; pub use level_text::*; +pub use mc_fallback::*; pub use name::*; pub use next::*; pub use number_format::*; @@ -128,8 +140,12 @@ pub use table_row::*; pub use table_row_property::*; pub use table_width::*; pub use text::*; +pub use text_box_content::*; pub use underline::*; pub use vanish::*; pub use vertical_align::*; pub use vertical_merge::*; +pub use wp_anchor::*; +pub use wps_shape::*; +pub use wps_text_box::*; pub use zoom::*; diff --git a/docx-core/src/documents/elements/run.rs b/docx-core/src/documents/elements/run.rs index 686adde..a72844e 100644 --- a/docx-core/src/documents/elements/run.rs +++ b/docx-core/src/documents/elements/run.rs @@ -1,12 +1,12 @@ -use super::{Break, DeleteText, RunProperty, Tab, Text}; +use super::{Break, DeleteText, Drawing, RunProperty, Tab, Text}; use serde::ser::{SerializeStruct, Serializer}; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use crate::documents::BuildXML; use crate::types::BreakType; use crate::xml_builder::*; -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Run { pub run_property: RunProperty, @@ -23,12 +23,13 @@ impl Default for Run { } } -#[derive(Debug, Clone, Deserialize, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub enum RunChild { Text(Text), DeleteText(DeleteText), Tab(Tab), Break(Break), + Drawing(Drawing), } impl Serialize for RunChild { @@ -60,6 +61,12 @@ impl Serialize for RunChild { t.serialize_field("data", s)?; t.end() } + RunChild::Drawing(ref s) => { + let mut t = serializer.serialize_struct("Drawing", 2)?; + t.serialize_field("type", "drawing")?; + t.serialize_field("data", s)?; + t.end() + } } } } @@ -87,6 +94,11 @@ impl Run { self } + pub fn add_drawing(mut self, d: Drawing) -> Run { + self.children.push(RunChild::Drawing(d)); + self + } + pub fn add_break(mut self, break_type: BreakType) -> Run { self.children.push(RunChild::Break(Break::new(break_type))); self @@ -138,6 +150,7 @@ impl BuildXML for Run { RunChild::DeleteText(t) => b = b.add_child(t), RunChild::Tab(t) => b = b.add_child(t), RunChild::Break(t) => b = b.add_child(t), + RunChild::Drawing(t) => b = b.add_child(t), } } b.close().build() diff --git a/docx-core/src/documents/elements/text_box_content.rs b/docx-core/src/documents/elements/text_box_content.rs new file mode 100644 index 0000000..21c9b44 --- /dev/null +++ b/docx-core/src/documents/elements/text_box_content.rs @@ -0,0 +1,105 @@ +use super::*; +use serde::ser::{SerializeStruct, Serializer}; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +pub struct TextBoxContent { + pub children: Vec, + pub has_numbering: bool, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum TextBoxContentChild { + Paragraph(Paragraph), + Table(Table), +} + +impl Serialize for TextBoxContentChild { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + TextBoxContentChild::Paragraph(ref p) => { + let mut t = serializer.serialize_struct("Paragraph", 2)?; + t.serialize_field("type", "paragraph")?; + t.serialize_field("data", p)?; + t.end() + } + TextBoxContentChild::Table(ref c) => { + let mut t = serializer.serialize_struct("Table", 2)?; + t.serialize_field("type", "table")?; + t.serialize_field("data", c)?; + t.end() + } + } + } +} + +impl TextBoxContent { + pub fn new() -> TextBoxContent { + Default::default() + } + + pub fn add_paragraph(mut self, p: Paragraph) -> Self { + if p.has_numbering { + self.has_numbering = true + } + self.children.push(TextBoxContentChild::Paragraph(p)); + self + } + + pub fn add_table(mut self, t: Table) -> Self { + if t.has_numbering { + self.has_numbering = true + } + self.children.push(TextBoxContentChild::Table(t)); + self + } +} + +impl Default for TextBoxContent { + fn default() -> Self { + TextBoxContent { + children: vec![], + has_numbering: false, + } + } +} + +impl BuildXML for TextBoxContent { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_text_box_content(); + for c in &self.children { + match c { + TextBoxContentChild::Paragraph(p) => b = b.add_child(p), + TextBoxContentChild::Table(t) => b = b.add_child(t), + } + } + b.close().build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_text_box_content_build() { + let b = TextBoxContent::new() + .add_paragraph(Paragraph::new()) + .build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/documents/elements/wp_anchor.rs b/docx-core/src/documents/elements/wp_anchor.rs new file mode 100644 index 0000000..cd01587 --- /dev/null +++ b/docx-core/src/documents/elements/wp_anchor.rs @@ -0,0 +1,65 @@ +use super::*; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct WpAnchor { + pub children: Vec, +} + +/* + 20.4.2.3 + anchor (WpAnchor for Floating DrawingML Object) + This element specifies that the DrawingML object located at this position in the document is a floating object. + Within a WordprocessingML document, drawing objects can exist in two states: + - Inline - The drawing object is in line with the text, and affects the line height and layout of its line (like a + - character glyph of similar size). + Floating - The drawing object is anchored within the text, but can be absolutely positioned in the + document relative to the page. + When this element encapsulates the DrawingML object's i +*/ +impl WpAnchor { + pub fn new() -> WpAnchor { + Default::default() + } + + pub fn add_graphic(mut self, g: AGraphic) -> WpAnchor { + self.children.push(g); + self + } +} + +impl Default for WpAnchor { + fn default() -> Self { + WpAnchor { children: vec![] } + } +} + +impl BuildXML for WpAnchor { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_anchor(); + for c in &self.children { + b = b.add_child(c) + } + b.close().build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_anchor_build() { + let b = WpAnchor::new().build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/wps_shape.rs b/docx-core/src/documents/elements/wps_shape.rs new file mode 100644 index 0000000..d5b55c7 --- /dev/null +++ b/docx-core/src/documents/elements/wps_shape.rs @@ -0,0 +1,63 @@ +use super::*; +use serde::ser::{SerializeStruct, Serializer}; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct WpsShape { + children: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum WpsShapeChild { + WpsTextBox(WpsTextBox), +} + +impl Serialize for WpsShapeChild { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + WpsShapeChild::WpsTextBox(ref s) => { + let mut t = serializer.serialize_struct("WpsTextBox", 2)?; + t.serialize_field("type", "textbox")?; + t.serialize_field("data", s)?; + t.end() + } + } + } +} + +impl WpsShape { + pub fn new() -> WpsShape { + Default::default() + } + + pub fn add_text_box(mut self, text_box: WpsTextBox) -> Self { + self.children.push(WpsShapeChild::WpsTextBox(text_box)); + self + } +} + +impl Default for WpsShape { + fn default() -> Self { + WpsShape { children: vec![] } + } +} + +impl BuildXML for WpsShape { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_wp_text_box(); + for c in &self.children { + match c { + WpsShapeChild::WpsTextBox(t) => b = b.add_child(t), + } + } + b.close().build() + } +} diff --git a/docx-core/src/documents/elements/wps_text_box.rs b/docx-core/src/documents/elements/wps_text_box.rs new file mode 100644 index 0000000..c61a0d4 --- /dev/null +++ b/docx-core/src/documents/elements/wps_text_box.rs @@ -0,0 +1,65 @@ +use super::*; +use serde::Serialize; + +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct WpsTextBox { + pub children: Vec, + pub has_numbering: bool, +} + +impl WpsTextBox { + pub fn new() -> WpsTextBox { + Default::default() + } + + pub fn add_content(mut self, c: TextBoxContent) -> Self { + if c.has_numbering { + self.has_numbering = true + } + self.children.push(c); + self + } +} + +impl Default for WpsTextBox { + fn default() -> Self { + WpsTextBox { + children: vec![], + has_numbering: false, + } + } +} + +impl BuildXML for WpsTextBox { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let mut b = b.open_wp_text_box(); + for c in &self.children { + b = b.add_child(c); + } + b.close().build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_wp_text_box_build() { + let c = TextBoxContent::new().add_paragraph(Paragraph::new()); + let b = WpsTextBox::new().add_content(c).build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/reader/a_graphic.rs b/docx-core/src/reader/a_graphic.rs new file mode 100644 index 0000000..d6d6794 --- /dev/null +++ b/docx-core/src/reader/a_graphic.rs @@ -0,0 +1,122 @@ +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for AGraphic { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut graphic = AGraphic::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = AXMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + if let AXMLElement::GraphicData = e { + dbg!("graphicData1"); + let data = AGraphicData::read(r, &attributes)?; + graphic = graphic.add_graphic_data(data); + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = AXMLElement::from_str(&name.local_name).unwrap(); + if e == AXMLElement::Graphic { + return Ok(graphic); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + + #[test] + fn test_read_graphic_with_textbox() { + let c = r#" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pattern1 + + + + + + + + + "#; + let mut parser = EventReader::new(c.as_bytes()); + let g = AGraphic::read(&mut parser, &[]).unwrap(); + assert_eq!( + g, + AGraphic::new().add_graphic_data( + AGraphicData::new(GraphicDataType::WpShape).add_shape( + WpsShape::new().add_text_box(WpsTextBox::new().add_content( + TextBoxContent::new().add_paragraph( + Paragraph::new().add_run(Run::new().add_text("pattern1")) + ) + )) + ) + ) + ); + } +} diff --git a/docx-core/src/reader/a_graphic_data.rs b/docx-core/src/reader/a_graphic_data.rs new file mode 100644 index 0000000..fbb61ca --- /dev/null +++ b/docx-core/src/reader/a_graphic_data.rs @@ -0,0 +1,53 @@ +#![allow(clippy::single_match)] + +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for AGraphicData { + fn read( + r: &mut EventReader, + attrs: &[OwnedAttribute], + ) -> Result { + let mut t = GraphicDataType::Unsupported; + for a in attrs { + if a.name.local_name == "uri" { + t = GraphicDataType::from_str(&a.value).unwrap(); + } + } + dbg!(&t); + let mut graphic_data = AGraphicData::new(t); + loop { + let e = r.next(); + dbg!(&graphic_data, &e); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = WpsXMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + match e { + WpsXMLElement::Wsp => { + dbg!("asdad"); + let shape = WpsShape::read(r, &attributes)?; + graphic_data = graphic_data.add_shape(shape); + } + _ => {} + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = AXMLElement::from_str(&name.local_name).unwrap(); + if e == AXMLElement::GraphicData { + return Ok(graphic_data); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/drawing.rs b/docx-core/src/reader/drawing.rs new file mode 100644 index 0000000..fee089b --- /dev/null +++ b/docx-core/src/reader/drawing.rs @@ -0,0 +1,44 @@ +#![allow(clippy::single_match)] + +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for Drawing { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut drawing = Drawing::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = WpXMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + match e { + WpXMLElement::Anchor => { + let anchor = WpAnchor::read(r, &attributes)?; + drawing = drawing.add_anchor(anchor); + } + _ => {} + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = XMLElement::from_str(&name.local_name).unwrap(); + if e == XMLElement::Drawing { + return Ok(drawing); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/mc_fallback.rs b/docx-core/src/reader/mc_fallback.rs new file mode 100644 index 0000000..3561552 --- /dev/null +++ b/docx-core/src/reader/mc_fallback.rs @@ -0,0 +1,36 @@ +#![allow(clippy::single_match)] + +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::McFallback; + +use crate::reader::*; + +impl ElementReader for McFallback { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + loop { + let fallback = McFallback::new(); + let e = r.next(); + match e { + Ok(XmlEvent::EndElement { name, .. }) => { + let e = McXMLElement::from_str(&name.local_name).unwrap(); + match e { + McXMLElement::Fallback => { + return Ok(fallback); + } + _ => {} + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/mod.rs b/docx-core/src/reader/mod.rs index 99182d8..555fe75 100644 --- a/docx-core/src/reader/mod.rs +++ b/docx-core/src/reader/mod.rs @@ -1,11 +1,15 @@ +mod a_graphic; +mod a_graphic_data; mod attributes; mod delete; mod document; mod document_rels; +mod drawing; mod errors; mod from_xml; mod insert; mod level; +mod mc_fallback; mod numbering_property; mod numberings; mod paragraph; @@ -17,6 +21,10 @@ mod styles; mod table; mod table_cell; mod table_row; +mod text_box_content; +mod wp_anchor; +mod wps_shape; +mod wps_text_box; mod xml_element; use std::io::Cursor; @@ -28,6 +36,7 @@ pub use attributes::*; pub use document_rels::*; pub use errors::ReaderError; pub use from_xml::*; +pub use mc_fallback::*; pub use read_zip::*; pub use xml_element::*; diff --git a/docx-core/src/reader/run.rs b/docx-core/src/reader/run.rs index 0f39633..b5944ca 100644 --- a/docx-core/src/reader/run.rs +++ b/docx-core/src/reader/run.rs @@ -1,3 +1,5 @@ +#![allow(clippy::single_match)] + use std::io::Read; use std::str::FromStr; @@ -29,39 +31,63 @@ impl ElementReader for Run { Ok(XmlEvent::StartElement { attributes, name, .. }) => { - let e = XMLElement::from_str(&name.local_name).unwrap(); - match e { - XMLElement::Tab => { - run = run.add_tab(); - } - XMLElement::Bold => { - if !read_bool(&attributes) { - continue; + match name.prefix.as_ref().map(std::ops::Deref::deref) { + Some("w") => { + let e = XMLElement::from_str(&name.local_name).unwrap(); + match e { + XMLElement::Tab => { + run = run.add_tab(); + } + XMLElement::Bold => { + if !read_bool(&attributes) { + continue; + } + run = run.bold(); + } + XMLElement::Highlight => { + run = run.highlight(attributes[0].value.clone()) + } + XMLElement::Color => run = run.color(attributes[0].value.clone()), + XMLElement::Size => { + run = run.size(usize::from_str(&attributes[0].value)?) + } + XMLElement::Underline => { + run = run.underline(&attributes[0].value.clone()) + } + XMLElement::Italic => { + if !read_bool(&attributes) { + continue; + } + run = run.italic(); + } + XMLElement::Vanish => run = run.vanish(), + XMLElement::Text => text_state = TextState::Text, + XMLElement::DeleteText => text_state = TextState::Delete, + XMLElement::Break => { + if let Some(a) = &attributes.get(0) { + run = run.add_break(BreakType::from_str(&a.value)?) + } else { + run = run.add_break(BreakType::TextWrapping) + } + } + XMLElement::Drawing => { + let drawing = Drawing::read(r, &attributes)?; + run = run.add_drawing(drawing); + } + _ => {} } - run = run.bold(); } - XMLElement::Highlight => run = run.highlight(attributes[0].value.clone()), - XMLElement::Color => run = run.color(attributes[0].value.clone()), - XMLElement::Size => run = run.size(usize::from_str(&attributes[0].value)?), - XMLElement::Underline => run = run.underline(&attributes[0].value.clone()), - XMLElement::Italic => { - if !read_bool(&attributes) { - continue; - } - run = run.italic(); - } - XMLElement::Vanish => run = run.vanish(), - XMLElement::Text => text_state = TextState::Text, - XMLElement::DeleteText => text_state = TextState::Delete, - XMLElement::Break => { - if let Some(a) = &attributes.get(0) { - run = run.add_break(BreakType::from_str(&a.value)?) - } else { - run = run.add_break(BreakType::TextWrapping) + Some("mc") => { + let e = McXMLElement::from_str(&name.local_name).unwrap(); + match e { + McXMLElement::Fallback => { + let _ = McFallback::read(r, &attributes)?; + } + _ => {} } } _ => {} - } + }; } Ok(XmlEvent::Characters(c)) => match text_state { TextState::Delete => { diff --git a/docx-core/src/reader/text_box_content.rs b/docx-core/src/reader/text_box_content.rs new file mode 100644 index 0000000..6c82c86 --- /dev/null +++ b/docx-core/src/reader/text_box_content.rs @@ -0,0 +1,48 @@ +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for TextBoxContent { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut content = TextBoxContent::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = XMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + match e { + XMLElement::Paragraph => { + let p = Paragraph::read(r, &attributes)?; + content = content.add_paragraph(p); + continue; + } + XMLElement::Table => { + let t = Table::read(r, &attributes)?; + content = content.add_table(t); + continue; + } + _ => {} + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = XMLElement::from_str(&name.local_name).unwrap(); + if e == XMLElement::TxbxContent { + return Ok(content); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/wp_anchor.rs b/docx-core/src/reader/wp_anchor.rs new file mode 100644 index 0000000..ffe2c50 --- /dev/null +++ b/docx-core/src/reader/wp_anchor.rs @@ -0,0 +1,39 @@ +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for WpAnchor { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut anchor = WpAnchor::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = AXMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + if let AXMLElement::Graphic = e { + let g = AGraphic::read(r, &attributes)?; + anchor = anchor.add_graphic(g); + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = WpXMLElement::from_str(&name.local_name).unwrap(); + if e == WpXMLElement::Anchor { + return Ok(anchor); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/wps_shape.rs b/docx-core/src/reader/wps_shape.rs new file mode 100644 index 0000000..4c7c731 --- /dev/null +++ b/docx-core/src/reader/wps_shape.rs @@ -0,0 +1,44 @@ +#![allow(clippy::single_match)] + +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for WpsShape { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut shape = WpsShape::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = WpsXMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + match e { + WpsXMLElement::Txbx => { + let text_box = WpsTextBox::read(r, &attributes)?; + shape = shape.add_text_box(text_box); + } + _ => {} + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = WpsXMLElement::from_str(&name.local_name).unwrap(); + if e == WpsXMLElement::Wsp { + return Ok(shape); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/wps_text_box.rs b/docx-core/src/reader/wps_text_box.rs new file mode 100644 index 0000000..ea4d746 --- /dev/null +++ b/docx-core/src/reader/wps_text_box.rs @@ -0,0 +1,44 @@ +#![allow(clippy::single_match)] + +use std::io::Read; +use std::str::FromStr; + +use xml::attribute::OwnedAttribute; +use xml::reader::{EventReader, XmlEvent}; + +use super::*; + +impl ElementReader for WpsTextBox { + fn read( + r: &mut EventReader, + _attrs: &[OwnedAttribute], + ) -> Result { + let mut text_box = WpsTextBox::new(); + loop { + let e = r.next(); + match e { + Ok(XmlEvent::StartElement { + name, attributes, .. + }) => { + let e = XMLElement::from_str(&name.local_name) + .expect("should convert to XMLElement"); + match e { + XMLElement::TxbxContent => { + let content = TextBoxContent::read(r, &attributes)?; + text_box = text_box.add_content(content); + } + _ => {} + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + let e = WpsXMLElement::from_str(&name.local_name).unwrap(); + if e == WpsXMLElement::Txbx { + return Ok(text_box); + } + } + Err(_) => return Err(ReaderError::XMLReadError), + _ => {} + } + } + } +} diff --git a/docx-core/src/reader/xml_element.rs b/docx-core/src/reader/xml_element.rs index 29ce779..31a4c72 100644 --- a/docx-core/src/reader/xml_element.rs +++ b/docx-core/src/reader/xml_element.rs @@ -79,6 +79,63 @@ pub enum XMLElement { LevelJustification, StyleLink, NumStyleLink, + Drawing, + TxbxContent, + Pict, + Unsupported, +} + +#[derive(PartialEq, Debug)] +pub enum McXMLElement { + AlternateContent, + Choice, + Fallback, + Unsupported, +} + +#[derive(PartialEq, Debug)] +pub enum WpXMLElement { + Anchor, + SimplePos, + PositionH, + PosOffset, + PositionV, + Extent, + EffectExtent, + WrapNone, + DocProperty, + Unsupported, +} + +#[derive(PartialEq, Debug)] +pub enum AXMLElement { + Graphic, + GraphicData, + Xfrm, + Off, + Ext, + PrstGeom, + SolidFill, + Ln, + Unsupported, +} + +#[derive(PartialEq, Debug)] +pub enum WpsXMLElement { + Wsp, + CNvSpProperty, + SpProperty, + Style, + Txbx, + BodyPr, + Unsupported, +} +#[derive(PartialEq, Debug)] +pub enum VXMLElement { + Rect, + Stroke, + Fill, + TextBox, Unsupported, } @@ -157,11 +214,89 @@ impl FromStr for XMLElement { "numStyleLink" => Ok(XMLElement::NumStyleLink), "styleLink" => Ok(XMLElement::StyleLink), "vAlign" => Ok(XMLElement::VAlign), + "drawing" => Ok(XMLElement::Drawing), + "txbxContent" => Ok(XMLElement::TxbxContent), + "pict" => Ok(XMLElement::Pict), _ => Ok(XMLElement::Unsupported), } } } +impl FromStr for McXMLElement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "alternateContent" => Ok(McXMLElement::AlternateContent), + "choice" => Ok(McXMLElement::Choice), + "fallback" => Ok(McXMLElement::Fallback), + _ => Ok(McXMLElement::Unsupported), + } + } +} + +impl FromStr for WpXMLElement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "anchor" => Ok(WpXMLElement::Anchor), + "simplePos" => Ok(WpXMLElement::SimplePos), + "positionH" => Ok(WpXMLElement::PositionH), + "posOffset" => Ok(WpXMLElement::PosOffset), + "positionV" => Ok(WpXMLElement::PositionV), + "extent" => Ok(WpXMLElement::Extent), + "effectExtent" => Ok(WpXMLElement::EffectExtent), + "wrapNone" => Ok(WpXMLElement::WrapNone), + "docPr" => Ok(WpXMLElement::DocProperty), + _ => Ok(WpXMLElement::Unsupported), + } + } +} + +impl FromStr for AXMLElement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "graphic" => Ok(AXMLElement::Graphic), + "graphicData" => Ok(AXMLElement::GraphicData), + "xfrm" => Ok(AXMLElement::Xfrm), + "off" => Ok(AXMLElement::Off), + "ext" => Ok(AXMLElement::Ext), + "prstGeom" => Ok(AXMLElement::PrstGeom), + "solidFill" => Ok(AXMLElement::SolidFill), + "ln" => Ok(AXMLElement::Ln), + _ => Ok(AXMLElement::Unsupported), + } + } +} + +impl FromStr for WpsXMLElement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "wsp" => Ok(WpsXMLElement::Wsp), + "cNvSpPr" => Ok(WpsXMLElement::CNvSpProperty), + "spPr" => Ok(WpsXMLElement::SpProperty), + "style" => Ok(WpsXMLElement::Style), + "txbx" => Ok(WpsXMLElement::Txbx), + "bodyPr" => Ok(WpsXMLElement::BodyPr), + _ => Ok(WpsXMLElement::Unsupported), + } + } +} + +impl FromStr for VXMLElement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "rect" => Ok(VXMLElement::Rect), + "stroke" => Ok(VXMLElement::Stroke), + "fill" => Ok(VXMLElement::Fill), + "textbox" => Ok(VXMLElement::TextBox), + _ => Ok(VXMLElement::Unsupported), + } + } +} + pub trait ElementReader { fn read(r: &mut EventReader, attrs: &[OwnedAttribute]) -> Result where diff --git a/docx-core/src/xml_builder/elements.rs b/docx-core/src/xml_builder/elements.rs index 5d928da..6b39a4a 100644 --- a/docx-core/src/xml_builder/elements.rs +++ b/docx-core/src/xml_builder/elements.rs @@ -216,6 +216,16 @@ impl XMLBuilder { closed_with_str!(level_justification, "w:lvlJc"); closed_with_str!(abstract_num_id, "w:abstractNumId"); closed!(vanish, "w:vanish"); + + open!(open_drawing, "w:drawing"); + open!(open_anchor, "wp:anchor"); + open!(open_graphic, "a:graphic", "xmlns:a"); + open!(open_graphic_data, "a:graphicData", "uri"); + + // shape + open!(open_wp_shape, "wps:wsp"); + open!(open_wp_text_box, "wps:txbx"); + open!(open_text_box_content, "w:txbxContent"); } #[cfg(test)] diff --git a/docx-core/tests/reader.rs b/docx-core/tests/reader.rs index a42ad52..37e7773 100644 --- a/docx-core/tests/reader.rs +++ b/docx-core/tests/reader.rs @@ -184,3 +184,18 @@ pub fn read_insert_table() { file.write_all(json.as_bytes()).unwrap(); file.flush().unwrap(); } + +#[test] +pub fn read_textbox() { + let mut file = File::open("../fixtures/textbox/textbox.docx").unwrap(); + let mut buf = vec![]; + file.read_to_end(&mut buf).unwrap(); + let json = read_docx(&buf).unwrap().json(); + + assert_debug_snapshot!(&json); + + let path = std::path::Path::new("./tests/output/textbox.json"); + let mut file = std::fs::File::create(&path).unwrap(); + file.write_all(json.as_bytes()).unwrap(); + file.flush().unwrap(); +} diff --git a/docx-core/tests/snapshots/lib__reader__read_textbox.snap b/docx-core/tests/snapshots/lib__reader__read_textbox.snap new file mode 100644 index 0000000..f999954 --- /dev/null +++ b/docx-core/tests/snapshots/lib__reader__read_textbox.snap @@ -0,0 +1,5 @@ +--- +source: docx-core/tests/reader.rs +expression: "&json" +--- +"{\n \"contentType\": {\n \"types\": {\n \"/_rels/.rels\": \"application/vnd.openxmlformats-package.relationships+xml\",\n \"/docProps/app.xml\": \"application/vnd.openxmlformats-officedocument.extended-properties+xml\",\n \"/docProps/core.xml\": \"application/vnd.openxmlformats-package.core-properties+xml\",\n \"/word/_rels/document.xml.rels\": \"application/vnd.openxmlformats-package.relationships+xml\",\n \"/word/comments.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml\",\n \"/word/document.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\",\n \"/word/fontTable.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\",\n \"/word/numbering.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml\",\n \"/word/settings.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\",\n \"/word/styles.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\"\n }\n },\n \"rels\": {\n \"rels\": [\n [\n \"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\",\n \"rId1\",\n \"docProps/core.xml\"\n ],\n [\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\",\n \"rId2\",\n \"docProps/app.xml\"\n ],\n [\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\",\n \"rId3\",\n \"word/document.xml\"\n ]\n ]\n },\n \"documentRels\": {\n \"hasComments\": false,\n \"hasNumberings\": false\n },\n \"docProps\": {\n \"app\": {},\n \"core\": {\n \"config\": {\n \"created\": null,\n \"creator\": null,\n \"description\": null,\n \"language\": null,\n \"lastModifiedBy\": null,\n \"modified\": null,\n \"revision\": null,\n \"subject\": null,\n \"title\": null\n }\n }\n },\n \"styles\": {\n \"docDefaults\": {\n \"runPropertyDefault\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n }\n }\n },\n \"styles\": [\n {\n \"styleId\": \"a\",\n \"name\": \"Normal\",\n \"styleType\": \"paragraph\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": \"both\",\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a0\",\n \"name\": \"Default Paragraph Font\",\n \"styleType\": \"character\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a1\",\n \"name\": \"Normal Table\",\n \"styleType\": \"table\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a2\",\n \"name\": \"No List\",\n \"styleType\": \"numbering\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n }\n ]\n },\n \"document\": {\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"drawing\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"anchor\",\n \"data\": {\n \"children\": [\n {\n \"children\": [\n {\n \"dataType\": \"wpShape\",\n \"children\": [\n {\n \"type\": \"shape\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"textbox\",\n \"data\": {\n \"children\": [\n {\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"H\"\n }\n }\n ]\n }\n },\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"ello\"\n }\n }\n ]\n }\n }\n ],\n \"property\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n },\n \"hasNumbering\": false,\n \"attrs\": []\n }\n }\n ],\n \"has_numbering\": false\n }\n ],\n \"hasNumbering\": false\n }\n }\n ]\n }\n }\n ]\n }\n ]\n }\n ]\n }\n }\n ]\n }\n },\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"H\"\n }\n }\n ]\n }\n },\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"ello\"\n }\n }\n ]\n }\n }\n ],\n \"property\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n },\n \"hasNumbering\": false,\n \"attrs\": []\n }\n }\n ],\n \"sectionProperty\": {\n \"pageSize\": {\n \"w\": 11906,\n \"h\": 16838\n },\n \"pageMargin\": {\n \"top\": 1985,\n \"left\": 1701,\n \"bottom\": 1701,\n \"right\": 1701,\n \"header\": 851,\n \"footer\": 992,\n \"gutter\": 0\n },\n \"columns\": 425,\n \"documentGrid\": 360\n },\n \"hasNumbering\": false\n },\n \"comments\": {\n \"comments\": []\n },\n \"numberings\": {\n \"abstractNums\": [],\n \"numberings\": []\n },\n \"settings\": {\n \"defaultTabStop\": 709,\n \"zoom\": 100\n },\n \"fontTable\": {}\n}" diff --git a/docx-core/tests/snapshots/reader__read_textbox.snap b/docx-core/tests/snapshots/reader__read_textbox.snap new file mode 100644 index 0000000..f999954 --- /dev/null +++ b/docx-core/tests/snapshots/reader__read_textbox.snap @@ -0,0 +1,5 @@ +--- +source: docx-core/tests/reader.rs +expression: "&json" +--- +"{\n \"contentType\": {\n \"types\": {\n \"/_rels/.rels\": \"application/vnd.openxmlformats-package.relationships+xml\",\n \"/docProps/app.xml\": \"application/vnd.openxmlformats-officedocument.extended-properties+xml\",\n \"/docProps/core.xml\": \"application/vnd.openxmlformats-package.core-properties+xml\",\n \"/word/_rels/document.xml.rels\": \"application/vnd.openxmlformats-package.relationships+xml\",\n \"/word/comments.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml\",\n \"/word/document.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\",\n \"/word/fontTable.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\",\n \"/word/numbering.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml\",\n \"/word/settings.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\",\n \"/word/styles.xml\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\"\n }\n },\n \"rels\": {\n \"rels\": [\n [\n \"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\",\n \"rId1\",\n \"docProps/core.xml\"\n ],\n [\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\",\n \"rId2\",\n \"docProps/app.xml\"\n ],\n [\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\",\n \"rId3\",\n \"word/document.xml\"\n ]\n ]\n },\n \"documentRels\": {\n \"hasComments\": false,\n \"hasNumberings\": false\n },\n \"docProps\": {\n \"app\": {},\n \"core\": {\n \"config\": {\n \"created\": null,\n \"creator\": null,\n \"description\": null,\n \"language\": null,\n \"lastModifiedBy\": null,\n \"modified\": null,\n \"revision\": null,\n \"subject\": null,\n \"title\": null\n }\n }\n },\n \"styles\": {\n \"docDefaults\": {\n \"runPropertyDefault\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n }\n }\n },\n \"styles\": [\n {\n \"styleId\": \"a\",\n \"name\": \"Normal\",\n \"styleType\": \"paragraph\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": \"both\",\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a0\",\n \"name\": \"Default Paragraph Font\",\n \"styleType\": \"character\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a1\",\n \"name\": \"Normal Table\",\n \"styleType\": \"table\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n },\n {\n \"styleId\": \"a2\",\n \"name\": \"No List\",\n \"styleType\": \"numbering\",\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"paragraphProperty\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n }\n }\n ]\n },\n \"document\": {\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"drawing\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"anchor\",\n \"data\": {\n \"children\": [\n {\n \"children\": [\n {\n \"dataType\": \"wpShape\",\n \"children\": [\n {\n \"type\": \"shape\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"textbox\",\n \"data\": {\n \"children\": [\n {\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"data\": {\n \"children\": [\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"H\"\n }\n }\n ]\n }\n },\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"ello\"\n }\n }\n ]\n }\n }\n ],\n \"property\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n },\n \"hasNumbering\": false,\n \"attrs\": []\n }\n }\n ],\n \"has_numbering\": false\n }\n ],\n \"hasNumbering\": false\n }\n }\n ]\n }\n }\n ]\n }\n ]\n }\n ]\n }\n }\n ]\n }\n },\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"H\"\n }\n }\n ]\n }\n },\n {\n \"type\": \"run\",\n \"data\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"children\": [\n {\n \"type\": \"text\",\n \"data\": {\n \"preserveSpace\": true,\n \"text\": \"ello\"\n }\n }\n ]\n }\n }\n ],\n \"property\": {\n \"runProperty\": {\n \"sz\": null,\n \"szCs\": null,\n \"color\": null,\n \"highlight\": null,\n \"underline\": null,\n \"bold\": null,\n \"boldCs\": null,\n \"italic\": null,\n \"italicCs\": null,\n \"vanish\": null\n },\n \"style\": \"Normal\",\n \"numberingProperty\": null,\n \"alignment\": null,\n \"indent\": null\n },\n \"hasNumbering\": false,\n \"attrs\": []\n }\n }\n ],\n \"sectionProperty\": {\n \"pageSize\": {\n \"w\": 11906,\n \"h\": 16838\n },\n \"pageMargin\": {\n \"top\": 1985,\n \"left\": 1701,\n \"bottom\": 1701,\n \"right\": 1701,\n \"header\": 851,\n \"footer\": 992,\n \"gutter\": 0\n },\n \"columns\": 425,\n \"documentGrid\": 360\n },\n \"hasNumbering\": false\n },\n \"comments\": {\n \"comments\": []\n },\n \"numberings\": {\n \"abstractNums\": [],\n \"numberings\": []\n },\n \"settings\": {\n \"defaultTabStop\": 709,\n \"zoom\": 100\n },\n \"fontTable\": {}\n}" diff --git a/docx-wasm/js/json/drawing.ts b/docx-wasm/js/json/drawing.ts new file mode 100644 index 0000000..fba538a --- /dev/null +++ b/docx-wasm/js/json/drawing.ts @@ -0,0 +1,44 @@ +import { TextBoxContentJSON } from "./textbox-content"; + +export type DrawingJSON = { + type: "drawing"; + data: { + children: DrawingChildJSON[]; + }; +}; + +export type DrawingChildJSON = WpAnchorJSON; + +export type WpAnchorJSON = { + type: "anchor"; + data: { + children: AGraphicJSON[]; + }; +}; + +export type AGraphicJSON = { + children: AGraphChildJSON[]; +}; + +export type AGraphChildJSON = AGraphicDataJSON; + +export type AGraphicDataJSON = { + dataType: "wpShape"; + children: WpsShapeJSON[]; +}; + +export type WpsShapeJSON = { + type: "shape"; + data: { + children: WpsShapeChildJSON[]; + }; +}; + +export type WpsShapeChildJSON = WpsTextBoxJSON; + +export type WpsTextBoxJSON = { + type: "textbox"; + data: { + children: TextBoxContentJSON[]; + }; +}; diff --git a/docx-wasm/js/json/index.ts b/docx-wasm/js/json/index.ts index 8376234..88dfd2f 100644 --- a/docx-wasm/js/json/index.ts +++ b/docx-wasm/js/json/index.ts @@ -48,3 +48,5 @@ export * from "./paragraph"; export * from "./run"; export * from "./table"; export * from "./numbering"; +export * from "./drawing"; +export * from "./textbox-content"; diff --git a/docx-wasm/js/json/run.ts b/docx-wasm/js/json/run.ts index 97159ab..63f4c47 100644 --- a/docx-wasm/js/json/run.ts +++ b/docx-wasm/js/json/run.ts @@ -1,3 +1,5 @@ +import { DrawingJSON } from "./drawing"; + export type RunPropertyJSON = { sz: number | null; szCs: number | null; @@ -11,7 +13,12 @@ export type RunPropertyJSON = { vanish: boolean | null; }; -export type RunChildJSON = TextJSON | DeleteTextJSON | TabJSON | BreakJSON; +export type RunChildJSON = + | TextJSON + | DeleteTextJSON + | TabJSON + | BreakJSON + | DrawingJSON; export type TextJSON = { type: "text"; diff --git a/docx-wasm/js/json/textbox-content.ts b/docx-wasm/js/json/textbox-content.ts new file mode 100644 index 0000000..c906b54 --- /dev/null +++ b/docx-wasm/js/json/textbox-content.ts @@ -0,0 +1,8 @@ +import { ParagraphJSON } from "./paragraph"; +import { TableJSON } from "./table"; + +export type TextBoxContentChildJSON = ParagraphJSON | TableJSON; + +export type TextBoxContentJSON = { + children: TextBoxContentChildJSON[]; +}; diff --git a/fixtures/header_footer/header_footer.docx b/fixtures/header_footer/header_footer.docx new file mode 100644 index 0000000..a2311a2 Binary files /dev/null and b/fixtures/header_footer/header_footer.docx differ diff --git a/fixtures/image/image.docx b/fixtures/image/image.docx new file mode 100644 index 0000000..5c8d79c Binary files /dev/null and b/fixtures/image/image.docx differ diff --git a/fixtures/image_node_docx/[Content_Types].xml b/fixtures/image_node_docx/[Content_Types].xml new file mode 100644 index 0000000..69b0cff --- /dev/null +++ b/fixtures/image_node_docx/[Content_Types].xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/_rels/.rels b/fixtures/image_node_docx/_rels/.rels new file mode 100644 index 0000000..3a89e29 --- /dev/null +++ b/fixtures/image_node_docx/_rels/.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/docProps/app.xml b/fixtures/image_node_docx/docProps/app.xml new file mode 100644 index 0000000..6d3e209 --- /dev/null +++ b/fixtures/image_node_docx/docProps/app.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/docProps/core.xml b/fixtures/image_node_docx/docProps/core.xml new file mode 100644 index 0000000..6b71073 --- /dev/null +++ b/fixtures/image_node_docx/docProps/core.xml @@ -0,0 +1 @@ +Un-namedUn-named12020-04-03T14:27:26Z2020-04-03T14:27:26Z \ No newline at end of file diff --git a/fixtures/image_node_docx/image.docx b/fixtures/image_node_docx/image.docx new file mode 100644 index 0000000..2c3f046 Binary files /dev/null and b/fixtures/image_node_docx/image.docx differ diff --git a/fixtures/image_node_docx/word/_rels/document.xml.rels b/fixtures/image_node_docx/word/_rels/document.xml.rels new file mode 100644 index 0000000..8b13378 --- /dev/null +++ b/fixtures/image_node_docx/word/_rels/document.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/_rels/footer1.xml.rels b/fixtures/image_node_docx/word/_rels/footer1.xml.rels new file mode 100644 index 0000000..ed9d666 --- /dev/null +++ b/fixtures/image_node_docx/word/_rels/footer1.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/_rels/header1.xml.rels b/fixtures/image_node_docx/word/_rels/header1.xml.rels new file mode 100644 index 0000000..ed9d666 --- /dev/null +++ b/fixtures/image_node_docx/word/_rels/header1.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/document.xml b/fixtures/image_node_docx/word/document.xml new file mode 100644 index 0000000..7207061 --- /dev/null +++ b/fixtures/image_node_docx/word/document.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/footer1.xml b/fixtures/image_node_docx/word/footer1.xml new file mode 100644 index 0000000..622cdc7 --- /dev/null +++ b/fixtures/image_node_docx/word/footer1.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/footnotes.xml b/fixtures/image_node_docx/word/footnotes.xml new file mode 100644 index 0000000..57efcdd --- /dev/null +++ b/fixtures/image_node_docx/word/footnotes.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/header1.xml b/fixtures/image_node_docx/word/header1.xml new file mode 100644 index 0000000..09f8e4b --- /dev/null +++ b/fixtures/image_node_docx/word/header1.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/media/2mhefq5b7fsoxmjaoiuyb.png b/fixtures/image_node_docx/word/media/2mhefq5b7fsoxmjaoiuyb.png new file mode 100644 index 0000000..9b8def5 Binary files /dev/null and b/fixtures/image_node_docx/word/media/2mhefq5b7fsoxmjaoiuyb.png differ diff --git a/fixtures/image_node_docx/word/media/40yrczdu6ohoeqs2cg2n4h.png b/fixtures/image_node_docx/word/media/40yrczdu6ohoeqs2cg2n4h.png new file mode 100644 index 0000000..9b8def5 Binary files /dev/null and b/fixtures/image_node_docx/word/media/40yrczdu6ohoeqs2cg2n4h.png differ diff --git a/fixtures/image_node_docx/word/media/oja94skc7s5oq9avc9zyf.png b/fixtures/image_node_docx/word/media/oja94skc7s5oq9avc9zyf.png new file mode 100644 index 0000000..9b8def5 Binary files /dev/null and b/fixtures/image_node_docx/word/media/oja94skc7s5oq9avc9zyf.png differ diff --git a/fixtures/image_node_docx/word/media/vpvf42pjbjmb5zjs1nsbb.png b/fixtures/image_node_docx/word/media/vpvf42pjbjmb5zjs1nsbb.png new file mode 100644 index 0000000..9b8def5 Binary files /dev/null and b/fixtures/image_node_docx/word/media/vpvf42pjbjmb5zjs1nsbb.png differ diff --git a/fixtures/image_node_docx/word/numbering.xml b/fixtures/image_node_docx/word/numbering.xml new file mode 100644 index 0000000..fc03be8 --- /dev/null +++ b/fixtures/image_node_docx/word/numbering.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/settings.xml b/fixtures/image_node_docx/word/settings.xml new file mode 100644 index 0000000..9202cef --- /dev/null +++ b/fixtures/image_node_docx/word/settings.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx/word/styles.xml b/fixtures/image_node_docx/word/styles.xml new file mode 100644 index 0000000..c554fb3 --- /dev/null +++ b/fixtures/image_node_docx/word/styles.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/[Content_Types].xml b/fixtures/image_node_docx_floating/[Content_Types].xml new file mode 100644 index 0000000..69b0cff --- /dev/null +++ b/fixtures/image_node_docx_floating/[Content_Types].xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/_rels/.rels b/fixtures/image_node_docx_floating/_rels/.rels new file mode 100644 index 0000000..3a89e29 --- /dev/null +++ b/fixtures/image_node_docx_floating/_rels/.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/docProps/app.xml b/fixtures/image_node_docx_floating/docProps/app.xml new file mode 100644 index 0000000..6d3e209 --- /dev/null +++ b/fixtures/image_node_docx_floating/docProps/app.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/docProps/core.xml b/fixtures/image_node_docx_floating/docProps/core.xml new file mode 100644 index 0000000..4e39bf2 --- /dev/null +++ b/fixtures/image_node_docx_floating/docProps/core.xml @@ -0,0 +1 @@ +Un-namedUn-named12020-04-03T14:27:42Z2020-04-03T14:27:42Z \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/image.docx b/fixtures/image_node_docx_floating/image.docx new file mode 100644 index 0000000..ff059d3 Binary files /dev/null and b/fixtures/image_node_docx_floating/image.docx differ diff --git a/fixtures/image_node_docx_floating/word/_rels/document.xml.rels b/fixtures/image_node_docx_floating/word/_rels/document.xml.rels new file mode 100644 index 0000000..283d56f --- /dev/null +++ b/fixtures/image_node_docx_floating/word/_rels/document.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/_rels/footer1.xml.rels b/fixtures/image_node_docx_floating/word/_rels/footer1.xml.rels new file mode 100644 index 0000000..ed9d666 --- /dev/null +++ b/fixtures/image_node_docx_floating/word/_rels/footer1.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/_rels/header1.xml.rels b/fixtures/image_node_docx_floating/word/_rels/header1.xml.rels new file mode 100644 index 0000000..ed9d666 --- /dev/null +++ b/fixtures/image_node_docx_floating/word/_rels/header1.xml.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/document.xml b/fixtures/image_node_docx_floating/word/document.xml new file mode 100644 index 0000000..262fd8c --- /dev/null +++ b/fixtures/image_node_docx_floating/word/document.xml @@ -0,0 +1,77 @@ + + + + + + + + + 1014400 + + + 1014400 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/footer1.xml b/fixtures/image_node_docx_floating/word/footer1.xml new file mode 100644 index 0000000..622cdc7 --- /dev/null +++ b/fixtures/image_node_docx_floating/word/footer1.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/footnotes.xml b/fixtures/image_node_docx_floating/word/footnotes.xml new file mode 100644 index 0000000..57efcdd --- /dev/null +++ b/fixtures/image_node_docx_floating/word/footnotes.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/header1.xml b/fixtures/image_node_docx_floating/word/header1.xml new file mode 100644 index 0000000..09f8e4b --- /dev/null +++ b/fixtures/image_node_docx_floating/word/header1.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/media/dy29bt3j1idb692k2uzxlj.png b/fixtures/image_node_docx_floating/word/media/dy29bt3j1idb692k2uzxlj.png new file mode 100644 index 0000000..9b8def5 Binary files /dev/null and b/fixtures/image_node_docx_floating/word/media/dy29bt3j1idb692k2uzxlj.png differ diff --git a/fixtures/image_node_docx_floating/word/numbering.xml b/fixtures/image_node_docx_floating/word/numbering.xml new file mode 100644 index 0000000..fc03be8 --- /dev/null +++ b/fixtures/image_node_docx_floating/word/numbering.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/settings.xml b/fixtures/image_node_docx_floating/word/settings.xml new file mode 100644 index 0000000..9202cef --- /dev/null +++ b/fixtures/image_node_docx_floating/word/settings.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_floating/word/styles.xml b/fixtures/image_node_docx_floating/word/styles.xml new file mode 100644 index 0000000..c554fb3 --- /dev/null +++ b/fixtures/image_node_docx_floating/word/styles.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/image_node_docx_relative/image.docx b/fixtures/image_node_docx_relative/image.docx new file mode 100644 index 0000000..4f7b097 Binary files /dev/null and b/fixtures/image_node_docx_relative/image.docx differ diff --git a/fixtures/table_valign/table_valign.docx b/fixtures/table_valign/table_valign.docx new file mode 100644 index 0000000..1bc0a27 Binary files /dev/null and b/fixtures/table_valign/table_valign.docx differ diff --git a/fixtures/textbox/[Content_Types].xml b/fixtures/textbox/[Content_Types].xml new file mode 100644 index 0000000..cc92235 --- /dev/null +++ b/fixtures/textbox/[Content_Types].xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/_rels/.rels b/fixtures/textbox/_rels/.rels new file mode 100644 index 0000000..fdd8c4f --- /dev/null +++ b/fixtures/textbox/_rels/.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/customXml/_rels/item1.xml.rels b/fixtures/textbox/customXml/_rels/item1.xml.rels new file mode 100644 index 0000000..a9c831d --- /dev/null +++ b/fixtures/textbox/customXml/_rels/item1.xml.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/customXml/item1.xml b/fixtures/textbox/customXml/item1.xml new file mode 100644 index 0000000..628e94b --- /dev/null +++ b/fixtures/textbox/customXml/item1.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fixtures/textbox/customXml/itemProps1.xml b/fixtures/textbox/customXml/itemProps1.xml new file mode 100644 index 0000000..ac511d4 --- /dev/null +++ b/fixtures/textbox/customXml/itemProps1.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/docProps/app.xml b/fixtures/textbox/docProps/app.xml new file mode 100644 index 0000000..f549f6c --- /dev/null +++ b/fixtures/textbox/docProps/app.xml @@ -0,0 +1,2 @@ + +1101Microsoft Office Word011falsefalse1falsefalse16.0000 \ No newline at end of file diff --git a/fixtures/textbox/docProps/core.xml b/fixtures/textbox/docProps/core.xml new file mode 100644 index 0000000..13ceaea --- /dev/null +++ b/fixtures/textbox/docProps/core.xml @@ -0,0 +1,2 @@ + +Ueki SatoshiUeki Satoshi12020-04-03T09:10:00Z2020-04-03T09:11:00Z \ No newline at end of file diff --git a/fixtures/textbox/textbox.docx b/fixtures/textbox/textbox.docx new file mode 100644 index 0000000..384e075 Binary files /dev/null and b/fixtures/textbox/textbox.docx differ diff --git a/fixtures/textbox/word/_rels/document.xml.rels b/fixtures/textbox/word/_rels/document.xml.rels new file mode 100644 index 0000000..b08d1fb --- /dev/null +++ b/fixtures/textbox/word/_rels/document.xml.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/word/document.xml b/fixtures/textbox/word/document.xml new file mode 100644 index 0000000..30eda42 --- /dev/null +++ b/fixtures/textbox/word/document.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + 608965 + + + 695325 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H + + + ello + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H + + + ello + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fixtures/textbox/word/fontTable.xml b/fixtures/textbox/word/fontTable.xml new file mode 100644 index 0000000..2b0b360 --- /dev/null +++ b/fixtures/textbox/word/fontTable.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/word/settings.xml b/fixtures/textbox/word/settings.xml new file mode 100644 index 0000000..d355497 --- /dev/null +++ b/fixtures/textbox/word/settings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/word/styles.xml b/fixtures/textbox/word/styles.xml new file mode 100644 index 0000000..083ad28 --- /dev/null +++ b/fixtures/textbox/word/styles.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/word/theme/theme1.xml b/fixtures/textbox/word/theme/theme1.xml new file mode 100644 index 0000000..96a4237 --- /dev/null +++ b/fixtures/textbox/word/theme/theme1.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fixtures/textbox/word/webSettings.xml b/fixtures/textbox/word/webSettings.xml new file mode 100644 index 0000000..55b7e9d --- /dev/null +++ b/fixtures/textbox/word/webSettings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file