mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-09 02:33:51 +00:00
M11: PDF/A verify reports nonzero reals nearer zero than ±1.175 × 10⁻³⁸ (6.1.13)
PDF Association TechNote 0010 A018: PDF/A-2 does not allow the nonzero reals that ISO 32000-1 Table C.1 lets a reader round to zero. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6ebfada74d
commit
bf20038b0b
@@ -117,7 +117,7 @@ pub const WORDINGS: &[&str] = &[
|
||||
// The document as a whole.
|
||||
"The document is encrypted",
|
||||
"An integer is outside the 32-bit range",
|
||||
"A real number is outside ±3.403 × 10³⁸",
|
||||
"A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸",
|
||||
"A CMap maps a character code to a CID above 65535",
|
||||
"A string is longer than 32767 bytes",
|
||||
"A name is longer than 127 bytes",
|
||||
@@ -528,7 +528,7 @@ pub fn verify(doc: &Document, level: Level) -> Vec<Issue> {
|
||||
issue("6.1.13", "An integer is outside the 32-bit range", None, None, false);
|
||||
}
|
||||
if over.real {
|
||||
issue("6.1.13", "A real number is outside ±3.403 × 10³⁸", None, None, false);
|
||||
issue("6.1.13", "A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸", None, None, false);
|
||||
}
|
||||
if over.string {
|
||||
issue("6.1.13", "A string is longer than 32767 bytes", None, None, false);
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
//! a name written with `#xx` escapes counts its decoded bytes. A page's `/Contents` streams are read
|
||||
//! joined, as one content stream (an operator's operands may end one stream and the operator start
|
||||
//! the next, ISO 32000-1 7.8.2). Content is decoded within one allowance for the whole document.
|
||||
//! Real numbers beyond ±3.403 × 10³⁸ are reported, and so is an embedded CMap of a Type 0 font
|
||||
//! Real numbers beyond ±3.403 × 10³⁸ are reported, and so are nonzero ones nearer zero than
|
||||
//! ±1.175 × 10⁻³⁸ (ISO 32000-1 Table C.1 lets a reader round them to zero; PDF/A-2 does not allow
|
||||
//! them, PDF Association TechNote 0010 A018), and so is an embedded CMap of a Type 0 font
|
||||
//! (or one it uses through `/UseCMap`) that maps a code to a CID above 65535. An integer token too
|
||||
//! long even for a real reads as one past that range, and is reported as a real.
|
||||
|
||||
@@ -19,6 +21,8 @@ const MIN_INT: i64 = i32::MIN as i64;
|
||||
const MAX_INT: i64 = i32::MAX as i64;
|
||||
/// Table C.1: the largest real value (approximate).
|
||||
const MAX_REAL: f64 = 3.403e38;
|
||||
/// Table C.1: the nonzero real value closest to zero (approximate).
|
||||
const MIN_REAL: f64 = 1.175e-38;
|
||||
/// Table C.1: the largest character identifier.
|
||||
const MAX_CID: u64 = 65535;
|
||||
/// The decoded CMap data, across all the document's embedded CMaps, the scan reads.
|
||||
@@ -65,7 +69,7 @@ impl Exceeded {
|
||||
}
|
||||
match o {
|
||||
Object::Int(i) => self.int |= !(MIN_INT..=MAX_INT).contains(i),
|
||||
Object::Real(r) => self.real |= !r.is_finite() || r.abs() > MAX_REAL,
|
||||
Object::Real(r) => self.real |= !r.is_finite() || r.abs() > MAX_REAL || (*r != 0.0 && r.abs() < MIN_REAL),
|
||||
Object::String(s) => self.string |= s.bytes.len() > MAX_STRING,
|
||||
Object::Name(n) => self.name(n),
|
||||
Object::Array(a) => {
|
||||
|
||||
@@ -569,11 +569,15 @@ endstream",
|
||||
// Corners near ±1e308 are reals past the limit too, and the width overflows to infinity.
|
||||
assert_eq!(
|
||||
limits(&page("|", "", "[-1e308 0 1e308 200]", "")),
|
||||
["A real number is outside ±3.403 × 10³⁸", "Page 1 has a boundary smaller than 3 or larger than 14400 units"]
|
||||
[
|
||||
"A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸",
|
||||
"Page 1 has a boundary smaller than 3 or larger than 14400 units"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// 6.1.13's two remaining limits of ISO 32000-1 Annex C: a real number beyond ±3.403 × 10³⁸, and
|
||||
/// 6.1.13's two remaining limits of ISO 32000-1 Annex C: a real number beyond ±3.403 × 10³⁸ (or
|
||||
/// nonzero and nearer zero than ±1.175 × 10⁻³⁸), and
|
||||
/// a CID above 65535 that an embedded CMap of a Type 0 font maps to (a `begincidrange` reaching
|
||||
/// past it, a `begincidchar` naming one, or a CMap it uses through `/UseCMap`).
|
||||
#[test]
|
||||
@@ -600,8 +604,15 @@ fn implementation_limits_cover_reals_and_cids() {
|
||||
let near = format!("34{}.0", "0".repeat(37));
|
||||
let far = format!("4{}.0", "0".repeat(38));
|
||||
assert!(limits(&doc(&format!("/R {near} /S -{near}"), &range("0000", "00ff", 65280), "")).is_empty(), "both at their limits");
|
||||
assert_eq!(limits(&doc(&format!("/R {far}"), "", "")), ["A real number is outside ±3.403 × 10³⁸"]);
|
||||
assert_eq!(limits(&doc(&format!("/R -{far}"), "", "")), ["A real number is outside ±3.403 × 10³⁸"]);
|
||||
assert_eq!(limits(&doc(&format!("/R {far}"), "", "")), ["A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸"]);
|
||||
assert_eq!(limits(&doc(&format!("/R -{far}"), "", "")), ["A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸"]);
|
||||
// A nonzero real nearer zero than ±1.175 × 10⁻³⁸ is not allowed either; zero and the
|
||||
// smallest allowed magnitude are.
|
||||
let tiny = format!("0.{}1", "0".repeat(39));
|
||||
let smallest = format!("0.{}1175", "0".repeat(37));
|
||||
assert!(limits(&doc(&format!("/Z 0.0 /M -0.0 /S {smallest} /T -{smallest}"), "", "")).is_empty(), "zero and the smallest real");
|
||||
assert_eq!(limits(&doc(&format!("/R {tiny}"), "", "")), ["A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸"]);
|
||||
assert_eq!(limits(&doc(&format!("/R -{tiny}"), "", "")), ["A real number is outside ±3.403 × 10³⁸, or nonzero but within ±1.175 × 10⁻³⁸"]);
|
||||
let cid = ["A CMap maps a character code to a CID above 65535"];
|
||||
assert_eq!(limits(&doc("", &range("3f00", "3fff", 65536), "")), cid);
|
||||
assert_eq!(limits(&doc("", &range("0000", "0100", 65280), "")), cid, "the range reaches 65536");
|
||||
|
||||
Reference in New Issue
Block a user