umya_spreadsheet/structs/
writer_manager.rs

1use crate::helper::const_str::*;
2use crate::structs::Spreadsheet;
3use crate::structs::XlsxError;
4use crate::writer::driver::*;
5use quick_xml::Writer;
6use std::io;
7use std::io::Cursor;
8pub struct WriterManager<'a, W: io::Seek + io::Write> {
9    files: Vec<String>,
10    arv: &'a mut zip::ZipWriter<W>,
11    is_light: bool,
12    table_no: i32,
13}
14
15impl<'a, W: io::Seek + io::Write> WriterManager<'a, W> {
16    #[inline]
17    pub fn new(arv: &'a mut zip::ZipWriter<W>) -> Self {
18        WriterManager {
19            files: Vec::new(),
20            arv,
21            is_light: false,
22            table_no: 0,
23        }
24    }
25
26    #[inline]
27    pub fn set_is_light(&mut self, value: bool) -> &mut Self {
28        self.is_light = value;
29        self
30    }
31
32    #[inline]
33    pub fn get_is_light(&self) -> &bool {
34        &self.is_light
35    }
36
37    #[inline]
38    pub fn get_num_tables(&self) -> i32 {
39        self.table_no
40    }
41
42    #[inline]
43    pub fn next_table_no(&mut self) -> i32 {
44        self.table_no += 1;
45        self.table_no
46    }
47
48    #[inline]
49    pub(crate) fn add_writer(
50        &mut self,
51        target: &str,
52        writer: Writer<Cursor<Vec<u8>>>,
53    ) -> Result<(), XlsxError> {
54        if !self.check_file_exist(target) {
55            make_file_from_writer(target, self.arv, writer, None, &self.is_light)?;
56            self.files.push(target.to_string());
57        }
58        Ok(())
59    }
60
61    #[inline]
62    pub(crate) fn add_bin(&mut self, target: &str, data: &[u8]) -> Result<(), XlsxError> {
63        if !self.check_file_exist(target) {
64            make_file_from_bin(target, &mut self.arv, data, None, &self.is_light)?;
65            self.files.push(target.to_string());
66        }
67        Ok(())
68    }
69
70    #[inline]
71    pub(crate) fn get_arv_mut(&mut self) -> &mut zip::ZipWriter<W> {
72        &mut self.arv
73    }
74
75    #[inline]
76    pub(crate) fn file_list_sort(&mut self) -> &mut Self {
77        self.files.sort();
78        self
79    }
80
81    #[inline]
82    pub(crate) fn check_file_exist(&mut self, file_path: &str) -> bool {
83        self.file_list_sort();
84        self.files.iter().any(|file| file == file_path)
85    }
86
87    pub(crate) fn add_file_at_drawing(
88        &mut self,
89        writer: Writer<Cursor<Vec<u8>>>,
90    ) -> Result<i32, XlsxError> {
91        let mut index = 0;
92        loop {
93            index += 1;
94            let file_path = format!("{}/drawing{}.xml", PKG_DRAWINGS, index);
95            if !self.check_file_exist(&file_path) {
96                self.add_writer(&file_path, writer)?;
97                return Ok(index);
98            }
99        }
100    }
101
102    pub(crate) fn add_file_at_vml_drawing(
103        &mut self,
104        writer: Writer<Cursor<Vec<u8>>>,
105    ) -> Result<i32, XlsxError> {
106        let mut index = 0;
107        loop {
108            index += 1;
109            let file_path = format!("{}/vmlDrawing{}.vml", PKG_DRAWINGS, index);
110            if !self.check_file_exist(&file_path) {
111                self.add_writer(&file_path, writer)?;
112                return Ok(index);
113            }
114        }
115    }
116
117    pub(crate) fn add_file_at_comment(
118        &mut self,
119        writer: Writer<Cursor<Vec<u8>>>,
120    ) -> Result<i32, XlsxError> {
121        let mut index = 0;
122        loop {
123            index += 1;
124            let file_path = format!("xl/comments{}.xml", index);
125            if !self.check_file_exist(&file_path) {
126                self.add_writer(&file_path, writer)?;
127                return Ok(index);
128            }
129        }
130    }
131
132    pub(crate) fn add_file_at_threaded_comment(
133        &mut self,
134        writer: Writer<Cursor<Vec<u8>>>,
135    ) -> Result<i32, XlsxError> {
136        let mut index = 0;
137        loop {
138            index += 1;
139            let file_path = format!("xl/threadedComments/threadedComment{}.xml", index);
140            if !self.check_file_exist(&file_path) {
141                self.add_writer(&file_path, writer)?;
142                return Ok(index);
143            }
144        }
145    }
146
147    pub(crate) fn add_file_at_chart(
148        &mut self,
149        writer: Writer<Cursor<Vec<u8>>>,
150    ) -> Result<i32, XlsxError> {
151        let mut index = 0;
152        loop {
153            index += 1;
154            let file_path = format!("{}/chart{}.xml", PKG_CHARTS, index);
155            if !self.check_file_exist(&file_path) {
156                self.add_writer(&file_path, writer)?;
157                return Ok(index);
158            }
159        }
160    }
161
162    pub(crate) fn add_file_at_ole_object(&mut self, writer: &[u8]) -> Result<i32, XlsxError> {
163        let mut index = 0;
164        loop {
165            index += 1;
166            let file_path = format!("{}/oleObject{}.bin", PKG_EMBEDDINGS, index);
167            if !self.check_file_exist(&file_path) {
168                self.add_bin(&file_path, writer)?;
169                return Ok(index);
170            }
171        }
172    }
173
174    pub(crate) fn add_file_at_excel(&mut self, writer: &[u8]) -> Result<i32, XlsxError> {
175        let mut index = 0;
176        loop {
177            index += 1;
178            let file_path = format!("{}/Microsoft_Excel_Worksheet{}.xlsx", PKG_EMBEDDINGS, index);
179            if !self.check_file_exist(&file_path) {
180                self.add_bin(&file_path, writer)?;
181                return Ok(index);
182            }
183        }
184    }
185
186    pub(crate) fn add_file_at_printer_settings(&mut self, writer: &[u8]) -> Result<i32, XlsxError> {
187        let mut index = 0;
188        loop {
189            index += 1;
190            let file_path = format!("{}/printerSettings{}.bin", PKG_PRNTR_SETTINGS, index);
191            if !self.check_file_exist(&file_path) {
192                self.add_bin(&file_path, writer)?;
193                return Ok(index);
194            }
195        }
196    }
197
198    #[inline]
199    pub(crate) fn add_file_at_table(
200        &mut self,
201        writer: Writer<Cursor<Vec<u8>>>,
202        table_no: i32,
203    ) -> Result<i32, XlsxError> {
204        let file_path = format!("{}/table{}.xml", PKG_TABLES, table_no);
205        self.add_writer(&file_path, writer)?;
206        return Ok(table_no);
207    }
208
209    #[inline]
210    pub(crate) fn has_extension(&self, extension: &str) -> bool {
211        let extension = format!(".{}", extension);
212        self.files.iter().any(|file| file.ends_with(&extension))
213    }
214
215    pub(crate) fn make_context_type_override(
216        &mut self,
217        spreadsheet: &Spreadsheet,
218    ) -> Vec<(String, String)> {
219        self.file_list_sort();
220
221        let mut list: Vec<(String, String)> = Vec::new();
222        for file in &self.files {
223            let file = format!("/{}", file);
224            let mut content_type = "";
225
226            // Override workbook
227            if file.starts_with("/xl/workbook.xml") {
228                content_type = match spreadsheet.get_has_macros() {
229                    true => WORKBOOK_MACRO_TYPE,
230                    false => WORKBOOK_TYPE,
231                };
232            }
233
234            // Override sheet
235            if file.starts_with("/xl/worksheets/sheet") {
236                content_type = SHEET_TYPE;
237            }
238
239            // Override table
240            if file.starts_with("/xl/tables/table") {
241                content_type = TABLE_TYPE;
242            }
243
244            // Override comments
245            if file.starts_with("/xl/comments") {
246                content_type = COMMENTS_TYPE;
247            }
248
249            // Override theme
250            if file.starts_with("/xl/theme/theme") {
251                content_type = THEME_TYPE;
252            }
253
254            // Override styles
255            if file.starts_with("/xl/styles.xml") {
256                content_type = STYLES_TYPE;
257            }
258
259            // Override sharedStrings
260            if file.starts_with("/xl/sharedStrings.xml") {
261                content_type = SHARED_STRINGS_TYPE;
262            }
263
264            // Override drawing
265            if file.starts_with("/xl/drawings/drawing") {
266                content_type = DRAWING_TYPE;
267            }
268
269            // Override chart
270            if file.starts_with("/xl/charts/chart") {
271                content_type = CHART_TYPE;
272            }
273
274            // Override embeddings
275            if file.starts_with("/xl/embeddings/oleObject") {
276                content_type = OLE_OBJECT_TYPE;
277            }
278
279            // Override xl/vbaProject.bin
280            if file.starts_with("/xl/vbaProject.bin") {
281                content_type = VBA_TYPE;
282            }
283
284            // Override docProps/core
285            if file.starts_with("/docProps/core.xml") {
286                content_type = CORE_PROPS_TYPE;
287            }
288
289            // Override docProps/app
290            if file.starts_with("/docProps/app.xml") {
291                content_type = XPROPS_TYPE;
292            }
293
294            // Override docProps/custom
295            if file.starts_with("/docProps/custom.xml") {
296                content_type = CUSTOM_PROPS_TYPE;
297            }
298
299            // Override Unsupported
300            if content_type.is_empty() {
301                for (old_part_name, old_content_type) in spreadsheet.get_backup_context_types() {
302                    if &**old_part_name == &file {
303                        content_type = old_content_type;
304                    }
305                }
306            }
307
308            if !content_type.is_empty() {
309                list.push((file, content_type.to_string()));
310            }
311        }
312        list
313    }
314}