Class: Origami::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/origami/parser.rb

Overview

:nodoc:

Defined Under Namespace

Classes: ParsingError

Constant Summary collapse

VERBOSE_QUIET =

Do not output debug information.

0
VERBOSE_INFO =

Output some useful information.

1
VERBOSE_DEBUG =

Output debug information.

2
VERBOSE_TRACE =

Output every objects read

3

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Parser

:nodoc:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/origami/parser.rb', line 53

def initialize(options = {}) #:nodoc:
    # Type information for indirect objects.
    @deferred_casts = {}

    #Default options values
    @options =
    {
        verbosity: VERBOSE_INFO, # Verbose level.
        ignore_errors: true,     # Try to keep on parsing when errors occur.
        callback: Proc.new {},   # Callback procedure whenever a structure is read.
        logger: STDERR,          # Where to output parser messages.
        colorize_log: true       # Colorize parser output?
    }

    @options.update(options)
    @logger = @options[:logger]
    @data = nil
end

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



51
52
53
# File 'lib/origami/parser.rb', line 51

def options
  @options
end

Class Method Details

.init_scanner(stream) ⇒ Object



211
212
213
214
215
216
217
218
219
# File 'lib/origami/parser.rb', line 211

def self.init_scanner(stream)
    if stream.is_a?(StringScanner)
        stream
    elsif stream.respond_to?(:to_str)
        StringScanner.new(stream.to_str)
    else
        raise TypeError, "Cannot initialize scanner from #{stream.class}"
    end
end

Instance Method Details

#debug(msg = "") ⇒ Object

:nodoc:



203
204
205
# File 'lib/origami/parser.rb', line 203

def debug(msg = "") #:nodoc:
    log(VERBOSE_DEBUG, 'debug', :magenta, msg)
end

#defer_type_cast(reference, type) ⇒ Object

:nodoc:



175
176
177
# File 'lib/origami/parser.rb', line 175

def defer_type_cast(reference, type) #:nodoc:
    @deferred_casts[reference] = type
end

#error(msg = "") ⇒ Object

:nodoc:



191
192
193
# File 'lib/origami/parser.rb', line 191

def error(msg = "") #:nodoc:
    log(VERBOSE_QUIET, 'error', :red, msg)
end

#info(msg = "") ⇒ Object

:nodoc:



199
200
201
# File 'lib/origami/parser.rb', line 199

def info(msg = "") #:nodoc:
    log(VERBOSE_INFO, 'info ', :green, msg)
end

#parse(stream) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/origami/parser.rb', line 84

def parse(stream)
    data =
    if stream.respond_to? :read
        StringScanner.new(stream.read.force_encoding('binary'))
    elsif stream.is_a? ::String
        @filename = stream
        StringScanner.new(File.binread(@filename))
    elsif stream.is_a? StringScanner
        stream
    else
        raise TypeError
    end

    @data = data
    @data.pos = 0
end

#parse_object(pos = @data.pos) ⇒ Object

:nodoc:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/origami/parser.rb', line 101

def parse_object(pos = @data.pos) #:nodoc:
    @data.pos = pos

    begin
        obj = Object.parse(@data, self)
        return if obj.nil?

        obj = try_object_promotion(obj)
        trace "Read #{obj.type} object, #{obj.reference}"

        @options[:callback].call(obj)
        obj

    rescue UnterminatedObjectError
        error $!.message
        obj = $!.obj

        Object.skip_until_next_obj(@data)
        @options[:callback].call(obj)
        obj

    rescue
        error "Breaking on: #{(@data.peek(10) + "...").inspect} at offset 0x#{@data.pos.to_s(16)}"
        error "Last exception: [#{$!.class}] #{$!.message}"
        if not @options[:ignore_errors]
            error "Manually fix the file or set :ignore_errors parameter."
            raise
        end

        debug 'Skipping this indirect object.'
        raise if not Object.skip_until_next_obj(@data)

        retry
    end
end

#parse_trailer(pos = @data.pos) ⇒ Object

:nodoc:



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/origami/parser.rb', line 157

def parse_trailer(pos = @data.pos) #:nodoc:
    @data.pos = pos

    begin
        info "...Parsing trailer..."
        trailer = Trailer.parse(@data, self)

        @options[:callback].call(trailer)
        trailer

    rescue
        debug "Exception caught while parsing trailer : " + $!.message
        warn "Unable to parse trailer!"

        raise
    end
end

#parse_xreftable(pos = @data.pos) ⇒ Object

:nodoc:



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/origami/parser.rb', line 137

def parse_xreftable(pos = @data.pos) #:nodoc:
    @data.pos = pos

    begin
        info "...Parsing xref table..."
        xreftable = XRef::Section.parse(@data)
        @options[:callback].call(xreftable)

        xreftable

    rescue
        debug "Exception caught while parsing xref table : " + $!.message
        warn "Unable to parse xref table! Xrefs might be stored into an XRef stream."

        @data.pos -= 'trailer'.length unless @data.skip_until(/trailer/).nil?

        nil
    end
end

#posObject

Raises:

  • (RuntimeError)


72
73
74
75
76
# File 'lib/origami/parser.rb', line 72

def pos
    raise RuntimeError, "Cannot get position, parser has no loaded data." if @data.nil?

    @data.pos
end

#pos=(offset) ⇒ Object

Raises:

  • (RuntimeError)


78
79
80
81
82
# File 'lib/origami/parser.rb', line 78

def pos=(offset)
    raise RuntimeError, "Cannot set position, parser has no loaded data." if @data.nil?

    @data.pos = offset
end

#target_dataObject



187
188
189
# File 'lib/origami/parser.rb', line 187

def target_data
    @data.string.dup if @data
end

#target_filenameObject



179
180
181
# File 'lib/origami/parser.rb', line 179

def target_filename
    @filename
end

#target_filesizeObject



183
184
185
# File 'lib/origami/parser.rb', line 183

def target_filesize
    @data.string.size if @data
end

#trace(msg = "") ⇒ Object

:nodoc:



207
208
209
# File 'lib/origami/parser.rb', line 207

def trace(msg = "") #:nodoc:
    log(VERBOSE_TRACE, 'trace', :cyan, msg)
end

#warn(msg = "") ⇒ Object

:nodoc:



195
196
197
# File 'lib/origami/parser.rb', line 195

def warn(msg = "") #:nodoc:
    log(VERBOSE_INFO, 'warn ', :yellow, msg)
end