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)


41
42
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
# File 'lib/origami/array.rb', line 41

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) && !value.is_a?(Reference)
        index_type = index_type.find { |type| type < value.class }
      end

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

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

    push(value)
  end
end

Class Method Details

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

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



160
161
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
# File 'lib/origami/array.rb', line 160

def self.of(klass, *klasses, length: nil)
  Class.new(self) do
    const_set('ARRAY_TYPE', (klasses.empty? && !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 && (self.length != static_length)
        warn "Warning: object #{self.class.name} has unexpected length #{self.length} (should be #{static_length})"
      end

      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
          warn "Warning: in object #{self.class}, invalid reference at index #{index}"
          next
        end

        unless object_value.is_a?(index_type)
          warn "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:



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

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

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

  while scanner.skip(@@regexp_close).nil?
    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



125
126
127
128
129
130
# File 'lib/origami/array.rb', line 125

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

  a
end

#<<(item) ⇒ Object



132
133
134
# File 'lib/origami/array.rb', line 132

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

#[]=(index, item) ⇒ Object



140
141
142
# File 'lib/origami/array.rb', line 140

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

#concat(*arys) ⇒ Object



152
153
154
# File 'lib/origami/array.rb', line 152

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

#insert(index, *items) ⇒ Object



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

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

  self
end

#pre_buildObject



69
70
71
72
73
# File 'lib/origami/array.rb', line 69

def pre_build
  map!(&:to_o)

  super
end

#push(*items) ⇒ Object



136
137
138
# File 'lib/origami/array.rb', line 136

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

#to_aObject Also known as: value

Converts self into a Ruby array.



101
102
103
# File 'lib/origami/array.rb', line 101

def to_a
  super.map(&:value)
end

#to_obfuscated_strObject



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

def to_obfuscated_str
  content = TOKENS.first + Obfuscator.junk_spaces
  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:



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

def to_s(eol: $/) # :nodoc:
  content = TOKENS.first.dup
  content << 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