class Origami::Stream

def self.parse(stream, parser = nil) #:nodoc:

: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:

:nodoc:
def [](key) #:nodoc:
    @dictionary[key]
end

def []=(key, val) #:nodoc:

: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:

: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:

: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:

:nodoc:
def each_key(&b) #:nodoc:
    @dictionary.each_key(&b)
end

def each_pair(&b) #:nodoc

: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:

: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:

: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:

: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:

: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:

:nodoc:
def value #:nodoc:
    self
end