package pdf // RunLengthDecode: byte-oriented RLE, ISO 32000-2, 7.4.5. // // The stream is a sequence of length bytes: // // 0..127 the next length+1 bytes are literal // 128 end of data // 129..255 the next byte repeats 257-length times (2..128) // // Only ever seen on scanned images from older producers, and on those the data // is as likely to be truncated as not, so running out of input mid-run ends // the stream with what was decoded so far instead of failing. // The filter expands by at most 128x, so a hostile stream can ask for a // gigabyte from eight megabytes of input. Decoding stops at this point; a real // image that needs more than this is not one we could raster anyway. @(private = "file") MAX_RUN_LENGTH_OUTPUT :: 1 << 30 // run_length_decode decodes RunLengthDecode data. // // A missing EOD marker, or input that ends inside a run, ends the stream // rather than failing. // // The returned slice is owned by the caller and allocated with `allocator`. run_length_decode :: proc(data: []byte, allocator := context.allocator) -> (out: []byte, err: Error) { n := run_length_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 } run_length_scan(data, buf) return buf, .None } // run_length_scan measures the output when `out` is nil and fills it // otherwise; see the note in filter_ascii.odin on why the work is done twice. @(private) run_length_scan :: proc(data: []byte, out: []byte) -> int { n := 0 i := 0 // `i` strictly increases on every branch, so the loop is bounded by the // input length without needing separate fuel. for i < len(data) { length := int(data[i]) i += 1 if length == 128 { break } if length < 128 { count := length + 1 // A literal run reaching past the end takes what is there; the // stream is truncated, and the bytes before the cut are still good. if count > len(data) - i { count = len(data) - i } for k in 0 ..< count { if n >= MAX_RUN_LENGTH_OUTPUT { return n } if n < len(out) { out[n] = data[i + k] } n += 1 } i += count if count < length + 1 { break } continue } if i >= len(data) { break } b := data[i] i += 1 count := 257 - length for _ in 0 ..< count { if n >= MAX_RUN_LENGTH_OUTPUT { return n } if n < len(out) { out[n] = b } n += 1 } } return n }