mf_file/zipdoc/
writer.rs

1use std::io::{self, Write, Seek};
2use zip::{ZipWriter, write::SimpleFileOptions, CompressionMethod};
3
4// 基于 ZIP 的文档写入器(docx 风格容器)
5pub struct ZipDocumentWriter<W: Write + Seek> {
6    pub(crate) zip: ZipWriter<W>,
7    pub(crate) manifest: serde_json::Value,
8}
9
10impl<W: Write + Seek> ZipDocumentWriter<W> {
11    // 创建写入器
12    pub fn new(w: W) -> io::Result<Self> {
13        let zip = ZipWriter::new(w);
14        let manifest = serde_json::json!({ "version": 1, "entries": [] });
15        Ok(Self { zip, manifest })
16    }
17    // 读取当前 manifest 的不可变引用
18    pub fn manifest(&self) -> &serde_json::Value {
19        &self.manifest
20    }
21    // 读取当前 manifest 的可变引用(可自由添加自定义字段)
22    pub fn manifest_mut(&mut self) -> &mut serde_json::Value {
23        &mut self.manifest
24    }
25    // 替换 manifest(链式调用)
26    pub fn set_manifest(
27        &mut self,
28        manifest: serde_json::Value,
29    ) -> &mut Self {
30        self.manifest = manifest;
31        self
32    }
33    // 写入 JSON 文件(deflate 压缩)
34    pub fn add_json(
35        &mut self,
36        name: &str,
37        value: &serde_json::Value,
38    ) -> io::Result<()> {
39        let opts = SimpleFileOptions::default()
40            .compression_method(CompressionMethod::Deflated);
41        self.zip.start_file(name, opts)?;
42        let data = serde_json::to_vec(value)
43            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
44        // 记录到 manifest.entries(若存在且为数组)
45        if let Some(entries) =
46            self.manifest.get_mut("entries").and_then(|v| v.as_array_mut())
47        {
48            entries.push(serde_json::json!({
49                "name": name,
50                "kind": "json",
51                "logical_len": data.len(),
52                "compression": "deflate"
53            }));
54        }
55        self.zip.write_all(&data)
56    }
57    // 写入原样存储的条目(不压缩)
58    pub fn add_stored(
59        &mut self,
60        name: &str,
61        bytes: &[u8],
62    ) -> io::Result<()> {
63        let opts = SimpleFileOptions::default()
64            .compression_method(CompressionMethod::Stored);
65        self.zip.start_file(name, opts)?;
66        if let Some(entries) =
67            self.manifest.get_mut("entries").and_then(|v| v.as_array_mut())
68        {
69            entries.push(serde_json::json!({
70                "name": name,
71                "kind": "binary",
72                "logical_len": bytes.len(),
73                "compression": "stored"
74            }));
75        }
76        self.zip.write_all(bytes)
77    }
78    // 写入 deflate 压缩条目
79    pub fn add_deflated(
80        &mut self,
81        name: &str,
82        bytes: &[u8],
83    ) -> io::Result<()> {
84        let opts = SimpleFileOptions::default()
85            .compression_method(CompressionMethod::Deflated);
86        self.zip.start_file(name, opts)?;
87        if let Some(entries) =
88            self.manifest.get_mut("entries").and_then(|v| v.as_array_mut())
89        {
90            entries.push(serde_json::json!({
91                "name": name,
92                "kind": "binary",
93                "logical_len": bytes.len(),
94                "compression": "deflate"
95            }));
96        }
97        self.zip.write_all(bytes)
98    }
99    // 完成写入,附带 manifest.json
100    pub fn finalize(mut self) -> io::Result<W> {
101        let opts = SimpleFileOptions::default()
102            .compression_method(CompressionMethod::Deflated);
103        self.zip.start_file("manifest.json", opts)?;
104        let data = serde_json::to_vec(&self.manifest)
105            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
106        self.zip.write_all(&data)?;
107        self.zip.finish().map_err(|e| io::Error::new(io::ErrorKind::Other, e))
108    }
109}