initial commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user