class Origami::Stream

Class representing a PDF Stream Object. Streams can be used to hold any kind of data, especially binary data.

Constants

Length

Attributes

dictionary[R]

Public Class Methods

new(data = "", dictionary = {}) click to toggle source

Creates a new PDF Stream.

data

The Stream uncompressed data.

dictionary

A hash representing the Stream attributes.

Calls superclass method Origami::Object::new
# File lib/origami/stream.rb, line 89
def initialize(data = "", dictionary = {})
    super()

    set_indirect(true)

    @encoded_data = nil
    @dictionary, @data = Dictionary.new(dictionary), data
    @dictionary.parent = self
end

Public Instance Methods

cast_to(type, _parser = nil) click to toggle source
Calls superclass method
# File lib/origami/stream.rb, line 246
def cast_to(type, _parser = nil)
    super(type)

    cast = type.new("", self.dictionary.copy)
    cast.encoded_data = self.encoded_data.dup
    cast.no, cast.generation = self.no, self.generation
    cast.set_indirect(true)
    cast.set_document(self.document)
    cast.file_offset = self.file_offset

    cast
end
data() click to toggle source

Returns the uncompressed stream content.

# File lib/origami/stream.rb, line 266
def data
    self.decode! unless decoded?

    @data
end
Also aliased as: decoded_data
data=(str) click to toggle source

Sets the uncompressed stream content.

str

The new uncompressed data.

# File lib/origami/stream.rb, line 277
def data=(str)
    @encoded_data = nil
    @data = str
end
Also aliased as: decoded_data=
decode!() click to toggle source

Uncompress the stream data.

# File lib/origami/stream.rb, line 304
def decode!
    self.decrypt! if self.is_a?(Encryption::EncryptedStream)
    return if decoded?

    filters = self.filters

    if filters.empty?
        @data = @encoded_data.dup
        return
    end

    unless filters.all?{|filter| filter.is_a?(Name)}
        raise InvalidStreamObjectError, "Invalid Filter type parameter"
    end

    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 if error.decoded_data
            raise
        end
    end

    self
end
decoded_data()
Alias for: data
decoded_data=(str)
Alias for: data=
dictionary=(dict) click to toggle source
# File lib/origami/stream.rb, line 99
def dictionary=(dict)
    @dictionary = dict
    @dictionary.parent = self
end
each_filter() { |filter| ... } click to toggle source

Iterates over each Filter in the Stream.

# File lib/origami/stream.rb, line 193
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
encode!() click to toggle source

Compress the stream data.

# File lib/origami/stream.rb, line 349
def encode!
    return if encoded?
    filters = self.filters

    if filters.empty?
        @encoded_data = @data.dup
        return
    end

    unless filters.all?{|filter| filter.is_a?(Name)}
        raise InvalidStreamObjectError, "Invalid Filter type parameter"
    end

    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
encoded_data() click to toggle source

Returns the raw compressed stream content.

# File lib/origami/stream.rb, line 286
def encoded_data
    self.encode! unless encoded?

    @encoded_data
end
encoded_data=(str) click to toggle source

Sets the raw compressed stream content.

str

the new raw data.

# File lib/origami/stream.rb, line 296
def encoded_data=(str)
    @encoded_data = str
    @data = nil
end
eval_js() click to toggle source

Evaluates the current Stream as JavaScript.

# File lib/origami/javascript.rb, line 690
def eval_js
    self.document.eval_js(self.data)
end
filters() click to toggle source

Returns an Array of Filters for this Stream.

# File lib/origami/stream.rb, line 219
def filters
    self.each_filter.to_a
end
has_key?(name)
Alias for: key?
key?(name) click to toggle source
# File lib/origami/stream.rb, line 408
def key?(name)
    @dictionary.key?(name)
end
Also aliased as: has_key?
post_build() click to toggle source
Calls superclass method Origami::Object#post_build
# File lib/origami/stream.rb, line 110
def post_build
    self.Length = @encoded_data.length

    super
end
pre_build() click to toggle source
Calls superclass method Origami::Object#pre_build
# File lib/origami/stream.rb, line 104
def pre_build
    encode!

    super
end
set_predictor(predictor, colors: 1, bitspercomponent: 8, columns: 1) click to toggle source

Set predictor type for the current Stream. Applies only for LZW and FlateDecode filters.

# File lib/origami/stream.rb, line 227
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
to_obfuscated_str() click to toggle source
Calls superclass method Origami::Object#to_obfuscated_str
# File lib/origami/obfuscation.rb, line 220
def to_obfuscated_str
    content = ""

    content << @dictionary.to_obfuscated_str
    content << "stream" + EOL
    content << self.encoded_data
    content << EOL << TOKENS.last

    super(content)
end

Private Instance Methods

decode_params() click to toggle source
# File lib/origami/stream.rb, line 446
def decode_params
    each_decode_params.to_a
end
each_decode_params() { |param| ... } click to toggle source
# File lib/origami/stream.rb, line 423
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