UniDoc说明中心下载 .udoc
UNIDOC / KNOWLEDGE IN MOTION

UDOC 容器规范

从理解,到动手实现。步骤、协议与可复制的示例,都在这份文档中。

UDOC3 is UniDoc's only native save format. It deliberately does not decode
UDOC1, UDOC2, or plain JSON documents.

Goals

  • Read the directory with one tail File.slice instead of inflating the file.
  • Compress document chunks independently.
  • Keep already-compressed media byte-for-byte.
  • Deduplicate media by SHA-256 content identity.
  • Detect damage before document data reaches the editor.
  • Preserve unknown parts in future codecs without changing the editor model.

Binary layout

All integers are unsigned little-endian.

0                                  8
+----------------------------------+
| "UDOC3PKG"                       | fixed header
+----------------------------------+
| entry payload 0                  |
| entry payload 1                  | store, independent Brotli, or one-file ZIP
| ...                              |
+----------------------------------+ directoryOffset
| Brotli central directory         | directoryLength (compressed)
+----------------------------------+
| "UD3DIR01"                       | 8 bytes
| directoryOffset (u64)            | 8 bytes
| directoryLength (u64)            | 8 bytes
| SHA-256(directory JSON)          | 32 bytes
| version = 3 (u32)                | 4 bytes
| directory raw length (u32)       | 4 bytes
+----------------------------------+ EOF (64-byte footer)

The central directory contains one descriptor per part:

{
  "path": "document/chunks/000001.json",
  "offset": 8,
  "compressedSize": 1234,
  "size": 8192,
  "codec": "br",
  "mime": "application/json",
  "sha256": "64 lowercase hex digits"
}

Offsets are absolute. Paths are unique, relative, slash-separated, and cannot
contain empty, . or .. segments. Entry ranges cannot overlap.

Logical package

manifest.json
document/document.json
document/chunks/000001.json
document/chunks/000002.json
...
rels/relationships.json
media/<sha256>.<extension>
embeds/<sha256>.html

manifest.json declares the root document part, ordered chunk list, block
count, chunk size, relationship part, and enabled features.

document/document.json holds document-level metadata, page setup, headers,
footers, and text boxes. It does not contain the block array.

Each chunk contains its absolute block start index and at most 256 ordered
logical blocks. A decoder rejects gaps, overlaps, or an incorrect total.

rels/relationships.json maps source paragraph IDs to internal or external
images, videos, and HTML embeds.

Media and embeds use their uncompressed SHA-256 as their filename. Repeated
content therefore has one physical part even if many blocks reference it.

Codec and integrity rules

  • JSON, HTML, XML, CSS, JavaScript, Markdown, plain text, and SVG parts use

independent Brotli (br, quality 9) when it saves meaningful space.

  • The central directory is always Brotli-compressed and its uncompressed length

is stored in the footer.

  • Binary static resources use a deterministic single-file ZIP payload (zip).

Already-compressed images, video, audio, PDF, WOFF/WOFF2, and archive formats
use ZIP Store; other binary resources may use ZIP Deflate. Transcoding is
forbidden. Attachments are opaque binary resources and always use this ZIP
side of the hybrid contract, even when their filename ends in .txt or
.html.

  • Very small textual parts may remain store when Brotli would not save enough

bytes. The descriptor's codec is authoritative.

  • The directory SHA-256 is verified before parsing any entry.
  • Every loaded entry is checked against both declared size and SHA-256.
  • Brotli output is bounded by its declared size while streaming in the Rust

service.

  • One entry is limited to 512 MiB; total declared expansion is limited to 2 GiB.
  • The current loader verifies all document, relationship, media, and embed parts.
  • Document chunks and media are decoded with bounded concurrency; duplicate

reads share one in-flight promise.

The directory-at-end design allows future lazy media hydration and incremental
append saves without changing the on-disk addressing model.