Class: Origami::Array

Inherits:
Array
  • Object
show all
Includes:
CompoundObject
Defined in:
lib/origami/array.rb,
lib/origami/obfuscation.rb

Overview

Class representing an Array Object. Arrays contain a set of Object.

Direct Known Subclasses

Destination

Constant Summary collapse

TOKENS =

:nodoc:

%w{ [ ] }
@@regexp_open =
Regexp.new(WHITESPACES + Regexp.escape(TOKENS.first) + WHITESPACES)
@@regexp_close =
Regexp.new(WHITESPACES + Regexp.escape(TOKENS.last) + WHITESPACES)

Instance Attribute Summary

Attributes included from ObjectCache

#names_cache, #strings_cache, #xref_cache

Attributes included from Object

#file_offset, #generation, #no, #objstm_offset, #parent

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CompoundObject

#copy, #delete, #include?, #update_values, #update_values!

Methods included from ObjectCache

#rebuild_caches

Methods included from Object

#cast_to, #copy, #document, #export, included, #indirect?, #indirect_parent, #logicalize, #logicalize!, #native_type, #numbered?, #post_build, #reference, #set_document, #set_indirect, skip_until_next_obj, #solve, #to_o, #type, typeof, #version_required, #xrefs

Constructor Details

#initialize(data = [], parser = nil, hint_type: nil) ⇒ Array

Creates a new PDF Array Object.

data

An array of objects.

Raises:

  • (TypeError)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/origami/array.rb', line 43

def initialize(data = [], parser = nil, hint_type: nil)
    raise TypeError, "Expected type Array, received #{data.class}." unless data.is_a?(::Array)
    super()

    data.each_with_index do |value, index|
        value = value.to_o

        if Origami::OPTIONS[:enable_type_guessing]
            index_type = hint_type.is_a?(::Array) ? hint_type[index % hint_type.size] : hint_type
            if index_type.is_a?(::Array) and not value.is_a?(Reference)
                index_type = index_type.find {|type| type < value.class }
            end

            if index_type.is_a?(Class) and index_type < value.class
                value = value.cast_to(index_type, parser)
            end

            if index_type and parser and Origami::OPTIONS[:enable_type_propagation]
                if value.is_a?(Reference)
                    parser.defer_type_cast(value, index_type)
                end
            end
        end

        self.push(value)
    end
end

Class Method Details

.of(klass, *klasses, length: nil) ⇒ Object

Parameterized Array class with additional typing information. Example: Array.of(Integer)



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/origami/array.rb', line 162

def self.of(klass, *klasses, length: nil)
    Class.new(self) do
        const_set('ARRAY_TYPE', (klasses.empty? and not klass.is_a?(::Array)) ? klass : [ klass ].concat(klasses))
        const_set('STATIC_LENGTH', length)

        def initialize(data = [], parser = nil)
            super(data, parser, hint_type: self.class.const_get('ARRAY_TYPE'))
        end

        def pre_build #:nodoc:
            do_type_check if Origami::OPTIONS[:enable_type_checking]

            super
        end

        def self.parse(stream, parser = nil)
            super(stream, parser, hint_type: const_get('ARRAY_TYPE'))
        end

        def do_type_check #:nodoc:
            static_length = self.class.const_get('STATIC_LENGTH')
            array_type = self.class.const_get('ARRAY_TYPE')

            if static_length and self.length != static_length
                STDERR.puts "Warning: object #{self.class.name} has unexpected length #{self.length} (should be #{static_length})"
            end

            self.each_with_index do |object, index|
                index_type = array_type.is_a?(::Array) ? array_type[index % array_type.size] : array_type

                begin
                    object_value = object.solve
                rescue InvalidReferenceError
                    STDERR.puts "Warning: in object #{self.class}, invalid reference at index #{index}"
                    next
                end

                unless object_value.is_a?(index_type)
                    STDERR.puts "Warning: object #{self.class.name || 'Array'} should be composed of #{index_type.name} at index #{index} (got #{object_value.type} instead)"
                end
            end
        end
    end
end

.parse(stream, parser = nil, hint_type: nil) ⇒ Object

:nodoc:



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/origami/array.rb', line 77

def self.parse(stream, parser = nil, hint_type: nil) #:nodoc:
    scanner = Parser.init_scanner(stream)
    offset = scanner.pos
    data = []

    if not scanner.skip(@@regexp_open)
        raise InvalidArrayObjectError, "No token '#{TOKENS.first}' found"
    end

    while scanner.skip(@@regexp_close).nil? do
        type = Object.typeof(scanner)
        raise InvalidArrayObjectError, "Bad embedded object format" if type.nil?

        value = type.parse(scanner, parser)
        data << value
    end

    array = Array.new(data, parser, hint_type: hint_type)
    array.file_offset = offset

    array
end

Instance Method Details

#+(other) ⇒ Object



127
128
129
130
131
132
# File 'lib/origami/array.rb', line 127

def +(other)
    a = Origami::Array.new(self.to_a + other.to_a)
    a.no, a.generation = @no, @generation

    a
end

#<<(item) ⇒ Object



134
135
136
# File 'lib/origami/array.rb', line 134

def <<(item)
    super link_object(item)
end

#[]=(index, item) ⇒ Object



142
143
144
# File 'lib/origami/array.rb', line 142

def []=(index, item)
    super(index, link_object(item))
end

#concat(*arys) ⇒ Object



154
155
156
# File 'lib/origami/array.rb', line 154

def concat(*arys)
    self.push(*arys.flatten)
end

#insert(index, *items) ⇒ Object



146
147
148
149
150
151
152
# File 'lib/origami/array.rb', line 146

def insert(index, *items)
    items.reverse_each do |item|
        super(index, link_object(item))
    end

    self
end

#pre_buildObject



71
72
73
74
75
# File 'lib/origami/array.rb', line 71

def pre_build
    self.map!(&:to_o)

    super
end

#push(*items) ⇒ Object



138
139
140
# File 'lib/origami/array.rb', line 138

def push(*items)
    items.each {|item| self << item }
end

#to_aObject Also known as: value

Converts self into a Ruby array.



103
104
105
# File 'lib/origami/array.rb', line 103

def to_a
    super.map(&:value)
end

#to_obfuscated_strObject



154
155
156
157
158
159
160
161
162
163
# File 'lib/origami/obfuscation.rb', line 154

def to_obfuscated_str
    content = TOKENS.first + Obfuscator.junk_spaces
    self.each do |entry|
        content << entry.to_o.to_obfuscated_str + Obfuscator.junk_spaces
    end

    content << TOKENS.last

    super(content)
end

#to_s(eol: $/) ⇒ Object

:nodoc:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/origami/array.rb', line 110

def to_s(eol: $/) #:nodoc:
    content = TOKENS.first.dup
    content << self.map {|entry|
        entry = entry.to_o

        case entry
        when Dictionary # Do not indent dictionaries inside of arrays.
            entry.to_s(indent: 0, eol: eol)
        else
            entry.to_s(eol: eol)
        end
    }.join(' ')
    content << TOKENS.last

    super(content, eol: eol)
end