class Origami::Stream
def self.parse(stream, parser = nil) #:nodoc:
def self.parse(stream, parser = nil) #:nodoc: scanner = Parser.init_scanner(stream) dictionary = Dictionary.parse(scanner, parser) return dictionary if not scanner.skip(@@regexp_open) length = dictionary[:Length] if not length.is_a?(Integer) raw_data = scanner.scan_until(@@regexp_close) if raw_data.nil? raise InvalidStreamObjectError, "Stream shall end with a 'endstream' statement" end else length = length.value raw_data = scanner.peek(length) scanner.pos += length if not ( unmatched = scanner.scan_until(@@regexp_close) ) raise InvalidStreamObjectError, "Stream shall end with a 'endstream' statement" end raw_data << unmatched end stm = if Origami::OPTIONS[:enable_type_guessing] self.guess_type(dictionary).new('', dictionary) else Stream.new('', dictionary) end raw_data.chomp!(TOKENS.last) if raw_data[-1,1] == "\n" if raw_data[-2,1] == "\r" raw_data = raw_data[0, raw_data.size - 2] else raw_data = raw_data[0, raw_data.size - 1] end end #raw_data.chomp! if length.is_a?(Integer) and length < raw_data.length stm.encoded_data = raw_data stm.file_offset = dictionary.file_offset stm end
def [](key) #:nodoc:
def [](key) #:nodoc: @dictionary[key] end
def []=(key, val) #:nodoc:
def []=(key, val) #:nodoc: @dictionary[key] = val end
def cast_to(type, _parser = nil)
def cast_to(type, _parser = nil) assert_cast_type(type) cast = type.new("", self.dictionary.copy) cast.encoded_data = self.encoded_data.dup cast.file_offset = self.file_offset transfer_attributes(cast) end
def data
Returns the uncompressed stream content.
def data self.decode! unless decoded? @data end
def data=(str)
_str_:: The new uncompressed data.
Sets the uncompressed stream content.
def data=(str) @encoded_data = nil @data = str end
def decode!
Uncompress the stream data.
def decode! self.decrypt! if self.is_a?(Encryption::EncryptedStream) return if decoded? filters = self.filters dparams = decode_params @data = @encoded_data.dup @data.freeze filters.each_with_index do |filter, layer| params = dparams[layer].is_a?(Dictionary) ? dparams[layer] : {} # Handle Crypt filters. if filter == :Crypt raise Filter::Error, "Crypt filter must be the first filter" unless layer.zero? # Skip the Crypt filter. next end begin @data = decode_data(@data, filter, params) rescue Filter::Error => error @data = error.decoded_data raise end end self end
def decode_data(data, filter, params) #:nodoc:
def decode_data(data, filter, params) #:nodoc: filter_module(filter).decode(data, params) end
def decode_params
def decode_params each_decode_params.to_a end
def decoded? #:nodoc:
def decoded? #:nodoc: not @data.nil? end
def dictionary=(dict)
def dictionary=(dict) @dictionary = dict @dictionary.parent = self end
def each_decode_params
def each_decode_params params = self.DecodeParms return enum_for(__method__) do case params when NilClass then 0 when Array then params.length else 1 end end unless block_given? return if params.nil? if params.is_a?(Array) params.each do |param| yield(param) end else yield(params) end self end
def each_filter
Iterates over each Filter in the Stream.
def each_filter filters = self.Filter return enum_for(__method__) do case filters when NilClass then 0 when Array then filters.length else 1 end end unless block_given? return if filters.nil? if filters.is_a?(Array) filters.each do |filter| yield(filter) end else yield(filters) end self end
def each_key(&b) #:nodoc:
def each_key(&b) #:nodoc: @dictionary.each_key(&b) end
def each_pair(&b) #:nodoc
def each_pair(&b) #:nodoc @dictionary.each_pair(&b) end
def encode!
Compress the stream data.
def encode! return if encoded? filters = self.filters dparams = decode_params @encoded_data = @data.dup (filters.length - 1).downto(0) do |layer| params = dparams[layer].is_a?(Dictionary) ? dparams[layer] : {} filter = filters[layer] # Handle Crypt filters. if filter == :Crypt raise Filter::Error, "Crypt filter must be the first filter" unless layer.zero? # Skip the Crypt filter. next end @encoded_data = encode_data(@encoded_data, filter, params) end self.Length = @encoded_data.length self end
def encode_data(data, filter, params) #:nodoc:
def encode_data(data, filter, params) #:nodoc: mod = filter_module(filter) encoded = mod.encode(data, params) if %i[ASCIIHexDecode ASCII85Decode AHx A85].include?(filter.value) encoded << mod::EOD end encoded end
def encoded? #:nodoc:
def encoded? #:nodoc: not @encoded_data.nil? end
def encoded_data
Returns the raw compressed stream content.
def encoded_data self.encode! unless encoded? @encoded_data end
def encoded_data=(str)
_str_:: the new raw data.
Sets the raw compressed stream content.
def encoded_data=(str) @encoded_data = str @data = nil end
def eval_js
Evaluates the current Stream as JavaScript.
def eval_js self.document.eval_js(self.data) end
def filter_module(name)
def filter_module(name) unless name.is_a?(Name) raise InvalidObjectStreamObjectError, "Filter has invalid type #{name.type}" end unless DEFINED_FILTERS.include?(name.value) raise InvalidStreamObjectError, "Invalid filter : #{name}" end Filter.const_get(name.value.to_s.sub(/Decode$/, "")) end
def filters
Returns an Array of Filters for this Stream.
def filters self.each_filter.to_a end
def initialize(data = ::String.new, dictionary = {})
_dictionary_:: A hash representing the Stream attributes.
_data_:: The Stream uncompressed data.
Creates a new PDF Stream.
def initialize(data = ::String.new, dictionary = {}) super() set_indirect(true) @encoded_data = nil @dictionary, @data = Dictionary.new(dictionary), data @dictionary.parent = self end
def key?(name)
def key?(name) @dictionary.key?(name) end
def keys
def keys @dictionary.keys end
def post_build
def post_build self.Length = @encoded_data.length super end
def pre_build
def pre_build encode! super end
def set_decode_params(layer, params) #:nodoc:
def set_decode_params(layer, params) #:nodoc: dparms = self.DecodeParms unless dparms.is_a? ::Array @dictionary[:DecodeParms] = dparms = [] end if layer > dparms.length - 1 dparms.concat(::Array.new(layer - dparms.length + 1, Null.new)) end dparms[layer] = params @dictionary[:DecodeParms] = dparms.first if dparms.length == 1 self end
def set_predictor(predictor, colors: 1, bitspercomponent: 8, columns: 1)
Applies only for LZW and FlateDecode filters.
Set predictor type for the current Stream.
def set_predictor(predictor, colors: 1, bitspercomponent: 8, columns: 1) filters = self.filters layer = filters.index(:FlateDecode) or filters.index(:LZWDecode) if layer.nil? raise InvalidStreamObjectError, 'Predictor functions can only be used with Flate or LZW filters' end params = Filter::LZW::DecodeParms.new params[:Predictor] = predictor params[:Colors] = colors if colors != 1 params[:BitsPerComponent] = bitspercomponent if bitspercomponent != 8 params[:Columns] = columns if columns != 1 set_decode_params(layer, params) self end
def to_obfuscated_str
def to_obfuscated_str content = ::String.new content << @dictionary.to_obfuscated_str content << "stream" + $/ content << self.encoded_data content << $/ << TOKENS.last super(content) end
def to_s(indent: 1, tab: "\t", eol: $/) #:nodoc:
def to_s(indent: 1, tab: "\t", eol: $/) #:nodoc: content = ::String.new content << @dictionary.to_s(indent: indent, tab: tab) content << "stream" + eol content << self.encoded_data content << eol << TOKENS.last super(content, eol: eol) end
def value #:nodoc:
def value #:nodoc: self end