package pdf // ASCIIHexDecode and ASCII85Decode: the two filters that exist so a PDF can be // mailed through a 7-bit channel. Both are self-delimiting -- the data ends at // a marker, not at the end of the buffer -- so both are routinely handed more // bytes than they will consume, and both must ignore whitespace anywhere. // // Neither ever fails. A character that belongs to neither alphabet is dropped: // producers emit stray line-noise (a '\0' padding a stream, a lone '<' left // over from a hex string) often enough that refusing the stream would lose a // page over one byte. ISO 32000-2, 7.4.2 and 7.4.3 both make an unexpected // character an error; treating it as a repair instead is the difference // between a reader and a validator. // ascii_hex_decode decodes ASCIIHexDecode data. // // Whitespace is ignored, '>' ends the data, and an odd final digit is padded // with '0' as the spec requires. Any other character is skipped. // // The returned slice is owned by the caller and allocated with `allocator`. ascii_hex_decode :: proc(data: []byte, allocator := context.allocator) -> (out: []byte, err: Error) { n := ascii_hex_scan(data, nil) if n == 0 { return nil, .None } buf, alloc_err := make([]byte, n, allocator) if alloc_err != nil { return nil, .Out_Of_Memory } ascii_hex_scan(data, buf) return buf, .None } // ascii85_decode decodes ASCII85Decode data. // // "~>" ends the data, 'z' at the start of a group stands for four zero bytes, // whitespace is ignored anywhere, and a truncated final group of n characters // yields n-1 bytes. A leading "<~" -- which the filter does not define but // which producers copying Adobe's own encoder emit -- is skipped. // // The returned slice is owned by the caller and allocated with `allocator`. ascii85_decode :: proc(data: []byte, allocator := context.allocator) -> (out: []byte, err: Error) { n := ascii85_scan(data, nil) if n == 0 { return nil, .None } buf, alloc_err := make([]byte, n, allocator) if alloc_err != nil { return nil, .Out_Of_Memory } ascii85_scan(data, buf) return buf, .None } // --------------------------------------------------------------------------- // Scanners // // Each decoder is one procedure run twice: once with `out == nil` to measure // the result, once to fill it. Measuring first means the allocation is exactly // the size of the output rather than an upper bound derived from an // attacker-supplied length, and means the two passes cannot disagree about // what the data says. // --------------------------------------------------------------------------- // ISO 32000-2, Table 1: the six white-space characters. NUL counts, which // matters here because it is what stream padding is usually made of. @(private) ascii_is_whitespace :: proc "contextless" (c: byte) -> bool { switch c { case 0x00, 0x09, 0x0A, 0x0C, 0x0D, 0x20: return true } return false } @(private) ascii_hex_scan :: proc(data: []byte, out: []byte) -> int { n := 0 hi: byte have_hi := false for c in data { if c == '>' { break } // hex_value rejects whitespace and junk alike, and both are skipped, // so there is nothing to tell apart here. v, ok := hex_value(c) if !ok { continue } if !have_hi { hi, have_hi = v, true continue } if n < len(out) { out[n] = hi << 4 | v } n += 1 have_hi = false } // A final odd digit is padded with '0', i.e. shifted into the high nibble. if have_hi { if n < len(out) { out[n] = hi << 4 } n += 1 } return n } @(private) ascii85_scan :: proc(data: []byte, out: []byte) -> int { i := 0 for i < len(data) && ascii_is_whitespace(data[i]) { i += 1 } if i + 1 < len(data) && data[i] == '<' && data[i + 1] == '~' { i += 2 } n := 0 group: [5]byte ngroup := 0 for ; i < len(data); i += 1 { c := data[i] if ascii_is_whitespace(c) { continue } // The terminator is "~>", but a '~' that is not followed by '>' is // still the end of anything decodable, so do not look at the next byte. if c == '~' { break } if c == 'z' && ngroup == 0 { n = ascii85_emit(out, n, 0, 4) continue } // Everything outside the alphabet is dropped -- including a 'z' in the // middle of a group, which has no defined meaning ('z' is above 'u'). if c < '!' || c > 'u' { continue } group[ngroup] = c - '!' ngroup += 1 if ngroup == 5 { n = ascii85_emit(out, n, ascii85_value(group[:], 5), 4) ngroup = 0 } } // A partial group of n characters encodes n-1 bytes. A single leftover // character encodes nothing at all and is dropped. if ngroup >= 2 { n = ascii85_emit(out, n, ascii85_value(group[:], ngroup), ngroup - 1) } return n } // ascii85_value folds a group of 1..5 digits, padding a short group with 'u' // as ISO 32000-2, 7.4.3 requires. Five digits can encode up to 85^5-1, which // is larger than a u32 can hold; such a group is out of spec, and clamping it // keeps the bytes that were probably meant rather than dropping the group. @(private) ascii85_value :: proc(digits: []byte, count: int) -> u32 { v: u64 = 0 for k in 0 ..< 5 { d: u64 = 84 // 'u' - '!' if k < count && k < len(digits) { d = u64(digits[k]) } v = v * 85 + d } if v > 0xFFFF_FFFF { return 0xFFFF_FFFF } return u32(v) } @(private) ascii85_emit :: proc(out: []byte, n: int, v: u32, count: int) -> int { b := [4]byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)} m := n for k in 0 ..< count { if k >= len(b) { break } if m < len(out) { out[m] = b[k] } m += 1 } return m }