Skip to main content

rust_xlsxwriter/
custom.rs

1// custom - A module for creating the Excel Custom.xml file.
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4//
5// Copyright 2022-2026, John McNamara, jmcnamara@cpan.org
6
7mod tests;
8
9use std::io::Cursor;
10
11use crate::xmlwriter::{xml_data_element_only, xml_declaration, xml_end_tag, xml_start_tag};
12use crate::{CustomProperty, CustomPropertyType, DocProperties};
13
14pub struct Custom {
15    pub(crate) writer: Cursor<Vec<u8>>,
16    pub(crate) properties: DocProperties,
17}
18
19impl Custom {
20    // -----------------------------------------------------------------------
21    // Public (and crate public) methods.
22    // -----------------------------------------------------------------------
23
24    // Create a new Custom struct.
25    pub(crate) fn new() -> Custom {
26        let writer = Cursor::new(Vec::with_capacity(2048));
27
28        Custom {
29            writer,
30
31            properties: DocProperties::new(),
32        }
33    }
34
35    // -----------------------------------------------------------------------
36    // XML assembly methods.
37    // -----------------------------------------------------------------------
38
39    // Assemble and generate the XML file.
40    pub(crate) fn assemble_xml_file(&mut self) {
41        xml_declaration(&mut self.writer);
42
43        // Write the <Properties> element.
44        self.write_properties();
45
46        for (pid, property) in self.properties.custom_properties.clone().iter().enumerate() {
47            // Write the <property> element.
48            self.write_property(property, pid + 2);
49        }
50
51        // Close the final tag.
52        xml_end_tag(&mut self.writer, "Properties");
53    }
54
55    // Write the <Properties> element.
56    fn write_properties(&mut self) {
57        let schema = "http://schemas.openxmlformats.org/officeDocument/2006".to_string();
58        let xmlns = format!("{schema}/custom-properties");
59        let xmlns_vt = format!("{schema}/docPropsVTypes");
60
61        let attributes = [("xmlns", xmlns), ("xmlns:vt", xmlns_vt)];
62
63        xml_start_tag(&mut self.writer, "Properties", &attributes);
64    }
65
66    // Write the <property> element.
67    fn write_property(&mut self, property: &CustomProperty, pid: usize) {
68        let fmtid = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}".to_string();
69        let attributes = [
70            ("fmtid", fmtid),
71            ("pid", pid.to_string()),
72            ("name", property.name.clone()),
73        ];
74
75        xml_start_tag(&mut self.writer, "property", &attributes);
76
77        match property.property_type {
78            CustomPropertyType::Int => self.write_vt_i_4(property.number_int),
79            CustomPropertyType::Bool => self.write_vt_bool(property.boolean),
80            CustomPropertyType::Real => self.write_vt_r_8(property.number_real),
81            CustomPropertyType::Text => self.write_vt_lpwstr(&property.text),
82            CustomPropertyType::DateTime => self.write_vt_filetime(&property.datetime),
83        }
84
85        xml_end_tag(&mut self.writer, "property");
86    }
87
88    // Write the <vt:lpwstr> element.
89    fn write_vt_lpwstr(&mut self, text: &str) {
90        xml_data_element_only(&mut self.writer, "vt:lpwstr", text);
91    }
92
93    // Write the <vt:filetime> element.
94    fn write_vt_filetime(&mut self, utc_datetime: &str) {
95        xml_data_element_only(&mut self.writer, "vt:filetime", utc_datetime);
96    }
97
98    // Write the <vt:i4> element.
99    fn write_vt_i_4(&mut self, number: i32) {
100        xml_data_element_only(&mut self.writer, "vt:i4", &number.to_string());
101    }
102
103    // Write the <vt:r8> element.
104    fn write_vt_r_8(&mut self, number: f64) {
105        xml_data_element_only(&mut self.writer, "vt:r8", &number.to_string());
106    }
107
108    // Write the <vt:bool> element.
109    fn write_vt_bool(&mut self, boolean: bool) {
110        xml_data_element_only(&mut self.writer, "vt:bool", &boolean.to_string());
111    }
112}