804 lines
29 KiB
Odin
804 lines
29 KiB
Odin
package pdf
|
|||
|
|
|
||
|
|
import "core:mem"
|
||
|
|
|
||
|
|
// Stream decoding: the /Filter chain, the /DecodeParms that go with it, and
|
||
|
|
// the two predictors (ISO 32000-2, 7.4).
|
||
|
|
//
|
||
|
|
// The codecs themselves live in filter_*.odin. This file is only the plumbing:
|
||
|
|
// which filters a stream asks for, in what order, with which parameters, and
|
||
|
|
// what to do when one of them cannot deliver.
|
||
|
|
//
|
||
|
|
// The governing rule is that a stream which will not decode is an *empty*
|
||
|
|
// stream, not a failed document. A page whose one broken image will not
|
||
|
|
// inflate should still draw its text, so `stream_data` records a repair and
|
||
|
|
// hands back nothing rather than returning an error every caller would have to
|
||
|
|
// ignore. `Stream.state` is where the difference between "decoded to nothing"
|
||
|
|
// and "would not decode" is kept.
|
||
|
|
|
||
|
|
// A chain longer than this is not a document, it is an attempt to make a
|
||
|
|
// reader do work. Real files use one filter; two (an ASCII armour over a
|
||
|
|
// compressor) is the most that occurs in practice.
|
||
|
|
@(private)
|
||
|
|
MAX_FILTER_CHAIN :: 16
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Filter names
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
Filter_Kind :: enum u8 {
|
||
|
|
Unknown = 0,
|
||
|
|
Ascii_Hex,
|
||
|
|
Ascii85,
|
||
|
|
Lzw,
|
||
|
|
Flate,
|
||
|
|
Run_Length,
|
||
|
|
Ccitt,
|
||
|
|
Dct,
|
||
|
|
Jpx,
|
||
|
|
Jbig2,
|
||
|
|
// /Crypt is a marker, not a transformation: decryption has already
|
||
|
|
// happened by the time a stream reaches this file.
|
||
|
|
Crypt,
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_kind classifies a filter name.
|
||
|
|
//
|
||
|
|
// The abbreviations are the ones ISO 32000-2 table 93 defines for inline
|
||
|
|
// images. They are accepted on ordinary streams too: a producer that emits
|
||
|
|
// /Fl outside an inline image is wrong, but the intent is not in doubt and no
|
||
|
|
// other filter name could be meant.
|
||
|
|
@(private)
|
||
|
|
filter_kind :: proc(name: string) -> Filter_Kind {
|
||
|
|
switch name {
|
||
|
|
case "ASCIIHexDecode", "AHx": return .Ascii_Hex
|
||
|
|
case "ASCII85Decode", "A85": return .Ascii85
|
||
|
|
case "LZWDecode", "LZW": return .Lzw
|
||
|
|
case "FlateDecode", "Fl": return .Flate
|
||
|
|
case "RunLengthDecode", "RL": return .Run_Length
|
||
|
|
case "CCITTFaxDecode", "CCF": return .Ccitt
|
||
|
|
case "DCTDecode", "DCT": return .Dct
|
||
|
|
case "JPXDecode": return .Jpx
|
||
|
|
case "JBIG2Decode": return .Jbig2
|
||
|
|
case "Crypt": return .Crypt
|
||
|
|
}
|
||
|
|
return .Unknown
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_name returns the unabbreviated spelling, so callers downstream of
|
||
|
|
// `stream_image_data` can compare against one name instead of two.
|
||
|
|
@(private)
|
||
|
|
filter_name :: proc(kind: Filter_Kind, fallback: string) -> string {
|
||
|
|
switch kind {
|
||
|
|
case .Ascii_Hex: return "ASCIIHexDecode"
|
||
|
|
case .Ascii85: return "ASCII85Decode"
|
||
|
|
case .Lzw: return "LZWDecode"
|
||
|
|
case .Flate: return "FlateDecode"
|
||
|
|
case .Run_Length: return "RunLengthDecode"
|
||
|
|
case .Ccitt: return "CCITTFaxDecode"
|
||
|
|
case .Dct: return "DCTDecode"
|
||
|
|
case .Jpx: return "JPXDecode"
|
||
|
|
case .Jbig2: return "JBIG2Decode"
|
||
|
|
case .Crypt: return "Crypt"
|
||
|
|
case .Unknown: return fallback
|
||
|
|
}
|
||
|
|
return fallback
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_is_image reports whether a filter produces an image rather than a
|
||
|
|
// byte stream. These four are the ones `stream_image_data` stops at: decoding
|
||
|
|
// them needs the image dictionary (dimensions, colour space, /Decode), and
|
||
|
|
// their output is samples, not bytes a content parser could read.
|
||
|
|
@(private)
|
||
|
|
filter_is_image :: proc(kind: Filter_Kind) -> bool {
|
||
|
|
#partial switch kind {
|
||
|
|
case .Dct, .Jpx, .Jbig2, .Ccitt: return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_takes_parms reports whether a filter reads /DecodeParms at all. Used
|
||
|
|
// to place a parameter dictionary that a producer wrote where an array was
|
||
|
|
// required; see `filter_attach_parms`.
|
||
|
|
@(private)
|
||
|
|
filter_takes_parms :: proc(kind: Filter_Kind) -> bool {
|
||
|
|
#partial switch kind {
|
||
|
|
case .Lzw, .Flate, .Ccitt, .Jbig2, .Crypt: return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// The chain
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
Filter_Step :: struct {
|
||
|
|
name: string,
|
||
|
|
kind: Filter_Kind,
|
||
|
|
parms: ^Dict,
|
||
|
|
// Position in the /Filter array, which is what /DecodeParms is indexed by.
|
||
|
|
// Not the same as the step's own index once a malformed entry is dropped.
|
||
|
|
slot: int,
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_chain fills `steps` with the stream's filters in application order.
|
||
|
|
//
|
||
|
|
// `ok` is false only when the file asks for more filters than
|
||
|
|
// MAX_FILTER_CHAIN; every other malformation is absorbed. A missing /Filter
|
||
|
|
// leaves n == 0 and ok == true.
|
||
|
|
@(private)
|
||
|
|
filter_chain :: proc(doc: ^Document, d: ^Dict, steps: []Filter_Step) -> (n: int, ok: bool) {
|
||
|
|
if d == nil || len(steps) == 0 {
|
||
|
|
return 0, true
|
||
|
|
}
|
||
|
|
|
||
|
|
// Inline images abbreviate both keys (ISO 32000-2, table 91). On an
|
||
|
|
// ordinary stream dictionary /F is an external file specification instead,
|
||
|
|
// but that is a string or a dictionary and neither survives the name test
|
||
|
|
// below, so looking is free.
|
||
|
|
filters := dict_get_alt(doc, d, "Filter", "F")
|
||
|
|
parms := dict_get_alt(doc, d, "DecodeParms", "DP")
|
||
|
|
|
||
|
|
#partial switch f in filters {
|
||
|
|
case Name:
|
||
|
|
steps[0] = Filter_Step{name = string(f), kind = filter_kind(string(f)), slot = 0}
|
||
|
|
n = 1
|
||
|
|
case ^Array:
|
||
|
|
count := array_len(f)
|
||
|
|
if count > len(steps) {
|
||
|
|
return 0, false
|
||
|
|
}
|
||
|
|
for i in 0 ..< count {
|
||
|
|
name, is_name := to_name(array_get(doc, f, i))
|
||
|
|
if !is_name {
|
||
|
|
// A null or a stray number inside /Filter. Dropping the entry
|
||
|
|
// keeps the rest of the chain usable; treating it as a filter
|
||
|
|
// would lose the stream over one bad element.
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
steps[n] = Filter_Step{name = name, kind = filter_kind(name), slot = i}
|
||
|
|
n += 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if n == 0 {
|
||
|
|
return 0, true
|
||
|
|
}
|
||
|
|
|
||
|
|
#partial switch p in parms {
|
||
|
|
case ^Array:
|
||
|
|
// Positional, and a short or over-long array is not fatal: a missing
|
||
|
|
// or null entry simply means "no parameters for that filter".
|
||
|
|
for i in 0 ..< n {
|
||
|
|
steps[i].parms = array_dict(doc, p, steps[i].slot)
|
||
|
|
}
|
||
|
|
case ^Dict:
|
||
|
|
filter_attach_parms(steps[:n], p)
|
||
|
|
case ^Stream:
|
||
|
|
// Never legal, but `to_dict` accepts a stream where a dictionary is
|
||
|
|
// wanted and a file that points /DecodeParms at a stream object still
|
||
|
|
// means its dictionary.
|
||
|
|
filter_attach_parms(steps[:n], p.dict)
|
||
|
|
}
|
||
|
|
return n, true
|
||
|
|
}
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
filter_attach_parms :: proc(steps: []Filter_Step, p: ^Dict) {
|
||
|
|
if len(steps) == 1 {
|
||
|
|
steps[0].parms = p
|
||
|
|
return
|
||
|
|
}
|
||
|
|
// ISO 32000-2, 7.4.1 requires an array of dictionaries when /Filter is an
|
||
|
|
// array, but producers write a bare dictionary for chains such as
|
||
|
|
// [/ASCII85Decode /FlateDecode]. It can only have been meant for whichever
|
||
|
|
// filter reads parameters at all, so give it to the first one that does.
|
||
|
|
for i in 0 ..< len(steps) {
|
||
|
|
if filter_takes_parms(steps[i].kind) {
|
||
|
|
steps[i].parms = p
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
steps[0].parms = p
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Decode parameters
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
Predictor_Parms :: struct {
|
||
|
|
predictor: int,
|
||
|
|
colors: int,
|
||
|
|
bpc: int,
|
||
|
|
columns: int,
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_predictor_parms reads the four predictor entries of ISO 32000-2
|
||
|
|
// table 8. Their defaults are what an absent /DecodeParms means, so a nil
|
||
|
|
// dictionary is the ordinary case rather than an error.
|
||
|
|
@(private)
|
||
|
|
filter_predictor_parms :: proc(doc: ^Document, parms: ^Dict) -> Predictor_Parms {
|
||
|
|
return Predictor_Parms{
|
||
|
|
predictor = int(dict_int(doc, parms, "Predictor", 1)),
|
||
|
|
colors = int(dict_int(doc, parms, "Colors", 1)),
|
||
|
|
bpc = int(dict_int(doc, parms, "BitsPerComponent", 8)),
|
||
|
|
columns = int(dict_int(doc, parms, "Columns", 1)),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// filter_ccitt_params reads the CCITTFaxDecode parameters of ISO 32000-2
|
||
|
|
// table 12. Exposed to the image layer, which gets the raw parameter
|
||
|
|
// dictionary back from `stream_image_data` and has to build the same struct.
|
||
|
|
@(private)
|
||
|
|
filter_ccitt_params :: proc(doc: ^Document, parms: ^Dict) -> Ccitt_Params {
|
||
|
|
p := ccitt_default_params()
|
||
|
|
p.k = int(dict_int(doc, parms, "K", 0))
|
||
|
|
p.columns = int(dict_int(doc, parms, "Columns", 1728))
|
||
|
|
p.rows = int(dict_int(doc, parms, "Rows", 0))
|
||
|
|
p.black_is_1 = dict_bool(doc, parms, "BlackIs1", false)
|
||
|
|
p.byte_align = dict_bool(doc, parms, "EncodedByteAlign", false)
|
||
|
|
p.end_of_line = dict_bool(doc, parms, "EndOfLine", false)
|
||
|
|
p.end_of_block = dict_bool(doc, parms, "EndOfBlock", true)
|
||
|
|
return p
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// One filter
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
// apply_filter runs a single filter over `data`.
|
||
|
|
//
|
||
|
|
// `name` may be the full name or the inline-image abbreviation. `parms` is the
|
||
|
|
// matching /DecodeParms entry and may be nil, which means "all defaults".
|
||
|
|
//
|
||
|
|
// Ownership: when `err` is .None the result is allocated with `allocator` and
|
||
|
|
// belongs to the caller. When it is not, the result is either nil or `data`
|
||
|
|
// itself and must not be freed -- the pass-through errors (.Unknown_Filter,
|
||
|
|
// .Unsupported_Image, .Unsupported_Jpx) hand the bytes back untouched so a
|
||
|
|
// caller that knows better can still do something with them.
|
||
|
|
//
|
||
|
|
// A codec that fails part-way through returns .None with a short result, which
|
||
|
|
// is deliberate: half a content stream draws half a page, and that beats a
|
||
|
|
// blank one. Compare the length against what you expected if you need to know.
|
||
|
|
//
|
||
|
|
// This is also the allocator boundary, and that is the part worth reading
|
||
|
|
// twice. Every codec here grows a buffer it cannot size in advance, and the
|
||
|
|
// tolerant ones -- flate above all -- decode the same bytes several ways and
|
||
|
|
// keep the best attempt, dropping the losers with `delete`. Both habits are
|
||
|
|
// harmless against the heap and ruinous against `doc.allocator`: a
|
||
|
|
// `core:mem/virtual` arena answers .Free with .Mode_Not_Implemented, so
|
||
|
|
// `delete` on arena memory is a silent no-op rather than an error, and every
|
||
|
|
// rejected attempt and every superseded growth buffer stays until `close`.
|
||
|
|
// A damaged 256 KiB flate stream can strand megabytes that way, and the frees
|
||
|
|
// that would appear to clean it up are the ones ARCHITECTURE.md forbids.
|
||
|
|
//
|
||
|
|
// So a codec never sees the caller's allocator. It speculates in scratch,
|
||
|
|
// where its own `delete` calls do what they say, and exactly one buffer -- the
|
||
|
|
// winner, at its final length -- is copied into `allocator` afterwards. The
|
||
|
|
// caller's arena grows by the size of the output, not by the number of
|
||
|
|
// attempts it took to find it, and a codec added later inherits that without
|
||
|
|
// having to know about it.
|
||
|
|
apply_filter :: proc(doc: ^Document, name: string, data: []byte, parms: ^Dict,
|
||
|
|
allocator := context.allocator) -> (out: []byte, err: Error) {
|
||
|
|
scratch := context.allocator
|
||
|
|
if allocator == scratch {
|
||
|
|
// The caller already asked for the allocator the codec would have
|
||
|
|
// speculated in, so copying the result to itself would only double the
|
||
|
|
// peak for nothing.
|
||
|
|
return apply_filter_decode(doc, name, data, parms, scratch)
|
||
|
|
}
|
||
|
|
|
||
|
|
tmp, terr := apply_filter_decode(doc, name, data, parms, scratch)
|
||
|
|
if terr != .None {
|
||
|
|
// Per the ownership rule above, a failed filter hands back nil or
|
||
|
|
// `data` itself. Neither is ours to copy or to free.
|
||
|
|
return tmp, terr
|
||
|
|
}
|
||
|
|
defer delete(tmp, scratch)
|
||
|
|
return filter_copy(tmp, allocator)
|
||
|
|
}
|
||
|
|
|
||
|
|
// apply_filter_decode is the dispatch proper. `scratch` is throw-away memory
|
||
|
|
// that `apply_filter` frees on the way out, so a codec reached from here may
|
||
|
|
// allocate and free as freely as it likes; nothing it leaves behind outlives
|
||
|
|
// the call. Do not call this with a Document arena -- that is the whole point
|
||
|
|
// of it being separate.
|
||
|
|
@(private)
|
||
|
|
apply_filter_decode :: proc(doc: ^Document, name: string, data: []byte, parms: ^Dict,
|
||
|
|
scratch: mem.Allocator) -> (out: []byte, err: Error) {
|
||
|
|
switch filter_kind(name) {
|
||
|
|
case .Ascii_Hex:
|
||
|
|
return ascii_hex_decode(data, scratch)
|
||
|
|
|
||
|
|
case .Ascii85:
|
||
|
|
return ascii85_decode(data, scratch)
|
||
|
|
|
||
|
|
case .Run_Length:
|
||
|
|
return run_length_decode(data, scratch)
|
||
|
|
|
||
|
|
case .Flate:
|
||
|
|
pp := filter_predictor_parms(doc, parms)
|
||
|
|
if pp.predictor <= 1 {
|
||
|
|
return flate_decode(data, scratch)
|
||
|
|
}
|
||
|
|
// The un-predicted bytes are an intermediate: freed here rather than
|
||
|
|
// carried out, so a predicted stream costs one buffer and not two.
|
||
|
|
raw, ferr := flate_decode(data, scratch)
|
||
|
|
defer delete(raw, scratch)
|
||
|
|
if ferr != .None {
|
||
|
|
return nil, ferr
|
||
|
|
}
|
||
|
|
return apply_predictor(raw, pp.predictor, pp.colors, pp.bpc, pp.columns, scratch)
|
||
|
|
|
||
|
|
case .Lzw:
|
||
|
|
// /EarlyChange defaults to 1 (ISO 32000-2, table 8).
|
||
|
|
early := dict_int(doc, parms, "EarlyChange", 1) != 0
|
||
|
|
pp := filter_predictor_parms(doc, parms)
|
||
|
|
if pp.predictor <= 1 {
|
||
|
|
return lzw_decode(data, early, scratch)
|
||
|
|
}
|
||
|
|
raw, ferr := lzw_decode(data, early, scratch)
|
||
|
|
defer delete(raw, scratch)
|
||
|
|
if ferr != .None {
|
||
|
|
return nil, ferr
|
||
|
|
}
|
||
|
|
return apply_predictor(raw, pp.predictor, pp.colors, pp.bpc, pp.columns, scratch)
|
||
|
|
|
||
|
|
case .Ccitt:
|
||
|
|
return ccitt_decode(data, filter_ccitt_params(doc, parms), scratch)
|
||
|
|
|
||
|
|
case .Crypt:
|
||
|
|
// Decryption is done at parse time, by the time any stream reaches
|
||
|
|
// here, so /Crypt is the identity. ISO 32000-2, 7.4.10.
|
||
|
|
return filter_copy(data, scratch)
|
||
|
|
|
||
|
|
case .Dct, .Jbig2:
|
||
|
|
// Decoded by the image layer, which needs the image dictionary to make
|
||
|
|
// sense of the samples. `stream_image_data` is the way in.
|
||
|
|
return data, .Unsupported_Image
|
||
|
|
|
||
|
|
case .Jpx:
|
||
|
|
return data, .Unsupported_Jpx
|
||
|
|
|
||
|
|
case .Unknown:
|
||
|
|
return data, .Unknown_Filter
|
||
|
|
}
|
||
|
|
return data, .Unknown_Filter
|
||
|
|
}
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
filter_copy :: proc(data: []byte, allocator: mem.Allocator) -> (out: []byte, err: Error) {
|
||
|
|
if len(data) == 0 {
|
||
|
|
return nil, .None
|
||
|
|
}
|
||
|
|
buf, aerr := make([]byte, len(data), allocator)
|
||
|
|
if aerr != nil {
|
||
|
|
return nil, .Out_Of_Memory
|
||
|
|
}
|
||
|
|
copy(buf, data)
|
||
|
|
return buf, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Whole streams
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
// stream_data decodes a stream's whole filter chain and caches the result.
|
||
|
|
//
|
||
|
|
// The bytes belong to the Document (they are allocated in its arena, or are a
|
||
|
|
// sub-slice of the file when the stream has no filters) and must not be freed.
|
||
|
|
// Calling this twice returns the same slice without decoding again.
|
||
|
|
//
|
||
|
|
// A stream that will not decode is reported as empty, with a .Bad_Filter_Data
|
||
|
|
// repair on the Document and `Stream.state` left at .Failed; the error return
|
||
|
|
// is reserved for a caller mistake. This is the difference between a reader
|
||
|
|
// and a validator: one broken image must not cost a page.
|
||
|
|
//
|
||
|
|
// With a nil Document there is no arena to allocate from, so the cached bytes
|
||
|
|
// come from the context allocator and belong to the caller -- except for a
|
||
|
|
// stream with no filters, which still borrows the file. `Stream.raw` says
|
||
|
|
// which of the two you have.
|
||
|
|
stream_data :: proc(doc: ^Document, s: ^Stream) -> (data: []byte, err: Error) {
|
||
|
|
if s == nil {
|
||
|
|
return nil, .Invalid_Argument
|
||
|
|
}
|
||
|
|
switch s.state {
|
||
|
|
case .Decoded:
|
||
|
|
return s.decoded, .None
|
||
|
|
case .Failed:
|
||
|
|
return nil, .None
|
||
|
|
case .Pending:
|
||
|
|
}
|
||
|
|
|
||
|
|
allocator := context.allocator
|
||
|
|
if doc != nil {
|
||
|
|
allocator = doc.allocator
|
||
|
|
}
|
||
|
|
|
||
|
|
// An empty payload decodes to nothing whatever the chain says. Running
|
||
|
|
// flate over it would only manufacture a repair for a stream that is
|
||
|
|
// legitimately empty -- an empty content stream is written this way.
|
||
|
|
if len(s.raw) == 0 {
|
||
|
|
s.decoded = nil
|
||
|
|
s.state = .Decoded
|
||
|
|
return nil, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
steps: [MAX_FILTER_CHAIN]Filter_Step
|
||
|
|
n, chain_ok := filter_chain(doc, s.dict, steps[:])
|
||
|
|
if !chain_ok {
|
||
|
|
return stream_failed(doc, s)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Only the last stage's output is worth keeping, so the ones before it are
|
||
|
|
// scratch: each is freed as soon as the next stage has read it, and the
|
||
|
|
// survivor is copied into `allocator` at the end. Giving `allocator` every
|
||
|
|
// stage instead would strand the intermediates of an /ASCII85Decode over a
|
||
|
|
// /FlateDecode in the Document arena for the life of the document -- the
|
||
|
|
// arena cannot free them and ARCHITECTURE.md forbids asking it to -- and
|
||
|
|
// with no Document at all it would leak them outright.
|
||
|
|
scratch := context.allocator
|
||
|
|
cur := s.raw
|
||
|
|
tmp: []byte
|
||
|
|
filtered := false
|
||
|
|
defer delete(tmp, scratch)
|
||
|
|
|
||
|
|
for i in 0 ..< n {
|
||
|
|
if steps[i].kind == .Crypt {
|
||
|
|
// Identity here, and skipping it avoids copying the payload for
|
||
|
|
// nothing.
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
next, ferr := apply_filter(doc, steps[i].name, cur, steps[i].parms, scratch)
|
||
|
|
if ferr != .None {
|
||
|
|
return stream_failed(doc, s)
|
||
|
|
}
|
||
|
|
delete(tmp, scratch)
|
||
|
|
tmp = next
|
||
|
|
cur = next
|
||
|
|
filtered = true
|
||
|
|
}
|
||
|
|
|
||
|
|
if !filtered {
|
||
|
|
// No /Filter at all, or a chain of nothing but /Crypt, which was
|
||
|
|
// already applied at parse time. The payload is still a sub-slice of
|
||
|
|
// the file, so there is nothing to copy and nothing to own -- and a
|
||
|
|
// caller with a nil Document must not free what it gets back here.
|
||
|
|
s.decoded = s.raw
|
||
|
|
s.state = .Decoded
|
||
|
|
return s.decoded, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
out := cur
|
||
|
|
if allocator == scratch {
|
||
|
|
// Where the two are the same allocator -- a nil Document -- the last
|
||
|
|
// stage already produced the buffer the caller keeps. Hand ownership
|
||
|
|
// over instead of copying it and freeing the original.
|
||
|
|
tmp = nil
|
||
|
|
} else {
|
||
|
|
cerr: Error
|
||
|
|
out, cerr = filter_copy(cur, allocator)
|
||
|
|
if cerr != .None {
|
||
|
|
return stream_failed(doc, s)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
s.decoded = out
|
||
|
|
s.state = .Decoded
|
||
|
|
return out, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
stream_failed :: proc(doc: ^Document, s: ^Stream) -> (data: []byte, err: Error) {
|
||
|
|
add_repair(doc, .Bad_Filter_Data, 0, s.ref)
|
||
|
|
s.decoded = nil
|
||
|
|
s.state = .Failed
|
||
|
|
return nil, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
// stream_data_raw returns the stream's bytes exactly as stored -- still
|
||
|
|
// filtered, but already decrypted. Borrowed from the Document; do not free.
|
||
|
|
stream_data_raw :: proc(doc: ^Document, s: ^Stream) -> []byte {
|
||
|
|
if s == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return s.raw
|
||
|
|
}
|
||
|
|
|
||
|
|
// stream_image_data decodes everything up to the stream's image filter.
|
||
|
|
//
|
||
|
|
// An image whose final filter is DCTDecode, JPXDecode, JBIG2Decode or
|
||
|
|
// CCITTFaxDecode is decoded straight to pixels by the raster path, which needs
|
||
|
|
// the image dictionary to do it. So this walks the chain applying only the
|
||
|
|
// byte filters, stops at the first image filter, and returns the bytes that
|
||
|
|
// filter would have been given, its unabbreviated name and its parameters.
|
||
|
|
// `image_filter` is "" when the chain held no image filter, in which case
|
||
|
|
// `data` is the finished sample bytes.
|
||
|
|
//
|
||
|
|
// The result is allocated with `allocator` and belongs to the caller. A JPX or
|
||
|
|
// JBIG2 codestream comes back intact and without an error: deciding what to do
|
||
|
|
// with a format this layer does not decode is the image layer's business.
|
||
|
|
stream_image_data :: proc(doc: ^Document, s: ^Stream, allocator := context.allocator) ->
|
||
|
|
(data: []byte, image_filter: string, parms: ^Dict, err: Error) {
|
||
|
|
if s == nil {
|
||
|
|
return nil, "", nil, .Invalid_Argument
|
||
|
|
}
|
||
|
|
|
||
|
|
steps: [MAX_FILTER_CHAIN]Filter_Step
|
||
|
|
n, chain_ok := filter_chain(doc, s.dict, steps[:])
|
||
|
|
if !chain_ok {
|
||
|
|
add_repair(doc, .Bad_Filter_Data, 0, s.ref)
|
||
|
|
return nil, "", nil, .Unknown_Filter
|
||
|
|
}
|
||
|
|
|
||
|
|
// Intermediates are scratch and are freed as the chain advances; only the
|
||
|
|
// last result is copied into `allocator`. Keeping them out of `allocator`
|
||
|
|
// means this is leak-free even when the caller hands us an arena it never
|
||
|
|
// frees individually.
|
||
|
|
cur := s.raw
|
||
|
|
tmp: []byte
|
||
|
|
defer delete(tmp, context.allocator)
|
||
|
|
|
||
|
|
for i in 0 ..< n {
|
||
|
|
if filter_is_image(steps[i].kind) {
|
||
|
|
out, cerr := filter_copy(cur, allocator)
|
||
|
|
if cerr != .None {
|
||
|
|
return nil, "", nil, cerr
|
||
|
|
}
|
||
|
|
return out, filter_name(steps[i].kind, steps[i].name), steps[i].parms, .None
|
||
|
|
}
|
||
|
|
if steps[i].kind == .Crypt {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
next, ferr := apply_filter(doc, steps[i].name, cur, steps[i].parms, context.allocator)
|
||
|
|
if ferr != .None {
|
||
|
|
add_repair(doc, .Bad_Filter_Data, 0, s.ref)
|
||
|
|
return nil, "", nil, ferr
|
||
|
|
}
|
||
|
|
delete(tmp, context.allocator)
|
||
|
|
tmp = next
|
||
|
|
cur = next
|
||
|
|
}
|
||
|
|
|
||
|
|
out, cerr := filter_copy(cur, allocator)
|
||
|
|
if cerr != .None {
|
||
|
|
return nil, "", nil, cerr
|
||
|
|
}
|
||
|
|
return out, "", nil, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Predictors
|
||
|
|
//
|
||
|
|
// A predictor is not a filter: it is a reversible transform the encoder ran
|
||
|
|
// over the samples first, so that the compressor behind it sees mostly zeroes.
|
||
|
|
// ISO 32000-2, 7.4.4.4 defines two, both borrowed wholesale -- predictor 2 is
|
||
|
|
// TIFF 6.0's horizontal differencing, and 10..15 are the five PNG line filters
|
||
|
|
// (RFC 2083, 6). The PNG value is the *maximum* filter the encoder used;
|
||
|
|
// the actual filter is the first byte of each row, so all six PNG values
|
||
|
|
// behave identically on decode.
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
// DeviceN tops out at 32 colorants, and no predictor has ever been applied to
|
||
|
|
// anything wider.
|
||
|
|
@(private)
|
||
|
|
MAX_PREDICTOR_COLORS :: 32
|
||
|
|
@(private)
|
||
|
|
MAX_PREDICTOR_COLUMNS :: 1 << 20
|
||
|
|
// 16 MiB for a single row. An xref stream's rows are a handful of bytes and an
|
||
|
|
// image's are tens of kilobytes; this only exists so a /Columns out of a fuzzer
|
||
|
|
// cannot ask for an allocation the machine will not survive.
|
||
|
|
@(private)
|
||
|
|
MAX_PREDICTOR_ROW_BYTES :: 1 << 24
|
||
|
|
@(private)
|
||
|
|
MAX_PREDICTOR_OUTPUT :: 1 << 30
|
||
|
|
|
||
|
|
// apply_predictor undoes a /Predictor transform.
|
||
|
|
//
|
||
|
|
// `predictor` is the /Predictor value: 0 or 1 for none, 2 for TIFF horizontal
|
||
|
|
// differencing, 10..15 for the PNG line filters. `colors`, `bpc` and `columns`
|
||
|
|
// are /Colors, /BitsPerComponent and /Columns.
|
||
|
|
//
|
||
|
|
// Parameters that no image could have are rejected with .Bad_Predictor rather
|
||
|
|
// than clamped: unlike a damaged payload, a nonsensical /Columns means the
|
||
|
|
// output would be misaligned garbage, and garbage that looks like data is
|
||
|
|
// worse than nothing.
|
||
|
|
//
|
||
|
|
// A final row cut short by a truncated payload is zero-padded and kept.
|
||
|
|
// Damaged xref streams rely on this -- the last entry of a truncated xref
|
||
|
|
// stream is still worth having.
|
||
|
|
//
|
||
|
|
// The result is allocated with `allocator` and belongs to the caller.
|
||
|
|
apply_predictor :: proc(data: []byte, predictor, colors, bpc, columns: int,
|
||
|
|
allocator := context.allocator) -> (out: []byte, err: Error) {
|
||
|
|
png := false
|
||
|
|
switch {
|
||
|
|
case predictor == 0, predictor == 1:
|
||
|
|
// /Predictor 0 is not defined; files that write it mean "none".
|
||
|
|
return filter_copy(data, allocator)
|
||
|
|
case predictor == 2:
|
||
|
|
case predictor >= 10 && predictor <= 15:
|
||
|
|
png = true
|
||
|
|
case:
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
|
||
|
|
if colors < 1 || colors > MAX_PREDICTOR_COLORS {
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
switch bpc {
|
||
|
|
case 1, 2, 4, 8, 16:
|
||
|
|
case:
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
if columns < 1 || columns > MAX_PREDICTOR_COLUMNS {
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
|
||
|
|
row_bits := i64(columns) * i64(colors) * i64(bpc)
|
||
|
|
if row_bits > i64(MAX_PREDICTOR_ROW_BYTES) * 8 {
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
row_bytes := int((row_bits + 7) / 8)
|
||
|
|
if row_bytes < 1 {
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
if len(data) == 0 {
|
||
|
|
return nil, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
// A PNG row carries a leading filter tag; a TIFF row does not.
|
||
|
|
stride := row_bytes + 1 if png else row_bytes
|
||
|
|
rows := (len(data) + stride - 1) / stride
|
||
|
|
total := rows * row_bytes
|
||
|
|
if total < 1 || total > MAX_PREDICTOR_OUTPUT {
|
||
|
|
return nil, .Bad_Predictor
|
||
|
|
}
|
||
|
|
|
||
|
|
buf, aerr := make([]byte, total, allocator)
|
||
|
|
if aerr != nil {
|
||
|
|
return nil, .Out_Of_Memory
|
||
|
|
}
|
||
|
|
|
||
|
|
for r in 0 ..< rows {
|
||
|
|
row := buf[r * row_bytes:][:row_bytes]
|
||
|
|
src := r * stride + (1 if png else 0)
|
||
|
|
// `buf` came from make and is zeroed, so a short final row is padded
|
||
|
|
// by simply not copying over it.
|
||
|
|
if src < len(data) {
|
||
|
|
copy(row, data[src:min(src + row_bytes, len(data))])
|
||
|
|
}
|
||
|
|
if png {
|
||
|
|
tag := 0
|
||
|
|
if r * stride < len(data) {
|
||
|
|
tag = int(data[r * stride])
|
||
|
|
}
|
||
|
|
prev: []byte
|
||
|
|
if r > 0 {
|
||
|
|
prev = buf[(r - 1) * row_bytes:][:row_bytes]
|
||
|
|
}
|
||
|
|
predictor_png_row(row, prev, tag, max(1, (colors * bpc + 7) / 8))
|
||
|
|
} else {
|
||
|
|
predictor_tiff_row(row, colors, bpc, columns)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return buf, .None
|
||
|
|
}
|
||
|
|
|
||
|
|
// predictor_png_row reverses one PNG line filter in place. `prev` is the
|
||
|
|
// already reconstructed line above, or nil on the first line, where the
|
||
|
|
// filters are defined to read zeroes. `bpp` is the byte distance to the pixel
|
||
|
|
// on the left, at least 1 (RFC 2083, 6.1).
|
||
|
|
@(private)
|
||
|
|
predictor_png_row :: proc(row, prev: []byte, tag, bpp: int) {
|
||
|
|
n := len(row)
|
||
|
|
switch tag {
|
||
|
|
case 0: // None
|
||
|
|
case 1: // Sub
|
||
|
|
for i in bpp ..< n {
|
||
|
|
row[i] += row[i - bpp]
|
||
|
|
}
|
||
|
|
case 2: // Up
|
||
|
|
if prev == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for i in 0 ..< n {
|
||
|
|
row[i] += prev[i]
|
||
|
|
}
|
||
|
|
case 3: // Average
|
||
|
|
for i in 0 ..< n {
|
||
|
|
left := i >= bpp ? int(row[i - bpp]) : 0
|
||
|
|
up := prev != nil ? int(prev[i]) : 0
|
||
|
|
row[i] += byte((left + up) / 2)
|
||
|
|
}
|
||
|
|
case 4: // Paeth
|
||
|
|
for i in 0 ..< n {
|
||
|
|
a := i >= bpp ? int(row[i - bpp]) : 0
|
||
|
|
b := prev != nil ? int(prev[i]) : 0
|
||
|
|
c := prev != nil && i >= bpp ? int(prev[i - bpp]) : 0
|
||
|
|
row[i] += byte(predictor_paeth(a, b, c))
|
||
|
|
}
|
||
|
|
case:
|
||
|
|
// An undefined tag. Encoders do not emit one, but a byte lost from the
|
||
|
|
// front of the payload shifts every tag, and reading the row as
|
||
|
|
// unfiltered keeps the rest of the stream in step instead of failing
|
||
|
|
// the whole stream on one byte.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// predictor_paeth is the predictor of RFC 2083, 6.6, verbatim: of the three
|
||
|
|
// neighbours it picks whichever the linear estimate a+b-c is nearest to,
|
||
|
|
// resolving ties towards a then b.
|
||
|
|
@(private)
|
||
|
|
predictor_paeth :: proc(a, b, c: int) -> int {
|
||
|
|
p := a + b - c
|
||
|
|
pa := abs(p - a)
|
||
|
|
pb := abs(p - b)
|
||
|
|
pc := abs(p - c)
|
||
|
|
if pa <= pb && pa <= pc {
|
||
|
|
return a
|
||
|
|
}
|
||
|
|
if pb <= pc {
|
||
|
|
return b
|
||
|
|
}
|
||
|
|
return c
|
||
|
|
}
|
||
|
|
|
||
|
|
// predictor_tiff_row reverses TIFF horizontal differencing in place: every
|
||
|
|
// component is stored as its difference from the component `colors` positions
|
||
|
|
// earlier in the same row, modulo the component's own width.
|
||
|
|
@(private)
|
||
|
|
predictor_tiff_row :: proc(row: []byte, colors, bpc, columns: int) {
|
||
|
|
n := columns * colors
|
||
|
|
switch bpc {
|
||
|
|
case 8:
|
||
|
|
limit := min(n, len(row))
|
||
|
|
for i in colors ..< limit {
|
||
|
|
row[i] += row[i - colors]
|
||
|
|
}
|
||
|
|
case 16:
|
||
|
|
limit := min(n, len(row) / 2)
|
||
|
|
for i in colors ..< limit {
|
||
|
|
prev := u16(row[(i - colors) * 2]) << 8 | u16(row[(i - colors) * 2 + 1])
|
||
|
|
cur := u16(row[i * 2]) << 8 | u16(row[i * 2 + 1])
|
||
|
|
v := cur + prev
|
||
|
|
row[i * 2] = byte(v >> 8)
|
||
|
|
row[i * 2 + 1] = byte(v)
|
||
|
|
}
|
||
|
|
case 1, 2, 4:
|
||
|
|
// Sub-byte components are packed high bit first and never straddle a
|
||
|
|
// byte, since 1, 2 and 4 all divide 8.
|
||
|
|
mask := (1 << uint(bpc)) - 1
|
||
|
|
limit := min(n, len(row) * 8 / bpc)
|
||
|
|
for i in colors ..< limit {
|
||
|
|
v := predictor_bits_get(row, i - colors, bpc) + predictor_bits_get(row, i, bpc)
|
||
|
|
predictor_bits_set(row, i, bpc, v & mask)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
predictor_bits_get :: proc(row: []byte, index, bpc: int) -> int {
|
||
|
|
bit := index * bpc
|
||
|
|
at := bit >> 3
|
||
|
|
if at < 0 || at >= len(row) {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
shift := uint(8 - bpc - (bit & 7))
|
||
|
|
return int(row[at] >> shift) & ((1 << uint(bpc)) - 1)
|
||
|
|
}
|
||
|
|
|
||
|
|
@(private)
|
||
|
|
predictor_bits_set :: proc(row: []byte, index, bpc, value: int) {
|
||
|
|
bit := index * bpc
|
||
|
|
at := bit >> 3
|
||
|
|
if at < 0 || at >= len(row) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
shift := uint(8 - bpc - (bit & 7))
|
||
|
|
mask := byte(((1 << uint(bpc)) - 1) << shift)
|
||
|
|
row[at] = (row[at] & ~mask) | (byte(value) << shift) & mask
|
||
|
|
}
|