///|
fn pdf_decode_stream_filter_bytes(
filter : @core.PdfName,
dictionary : @syntax.PdfObject,
data : @core.PdfBytes,
) -> @core.PdfBytes raise @core.PdfError {
if pdf_filter_is_one_of(
filter, pdf_filter_lzw_decode_name, pdf_filter_lzw_short_name,
) {
@codec.pdf_lzw_decode(data, early_change=pdf_lzw_early_change(dictionary))
} else if pdf_filter_is_one_of(
filter, pdf_filter_ccitt_fax_decode_name, pdf_filter_ccitt_fax_short_name,
) {
pdf_ccitt_decode_view(data, pdf_ccitt_params(dictionary))
} else {
pdf_decode_filter_bytes(filter, data)
}
}
///|
fn PdfDocument::pdf_decode_stream_filter_bytes_direct(
self : PdfDocument,
filter : @core.PdfName,
dictionary : @syntax.PdfObject,
data : @core.PdfBytes,
) -> @core.PdfBytes raise @core.PdfError {
if pdf_filter_is_one_of(
filter, pdf_filter_lzw_decode_name, pdf_filter_lzw_short_name,
) {
@codec.pdf_lzw_decode(
data,
early_change=self.pdf_lzw_early_change_direct(dictionary),
)
} else if pdf_filter_is_one_of(
filter, pdf_filter_ccitt_fax_decode_name, pdf_filter_ccitt_fax_short_name,
) {
pdf_ccitt_decode_view(data, self.pdf_ccitt_params_direct(dictionary))
} else {
pdf_decode_filter_bytes(filter, data)
}
}
///|
fn pdf_decode_stream_onestage_value(
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
pdf_stream_dictionary_length(stream.dictionary)
let data = @syntax.pdf_stream_data_bytes(stream.data)
match pdf_stream_first_filter(stream.dictionary) {
None => {
let dictionary = pdf_stream_replace_length(
stream.dictionary,
data.length(),
)
{ dictionary, data: StreamGot(data), }
}
Some(filter) => {
let decoded = pdf_decode_stream_filter_bytes(
filter,
stream.dictionary,
data,
)
let unpredicted = pdf_apply_first_predictor(stream.dictionary, decoded)
let dictionary = pdf_stream_replace_length(
pdf_remove_first_decoder(stream.dictionary),
unpredicted.length(),
)
{ dictionary, data: StreamGot(unpredicted), }
}
}
}
///|
fn PdfDocument::pdf_stream_dictionary_length_direct(
self : PdfDocument,
dictionary : @syntax.PdfObject,
) -> Unit raise @core.PdfError {
match self.lookup_direct(pdf_codec_length_key(), dictionary) {
Some(PdfInteger(_)) => ()
_ => raise StreamLengthExpected
}
}
///|
fn PdfDocument::pdf_decode_stream_onestage_value_direct(
self : PdfDocument,
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
self.pdf_stream_dictionary_length_direct(stream.dictionary)
let data = @syntax.pdf_stream_data_bytes(stream.data)
match self.pdf_stream_first_filter_entry_direct(stream.dictionary) {
None => {
let dictionary = pdf_stream_replace_length(
stream.dictionary,
data.length(),
)
{ dictionary, data: StreamGot(data), }
}
Some((filter_key, filter_value, filter)) => {
let decoded = self.pdf_decode_stream_filter_bytes_direct(
filter,
stream.dictionary,
data,
)
let unpredicted = self.pdf_apply_first_predictor_direct(
stream.dictionary,
decoded,
)
let dictionary = pdf_stream_replace_length(
self.pdf_remove_first_decoder_direct(
stream.dictionary,
filter_key,
filter_value,
),
unpredicted.length(),
)
{ dictionary, data: StreamGot(unpredicted), }
}
}
}
///|
/// Decode exactly one filter stage from a stream object.
///
/// The first filter and matching decode parameters are removed from the stream
/// dictionary, and `/Length` is refreshed. Non-stream objects raise
/// `@core.PdfError::ParseStreamExpected`.
pub fn pdf_decode_stream_onestage(
object : @syntax.PdfObject,
) -> @syntax.PdfObject raise @core.PdfError {
match object {
PdfStreamObject(stream) =>
PdfStreamObject(pdf_decode_stream_onestage_value(stream))
_ => raise ParseStreamExpected
}
}
///|
fn PdfDocument::pdf_stream_has_filter_value_direct(
self : PdfDocument,
stream : @syntax.PdfStream,
) -> Bool raise @core.PdfError {
self.pdf_stream_first_filter_direct(stream.dictionary) != None
}
///|
fn PdfDocument::pdf_decode_stream_value_direct(
self : PdfDocument,
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
let mut current = stream
let mut stages = 0
while self.pdf_stream_has_filter_value_direct(current) {
if stages >= 1024 {
raise FilterExpected
}
current = self.pdf_decode_stream_onestage_value_direct(current)
stages += 1
}
self.pdf_decode_stream_onestage_value_direct(current)
}
///|
/// Decode all supported filter stages from a stream object in this document.
///
/// Indirect filter and decode-parameter objects are resolved through the
/// document. Unsupported filters raise `@core.PdfError::FilterNotSupported`.
pub fn PdfDocument::pdf_decode_stream(
self : PdfDocument,
object : @syntax.PdfObject,
) -> @syntax.PdfObject raise @core.PdfError {
match self.direct(object) {
PdfStreamObject(stream) =>
PdfStreamObject(self.pdf_decode_stream_value_direct(stream))
_ => raise ParseStreamExpected
}
}
///|
fn PdfDocument::pdf_decode_stream_until_unknown_value_direct(
self : PdfDocument,
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
let mut current = stream
let mut stages = 0
let mut stopped = false
while !stopped && self.pdf_stream_has_filter_value_direct(current) {
if stages >= 1024 {
raise FilterExpected
}
try self.pdf_decode_stream_onestage_value_direct(current) catch {
FilterNotSupported(_) => stopped = true
error => raise error
} noraise {
decoded => {
current = decoded
stages += 1
}
}
}
if stopped {
current
} else {
self.pdf_decode_stream_onestage_value_direct(current)
}
}
///|
/// Decode supported filter stages until the first unsupported filter.
///
/// The unsupported filter and remaining filters stay in the stream dictionary;
/// malformed supported filters still raise.
pub fn PdfDocument::pdf_decode_stream_until_unknown(
self : PdfDocument,
object : @syntax.PdfObject,
) -> @syntax.PdfObject raise @core.PdfError {
match self.direct(object) {
PdfStreamObject(stream) =>
PdfStreamObject(self.pdf_decode_stream_until_unknown_value_direct(stream))
_ => raise ParseStreamExpected
}
}
///|
fn pdf_decode_stream_until_unknown_value(
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
pdf_document_empty().pdf_decode_stream_until_unknown_value_direct(stream)
}
///|
/// Decode supported filter stages on every parsed stream in the document.
///
/// Streams already marked as decrypted stay in that state. Objects are updated
/// in place and logged as altered when their stream data changes.
pub fn PdfDocument::pdf_decode_streams_until_unknown(
self : PdfDocument,
) -> Unit raise @core.PdfError {
for number in self.objects.object_numbers() {
let entry = self.objects.get_entry(number).unwrap()
match entry.data {
ObjectParsed(PdfStreamObject(stream)) => {
let decoded = self.pdf_decode_stream_until_unknown_value_direct(stream)
self.objects.set_entry(number, {
data: ObjectParsed(PdfStreamObject(decoded)),
generation: entry.generation,
})
self.objects.log.push((number, ObjectAltered))
}
ObjectParsedAlreadyDecrypted(PdfStreamObject(stream)) => {
let decoded = self.pdf_decode_stream_until_unknown_value_direct(stream)
self.objects.set_entry(number, {
data: ObjectParsedAlreadyDecrypted(PdfStreamObject(decoded)),
generation: entry.generation,
})
self.objects.log.push((number, ObjectAltered))
}
_ => ()
}
}
}
///|
fn pdf_stream_has_filter_value(
stream : @syntax.PdfStream,
) -> Bool raise @core.PdfError {
pdf_stream_first_filter(stream.dictionary) != None
}
///|
fn pdf_decode_stream_value(
stream : @syntax.PdfStream,
) -> @syntax.PdfStream raise @core.PdfError {
let mut current = stream
let mut stages = 0
while pdf_stream_has_filter_value(current) {
if stages >= 1024 {
raise FilterExpected
}
current = pdf_decode_stream_onestage_value(current)
stages += 1
}
pdf_decode_stream_onestage_value(current)
}
///|
/// Decode all supported filter stages from a direct stream object.
pub fn pdf_decode_stream(
object : @syntax.PdfObject,
) -> @syntax.PdfObject raise @core.PdfError {
match object {
PdfStreamObject(stream) => PdfStreamObject(pdf_decode_stream_value(stream))
_ => raise ParseStreamExpected
}
}