umya_spreadsheet/structs/
ole_object.rs

1use super::EmbeddedObjectProperties;
2use super::StringValue;
3use crate::helper::const_str::MC_NS;
4use crate::reader::driver::*;
5use crate::structs::drawing::spreadsheet::TwoCellAnchor;
6use crate::structs::raw::RawRelationships;
7use crate::structs::vml::Shape;
8use crate::writer::driver::*;
9use quick_xml::events::{BytesStart, Event};
10use quick_xml::Reader;
11use quick_xml::Writer;
12use std::io::Cursor;
13use thin_vec::ThinVec;
14
15#[derive(Clone, Default, Debug)]
16pub struct OleObject {
17    requires: StringValue,
18    prog_id: StringValue,
19    object_extension: Box<str>,
20    object_data: Option<ThinVec<u8>>,
21    embedded_object_properties: EmbeddedObjectProperties,
22    two_cell_anchor: TwoCellAnchor,
23    shape: Shape,
24}
25
26impl OleObject {
27    #[inline]
28    pub fn get_requires(&self) -> &str {
29        self.requires.get_value_str()
30    }
31
32    #[inline]
33    pub fn set_requires<S: Into<String>>(&mut self, value: S) -> &mut Self {
34        self.requires.set_value(value);
35        self
36    }
37
38    #[inline]
39    pub fn get_prog_id(&self) -> &str {
40        self.prog_id.get_value_str()
41    }
42
43    #[inline]
44    pub fn set_prog_id<S: Into<String>>(&mut self, value: S) -> &mut Self {
45        self.prog_id.set_value(value);
46        self
47    }
48
49    #[inline]
50    pub fn get_object_extension(&self) -> &str {
51        &self.object_extension
52    }
53
54    #[inline]
55    pub fn set_object_extension<S: Into<String>>(&mut self, value: S) {
56        self.object_extension = value.into().into_boxed_str();
57    }
58
59    #[inline]
60    pub fn get_object_data(&self) -> Option<&[u8]> {
61        self.object_data.as_deref()
62    }
63
64    #[inline]
65    pub fn get_object_data_mut(&mut self) -> Option<&mut ThinVec<u8>> {
66        self.object_data.as_mut()
67    }
68
69    #[inline]
70    pub fn set_object_data(&mut self, value: impl Into<ThinVec<u8>>) -> &mut Self {
71        self.object_data = Some(value.into());
72        self
73    }
74
75    #[inline]
76    pub fn get_embedded_object_properties(&self) -> &EmbeddedObjectProperties {
77        &self.embedded_object_properties
78    }
79
80    #[inline]
81    pub fn get_embedded_object_properties_mut(&mut self) -> &mut EmbeddedObjectProperties {
82        &mut self.embedded_object_properties
83    }
84
85    #[inline]
86    pub fn set_embedded_object_properties(&mut self, value: EmbeddedObjectProperties) -> &mut Self {
87        self.embedded_object_properties = value;
88        self
89    }
90
91    #[inline]
92    pub fn get_two_cell_anchor(&self) -> &TwoCellAnchor {
93        &self.two_cell_anchor
94    }
95
96    #[inline]
97    pub fn get_two_cell_anchor_mut(&mut self) -> &mut TwoCellAnchor {
98        &mut self.two_cell_anchor
99    }
100
101    #[inline]
102    pub fn set_two_cell_anchor(&mut self, value: TwoCellAnchor) -> &mut Self {
103        self.two_cell_anchor = value;
104        self
105    }
106
107    #[inline]
108    pub fn get_shape(&self) -> &Shape {
109        &self.shape
110    }
111
112    #[inline]
113    pub fn get_shape_mut(&mut self) -> &mut Shape {
114        &mut self.shape
115    }
116
117    #[inline]
118    pub fn set_shape(&mut self, value: Shape) -> &mut Self {
119        self.shape = value;
120        self
121    }
122
123    #[inline]
124    pub(crate) fn is_bin(&self) -> bool {
125        &*self.object_extension == "bin"
126    }
127
128    #[inline]
129    pub(crate) fn is_xlsx(&self) -> bool {
130        &*self.object_extension == "xlsx"
131    }
132
133    pub(crate) fn set_attributes<R: std::io::BufRead>(
134        &mut self,
135        reader: &mut Reader<R>,
136        _e: &BytesStart,
137        relationships: &RawRelationships,
138    ) {
139        let mut alternate_content: &str = "";
140
141        xml_read_loop!(
142            reader,
143            Event::Start(ref e) => {
144                match e.name().into_inner() {
145                    b"mc:Choice" => {
146                        alternate_content = "Choice";
147                        set_string_from_xml!(self, e, requires, "Requires");
148                    }
149                    b"mc:Fallback" => {
150                        alternate_content = "Fallback";
151                    }
152                    b"oleObject" => {
153                        if alternate_content == "Choice" {
154                            self.prog_id
155                                .set_value_string(get_attribute(e, b"progId").unwrap());
156
157                            let r_id = get_attribute(e, b"r:id").unwrap();
158                            let attached_file =
159                                relationships.get_relationship_by_rid(&r_id).get_raw_file();
160                            self.set_object_extension(attached_file.get_extension());
161                            self.set_object_data(attached_file.get_file_data().clone());
162                        }
163                    }
164                    b"objectPr" => {
165                        let mut obj = EmbeddedObjectProperties::default();
166                        obj.set_attributes(reader, e, relationships);
167                        self.set_embedded_object_properties(obj);
168                    }
169                    _ => (),
170                }
171            },
172            Event::End(ref e) => {
173                if e.name().into_inner() == b"mc:AlternateContent" {
174                    return
175                }
176            },
177            Event::Eof => panic!("Error: Could not find {} end element", "mc:AlternateContent")
178        );
179    }
180
181    pub(crate) fn write_to(
182        &self,
183        writer: &mut Writer<Cursor<Vec<u8>>>,
184        r_id: &usize,
185        ole_id: &usize,
186    ) {
187        // mc:AlternateContent
188        write_start_tag(
189            writer,
190            "mc:AlternateContent",
191            vec![("xmlns:mc", MC_NS)],
192            false,
193        );
194
195        // mc:Choice
196        write_start_tag(
197            writer,
198            "mc:Choice",
199            vec![("Requires", self.requires.get_value_str())],
200            false,
201        );
202
203        // oleObject
204        let r_id_str = format!("rId{}", r_id);
205        let shape_id_str = format!("{}", ole_id);
206        let attributes = vec![
207            ("progId", self.prog_id.get_value_str()),
208            ("shapeId", &shape_id_str),
209            ("r:id", &r_id_str),
210        ];
211        write_start_tag(writer, "oleObject", attributes, false);
212
213        // objectPr
214        self.embedded_object_properties
215            .write_to(writer, &(r_id + 1));
216
217        write_end_tag(writer, "oleObject");
218
219        write_end_tag(writer, "mc:Choice");
220
221        // mc:Fallback
222        write_start_tag(writer, "mc:Fallback", vec![], false);
223
224        // oleObject
225        let r_id_str = format!("rId{}", r_id);
226        let attributes = vec![
227            ("progId", self.prog_id.get_value_str()),
228            ("shapeId", &shape_id_str),
229            ("r:id", &r_id_str),
230        ];
231        write_start_tag(writer, "oleObject", attributes, true);
232
233        write_end_tag(writer, "mc:Fallback");
234
235        write_end_tag(writer, "mc:AlternateContent");
236    }
237}