Skip to main content

ofd_core/
lib.rs

1//! `ofd-core`:OFD(开放版式文档,GB/T 33190—2016)基础结构解析库。
2//!
3//! 本 crate 实现规范第 6 章(容器方案)与第 7 章(基本结构)的解析,
4//! 提供从 ZIP 容器到数据模型的标准 Rust API:
5//!
6//! - [`types`]:基础数据类型(7.3),如 [`StBox`]、[`StLoc`] 等;
7//! - [`OfdPackage`]:ZIP 容器读取(第 6 章);
8//! - [`model`]:`OFD.xml`、`Document.xml`、页树/页对象、资源等数据模型;
9//! - [`OfdReader`]:在容器与数据模型之上的高层接口,自动处理路径解析与装载。
10//!
11//! # 示例
12//!
13//! ```no_run
14//! use ofd_core::OfdReader;
15//!
16//! let mut reader = OfdReader::open("sample.ofd")?;
17//! println!("版本: {}, 类型: {}", reader.ofd().version, reader.ofd().doc_type);
18//!
19//! // 装载第一个版式文档及其首页
20//! let bodies = reader.ofd().doc_bodies.clone();
21//! let doc = reader.load_document(&bodies[0])?;
22//! for page_ref in doc.pages() {
23//!     let page = reader.load_page(&doc, page_ref)?;
24//!     println!("页 {} 是否空白: {}", page_ref.id, page.is_blank());
25//! }
26//! # Ok::<(), ofd_core::OfdError>(())
27//! ```
28
29pub mod crypto;
30pub mod error;
31pub mod model;
32pub mod package;
33pub mod render;
34pub mod types;
35pub mod verify;
36pub mod xmlfmt;
37
38use std::fs::File;
39use std::io::{Read, Seek};
40use std::path::Path;
41
42pub use error::{OfdError, Result};
43pub use model::*;
44pub use package::OfdPackage;
45pub use render::RenderOptions;
46pub use types::{StArray, StBox, StId, StLoc, StPos, StRefId, parent_dir, resolve_path};
47pub use verify::{
48    CheckMethod, CheckReport, LoadedSignature, RefStatus, SigVerdict, SignatureReport, check_path,
49    check_reader,
50};
51pub use xmlfmt::pretty_xml;
52
53/// 包内主入口文件名(见表 1)。
54pub const ENTRY_OFD: &str = "OFD.xml";
55
56/// OFD 文档的高层读取器。
57///
58/// 打开时即解析主入口 [`Ofd`](`OFD.xml`),随后可按需装载各版式文档的根节点、
59/// 页对象、模板页与资源;装载过程自动完成 [`StLoc`] 的相对/绝对路径解析。
60pub struct OfdReader<R> {
61    package: OfdPackage<R>,
62    ofd: Ofd,
63}
64
65impl OfdReader<File> {
66    /// 从文件系统路径打开一个 OFD 文档。
67    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
68        Self::new(OfdPackage::open(path)?)
69    }
70}
71
72impl<R: Read + Seek> OfdReader<R> {
73    /// 基于已打开的 [`OfdPackage`] 创建读取器,并解析主入口 `OFD.xml`。
74    pub fn new(mut package: OfdPackage<R>) -> Result<Self> {
75        let ofd: Ofd = package.parse(ENTRY_OFD)?;
76        Ok(OfdReader { package, ofd })
77    }
78
79    /// 主入口数据模型(`OFD.xml`)。
80    pub fn ofd(&self) -> &Ofd {
81        &self.ofd
82    }
83
84    /// 底层容器的可变引用,便于读取本库未直接建模的部件。
85    pub fn package_mut(&mut self) -> &mut OfdPackage<R> {
86        &mut self.package
87    }
88
89    /// 装载某个版式文档的根节点(`Document.xml`)。
90    ///
91    /// 返回的 [`LoadedDocument`] 携带文档所在目录,供后续解析页、资源等
92    /// 相对路径使用。
93    pub fn load_document(&mut self, body: &DocBody) -> Result<LoadedDocument> {
94        let doc_root = body
95            .doc_root
96            .as_ref()
97            .ok_or_else(|| OfdError::Structure("DocBody is missing DocRoot".to_string()))?;
98        let path = resolve_path("", doc_root);
99        let base = parent_dir(&path).to_string();
100        let document: Document = self.package.parse(&path)?;
101        Ok(LoadedDocument { document, base })
102    }
103
104    /// 装载页树中某一页的页对象(`Content.xml`)。
105    pub fn load_page(&mut self, doc: &LoadedDocument, page: &PageRef) -> Result<PageObject> {
106        let path = resolve_path(&doc.base, &page.base_loc);
107        self.package.parse(&path)
108    }
109
110    /// 装载某个模板页的内容(结构与普通页相同)。
111    pub fn load_template(
112        &mut self,
113        doc: &LoadedDocument,
114        template: &CtTemplatePage,
115    ) -> Result<PageObject> {
116        let path = resolve_path(&doc.base, &template.base_loc);
117        self.package.parse(&path)
118    }
119
120    /// 装载文档的一个资源文件(公共资源或文档资源)。
121    pub fn load_resource(&mut self, doc: &LoadedDocument, loc: &StLoc) -> Result<Res> {
122        let path = resolve_path(&doc.base, loc);
123        self.package.parse(&path)
124    }
125}
126
127/// 已装载的版式文档及其在包内的所在目录。
128///
129/// `base` 为 `Document.xml` 所在目录(如 `Doc_0`),用于解析页对象、资源等
130/// 节点中的相对 [`StLoc`]。
131pub struct LoadedDocument {
132    /// 文档根节点数据模型。
133    pub document: Document,
134    /// 文档所在目录(不含末尾 `/`)。
135    pub base: String,
136}
137
138impl LoadedDocument {
139    /// 页树中的页节点(按页顺序)。
140    pub fn pages(&self) -> &[PageRef] {
141        &self.document.pages.pages
142    }
143
144    /// 文档公共数据中定义的模板页。
145    pub fn template_pages(&self) -> &[CtTemplatePage] {
146        &self.document.common_data.template_pages
147    }
148
149    /// 公共资源文件路径列表。
150    pub fn public_res(&self) -> &[StLoc] {
151        &self.document.common_data.public_res
152    }
153
154    /// 文档资源文件路径列表。
155    pub fn document_res(&self) -> &[StLoc] {
156        &self.document.common_data.document_res
157    }
158}