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;
36
37use std::fs::File;
38use std::io::{Read, Seek};
39use std::path::Path;
40
41pub use error::{OfdError, Result};
42pub use model::*;
43pub use package::OfdPackage;
44pub use render::RenderOptions;
45pub use types::{StArray, StBox, StId, StLoc, StPos, StRefId, parent_dir, resolve_path};
46pub use verify::{
47    CheckMethod, CheckReport, LoadedSignature, RefStatus, SigVerdict, SignatureReport, check_path,
48    check_reader,
49};
50
51/// 包内主入口文件名(见表 1)。
52pub const ENTRY_OFD: &str = "OFD.xml";
53
54/// OFD 文档的高层读取器。
55///
56/// 打开时即解析主入口 [`Ofd`](`OFD.xml`),随后可按需装载各版式文档的根节点、
57/// 页对象、模板页与资源;装载过程自动完成 [`StLoc`] 的相对/绝对路径解析。
58pub struct OfdReader<R> {
59    package: OfdPackage<R>,
60    ofd: Ofd,
61}
62
63impl OfdReader<File> {
64    /// 从文件系统路径打开一个 OFD 文档。
65    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
66        Self::new(OfdPackage::open(path)?)
67    }
68}
69
70impl<R: Read + Seek> OfdReader<R> {
71    /// 基于已打开的 [`OfdPackage`] 创建读取器,并解析主入口 `OFD.xml`。
72    pub fn new(mut package: OfdPackage<R>) -> Result<Self> {
73        let ofd: Ofd = package.parse(ENTRY_OFD)?;
74        Ok(OfdReader { package, ofd })
75    }
76
77    /// 主入口数据模型(`OFD.xml`)。
78    pub fn ofd(&self) -> &Ofd {
79        &self.ofd
80    }
81
82    /// 底层容器的可变引用,便于读取本库未直接建模的部件。
83    pub fn package_mut(&mut self) -> &mut OfdPackage<R> {
84        &mut self.package
85    }
86
87    /// 装载某个版式文档的根节点(`Document.xml`)。
88    ///
89    /// 返回的 [`LoadedDocument`] 携带文档所在目录,供后续解析页、资源等
90    /// 相对路径使用。
91    pub fn load_document(&mut self, body: &DocBody) -> Result<LoadedDocument> {
92        let doc_root = body
93            .doc_root
94            .as_ref()
95            .ok_or_else(|| OfdError::Structure("DocBody is missing DocRoot".to_string()))?;
96        let path = resolve_path("", doc_root);
97        let base = parent_dir(&path).to_string();
98        let document: Document = self.package.parse(&path)?;
99        Ok(LoadedDocument { document, base })
100    }
101
102    /// 装载页树中某一页的页对象(`Content.xml`)。
103    pub fn load_page(&mut self, doc: &LoadedDocument, page: &PageRef) -> Result<PageObject> {
104        let path = resolve_path(&doc.base, &page.base_loc);
105        self.package.parse(&path)
106    }
107
108    /// 装载某个模板页的内容(结构与普通页相同)。
109    pub fn load_template(
110        &mut self,
111        doc: &LoadedDocument,
112        template: &CtTemplatePage,
113    ) -> Result<PageObject> {
114        let path = resolve_path(&doc.base, &template.base_loc);
115        self.package.parse(&path)
116    }
117
118    /// 装载文档的一个资源文件(公共资源或文档资源)。
119    pub fn load_resource(&mut self, doc: &LoadedDocument, loc: &StLoc) -> Result<Res> {
120        let path = resolve_path(&doc.base, loc);
121        self.package.parse(&path)
122    }
123}
124
125/// 已装载的版式文档及其在包内的所在目录。
126///
127/// `base` 为 `Document.xml` 所在目录(如 `Doc_0`),用于解析页对象、资源等
128/// 节点中的相对 [`StLoc`]。
129pub struct LoadedDocument {
130    /// 文档根节点数据模型。
131    pub document: Document,
132    /// 文档所在目录(不含末尾 `/`)。
133    pub base: String,
134}
135
136impl LoadedDocument {
137    /// 页树中的页节点(按页顺序)。
138    pub fn pages(&self) -> &[PageRef] {
139        &self.document.pages.pages
140    }
141
142    /// 文档公共数据中定义的模板页。
143    pub fn template_pages(&self) -> &[CtTemplatePage] {
144        &self.document.common_data.template_pages
145    }
146
147    /// 公共资源文件路径列表。
148    pub fn public_res(&self) -> &[StLoc] {
149        &self.document.common_data.public_res
150    }
151
152    /// 文档资源文件路径列表。
153    pub fn document_res(&self) -> &[StLoc] {
154        &self.document.common_data.document_res
155    }
156}