umya_spreadsheet/writer/
xlsx.rs

1use super::driver;
2use crate::helper::crypt::*;
3use crate::structs::Spreadsheet;
4use crate::structs::WriterManager;
5use crate::XlsxError;
6use std::fmt;
7use std::fs;
8use std::fs::File;
9use std::io;
10use std::io::Read;
11use std::io::Write;
12use std::path::Path;
13use std::string::FromUtf8Error;
14
15mod chart;
16mod comment;
17mod content_types;
18mod doc_props_app;
19mod doc_props_core;
20mod doc_props_custom;
21mod drawing;
22mod drawing_rels;
23mod embeddings;
24mod jsa_project_bin;
25mod media;
26mod person;
27mod printer_settings;
28mod rels;
29mod shared_strings;
30mod styles;
31mod table;
32mod theme;
33mod threaded_comment;
34mod vba_project_bin;
35mod vml_drawing;
36mod vml_drawing_rels;
37mod workbook;
38mod workbook_rels;
39mod worksheet;
40mod worksheet_rels;
41
42fn make_buffer(spreadsheet: &Spreadsheet, is_light: bool) -> Result<std::vec::Vec<u8>, XlsxError> {
43    let mut arv = zip::ZipWriter::new(std::io::Cursor::new(Vec::new()));
44    let mut writer_manager = WriterManager::new(&mut arv);
45    writer_manager.set_is_light(is_light);
46
47    // Add docProps App
48    doc_props_app::write(spreadsheet, &mut writer_manager)?;
49
50    // Add docProps Core
51    doc_props_core::write(spreadsheet, &mut writer_manager)?;
52
53    // Add docProps Custom
54    doc_props_custom::write(spreadsheet, &mut writer_manager)?;
55
56    // Add vbaProject.bin
57    vba_project_bin::write(spreadsheet, &mut writer_manager)?;
58
59    // Add jsaProject.bin
60    jsa_project_bin::write(spreadsheet, &mut writer_manager)?;
61
62    // Add relationships
63    rels::write(spreadsheet, &mut writer_manager)?;
64
65    // Add theme
66    theme::write(spreadsheet.get_theme(), &mut writer_manager)?;
67
68    // Add persion
69    person::write(spreadsheet, &mut writer_manager)?;
70
71    // worksheet
72    let shared_string_table = spreadsheet.get_shared_string_table();
73    let mut stylesheet = spreadsheet.get_stylesheet().clone();
74    let mut worksheet_no = 1;
75    for worksheet in spreadsheet.get_sheet_collection_no_check() {
76        if worksheet.is_deserialized() {
77            // from deserialized.
78            worksheet::write(
79                &worksheet_no,
80                worksheet,
81                &shared_string_table,
82                &mut stylesheet,
83                spreadsheet.get_has_macros(),
84                &mut writer_manager,
85            )?;
86        } else {
87            // from no deserialized.
88            worksheet
89                .get_raw_data_of_worksheet()
90                .write(&worksheet_no, &mut writer_manager)?;
91        }
92        worksheet_no += 1;
93    }
94
95    // Objects associated with worksheets
96    let mut worksheet_no = 0;
97    for worksheet in spreadsheet.get_sheet_collection_no_check() {
98        worksheet_no += 1;
99        if !worksheet.is_deserialized() {
100            continue;
101        }
102
103        // from deserialized.
104        // Add charts
105        let mut chart_no_list: Vec<String> = Vec::new();
106        for chart in worksheet.get_worksheet_drawing().get_chart_collection() {
107            let chart_space = chart.get_chart_space();
108            let chart_no = chart::write(chart_space, spreadsheet, &mut writer_manager)?;
109            chart_no_list.push(chart_no);
110        }
111
112        // Add drawing
113        let (drawing_no, rel_list) = drawing::write(worksheet, &mut writer_manager)?;
114
115        // Add drawing rels
116        drawing_rels::write(
117            worksheet,
118            &drawing_no,
119            &chart_no_list,
120            &rel_list,
121            &mut writer_manager,
122        )?;
123
124        // Add vml drawing
125        let (vml_drawing_no, rel_list) = vml_drawing::write(worksheet, &mut writer_manager)?;
126
127        // Add vml drawing rels
128        vml_drawing_rels::write(worksheet, &vml_drawing_no, &rel_list, &mut writer_manager)?;
129
130        // Add comment
131        let comment_no = comment::write(worksheet, &mut writer_manager)?;
132
133        // Add threaded_comment
134        let threaded_comment_no = threaded_comment::write(worksheet, &mut writer_manager)?;
135
136        // Add ole_object and excel
137        let (ole_object_no_list, excel_no_list) =
138            embeddings::write(worksheet, &mut writer_manager)?;
139
140        // Add Media
141        media::write(worksheet, &mut writer_manager)?;
142
143        // Add printer_settings
144        let printer_settings_no = match worksheet.get_page_setup().get_object_data() {
145            Some(_) => printer_settings::write(worksheet, &mut writer_manager)?,
146            None => String::new(),
147        };
148
149        // Add tables
150        let table_no_list = table::write(worksheet, &mut writer_manager)?;
151
152        // Add worksheet rels
153        worksheet_rels::write(
154            worksheet,
155            &worksheet_no.to_string(),
156            &drawing_no,
157            &vml_drawing_no,
158            &comment_no,
159            &threaded_comment_no,
160            &ole_object_no_list,
161            &excel_no_list,
162            &printer_settings_no,
163            &table_no_list,
164            &mut writer_manager,
165        )?;
166    }
167
168    // file list sort
169    writer_manager.file_list_sort();
170
171    // Add SharedStrings
172    shared_strings::write(&shared_string_table, &mut writer_manager)?;
173
174    // Add Styles
175    styles::write(&stylesheet, &mut writer_manager)?;
176
177    // Add workbook
178    workbook::write(spreadsheet, &mut writer_manager)?;
179
180    // Add workbook relationships
181    let has_shared_string_table = shared_string_table.read().unwrap().has_value();
182    workbook_rels::write(spreadsheet, has_shared_string_table, &mut writer_manager)?;
183
184    // Add Content_Types
185    content_types::write(spreadsheet, &mut writer_manager)?;
186
187    Ok(arv.finish()?.into_inner())
188}
189
190/// write spreadsheet file to arbitrary writer.
191/// # Arguments
192/// * `spreadsheet` - Spreadsheet structs object.
193/// * `writer` - writer to write to.
194/// # Return value
195/// * `Result` - OK is void. Err is error message.
196#[inline]
197pub fn write_writer<W: io::Write>(
198    spreadsheet: &Spreadsheet,
199    mut writer: W,
200) -> Result<(), XlsxError> {
201    let buffer = make_buffer(spreadsheet, false)?;
202    writer.write_all(&buffer)?;
203    Ok(())
204}
205
206/// write spreadsheet file to arbitrary writer.
207/// # Arguments
208/// * `spreadsheet` - Spreadsheet structs object.
209/// * `writer` - writer to write to.
210/// # Return value
211/// * `Result` - OK is void. Err is error message.
212#[inline]
213pub fn write_writer_light<W: io::Write>(
214    spreadsheet: &Spreadsheet,
215    mut writer: W,
216) -> Result<(), XlsxError> {
217    let buffer = make_buffer(spreadsheet, true)?;
218    writer.write_all(&buffer)?;
219    Ok(())
220}
221
222/// write spreadsheet file.
223/// # Arguments
224/// * `spreadsheet` - Spreadsheet structs object.
225/// * `path` - file path to save.
226/// # Return value
227/// * `Result` - OK is void. Err is error message.
228/// # Examples
229/// ```
230/// let mut book = umya_spreadsheet::new_file();
231/// let path = std::path::Path::new("./tests/result_files/zzz.xlsx");
232/// let _ = umya_spreadsheet::writer::xlsx::write(&book, path);
233/// ```
234pub fn write<P: AsRef<Path>>(spreadsheet: &Spreadsheet, path: P) -> Result<(), XlsxError> {
235    let extension = path.as_ref().extension().unwrap().to_str().unwrap();
236    let path_tmp = path
237        .as_ref()
238        .with_extension(format!("{}{}", extension, "tmp"));
239    if let Err(v) = write_writer(
240        spreadsheet,
241        &mut io::BufWriter::new(fs::File::create(&path_tmp)?),
242    ) {
243        fs::remove_file(path_tmp)?;
244        return Err(v);
245    }
246    fs::rename(path_tmp, path)?;
247    Ok(())
248}
249
250/// write spreadsheet file.
251/// # Arguments
252/// * `spreadsheet` - Spreadsheet structs object.
253/// * `path` - file path to save.
254/// # Return value
255/// * `Result` - OK is void. Err is error message.
256/// # Examples
257/// ```
258/// let mut book = umya_spreadsheet::new_file();
259/// let path = std::path::Path::new("./tests/result_files/zzz.xlsx");
260/// let _ = umya_spreadsheet::writer::xlsx::write_light(&book, path);
261/// ```
262pub fn write_light<P: AsRef<Path>>(spreadsheet: &Spreadsheet, path: P) -> Result<(), XlsxError> {
263    let extension = path.as_ref().extension().unwrap().to_str().unwrap();
264    let path_tmp = path
265        .as_ref()
266        .with_extension(format!("{}{}", extension, "tmp"));
267    if let Err(v) = write_writer_light(
268        spreadsheet,
269        &mut io::BufWriter::new(fs::File::create(&path_tmp)?),
270    ) {
271        fs::remove_file(path_tmp)?;
272        return Err(v);
273    }
274    fs::rename(path_tmp, path)?;
275    Ok(())
276}
277
278/// write spreadsheet file with password.
279/// # Arguments
280/// * `spreadsheet` - Spreadsheet structs object.
281/// * `path` - file path to save.
282/// * `password` - password.
283/// # Return value
284/// * `Result` - OK is void. Err is error message.
285/// # Examples
286/// ```
287/// let mut book = umya_spreadsheet::new_file();
288/// let path = std::path::Path::new("./tests/result_files/zzz_password.xlsx");
289/// let _ = umya_spreadsheet::writer::xlsx::write_with_password(&book, path, "password");
290/// ```
291pub fn write_with_password<P: AsRef<Path>>(
292    spreadsheet: &Spreadsheet,
293    path: P,
294    password: &str,
295) -> Result<(), XlsxError> {
296    let extension = path.as_ref().extension().unwrap().to_str().unwrap();
297    let path_tmp = path
298        .as_ref()
299        .with_extension(format!("{}{}", extension, "tmp"));
300    let buffer = match make_buffer(spreadsheet, false) {
301        Ok(v) => v,
302        Err(v) => {
303            fs::remove_file(path_tmp)?;
304            return Err(v);
305        }
306    };
307
308    // set password
309    encrypt(&path_tmp, &buffer, password);
310
311    fs::rename(path_tmp, path)?;
312    Ok(())
313}
314
315/// write spreadsheet file with password.
316/// # Arguments
317/// * `spreadsheet` - Spreadsheet structs object.
318/// * `path` - file path to save.
319/// * `password` - password.
320/// # Return value
321/// * `Result` - OK is void. Err is error message.
322/// # Examples
323/// ```
324/// let mut book = umya_spreadsheet::new_file();
325/// let path = std::path::Path::new("./tests/result_files/zzz_password.xlsx");
326/// let _ = umya_spreadsheet::writer::xlsx::write_with_password_light(&book, path, "password");
327/// ```
328pub fn write_with_password_light<P: AsRef<Path>>(
329    spreadsheet: &Spreadsheet,
330    path: P,
331    password: &str,
332) -> Result<(), XlsxError> {
333    let extension = path.as_ref().extension().unwrap().to_str().unwrap();
334    let path_tmp = path
335        .as_ref()
336        .with_extension(format!("{}{}", extension, "tmp"));
337    let buffer = match make_buffer(spreadsheet, true) {
338        Ok(v) => v,
339        Err(v) => {
340            fs::remove_file(path_tmp)?;
341            return Err(v);
342        }
343    };
344
345    // set password
346    encrypt(&path_tmp, &buffer, password);
347
348    fs::rename(path_tmp, path)?;
349    Ok(())
350}
351
352/// write spreadsheet file with password.
353/// # Arguments
354/// * `from_path` - file path from readfile.
355/// * `to_path` - file path to save.
356/// * `password` - password.
357/// # Return value
358/// * `Result` - OK is void. Err is error message.
359/// # Examples
360/// ```
361/// let from_path = std::path::Path::new("./tests/test_files/aaa.xlsx");
362/// let to_path = std::path::Path::new("./tests/result_files/zzz_password2.xlsx");
363/// let _ = umya_spreadsheet::writer::xlsx::set_password(&from_path, &to_path, "password");
364/// ```
365pub fn set_password<P: AsRef<Path>>(
366    from_path: P,
367    to_path: P,
368    password: &str,
369) -> Result<(), XlsxError> {
370    let mut file = File::open(from_path).unwrap();
371    let mut buffer = Vec::new();
372    file.read_to_end(&mut buffer).unwrap();
373
374    // set password
375    encrypt(&to_path, &buffer, password);
376
377    Ok(())
378}