origami 1.0.4 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -41,19 +41,30 @@ module Origami
41
41
  DEFAULT_LINEWIDTH = 1.0
42
42
 
43
43
  attr_reader :instructions
44
+ attr_accessor :canvas
44
45
 
45
46
  def initialize(rawdata = "", dictionary = {})
46
47
 
47
48
  @instructions = nil
48
- @gs = Graphics::State.new
49
+ @canvas = Graphics::DummyCanvas.new
49
50
 
50
51
  super(rawdata, dictionary)
51
52
  end
52
53
 
54
+ def render(engine)
55
+ load! if @instructions.nil?
56
+
57
+ @instructions.each do |instruction|
58
+ instruction.render(engine)
59
+ end
60
+
61
+ nil
62
+ end
63
+
53
64
  def pre_build #:nodoc:
54
65
  load! if @instructions.nil?
55
- if @gs.text_state.is_in_text_object?
56
- @instructions << PDF::Instruction.new('ET').update_state(@gs)
66
+ if @canvas.gs.text_state.is_in_text_object?
67
+ @instructions << PDF::Instruction.new('ET').render(@canvas)
57
68
  end
58
69
 
59
70
  @data = @instructions.join
@@ -99,16 +110,16 @@ module Origami
99
110
  set_line_join(line_join)
100
111
  set_dash_pattern(dash_pattern)
101
112
 
102
- if @gs.text_state.is_in_text_object?
103
- @instructions << PDF::Instruction.new('ET').update_state(@gs)
113
+ if @canvas.gs.text_state.is_in_text_object?
114
+ @instructions << PDF::Instruction.new('ET').render(@canvas)
104
115
  end
105
116
 
106
117
  unless coords.size < 1
107
118
  x,y = coords.slice!(0)
108
- @instructions << PDF::Instruction.new('m',x,y).update_state(@gs)
119
+ @instructions << PDF::Instruction.new('m',x,y).render(@canvas)
109
120
 
110
121
  coords.each do |px,py|
111
- @instructions << PDF::Instruction.new('l',px,py).update_state(@gs)
122
+ @instructions << PDF::Instruction.new('l',px,py).render(@canvas)
112
123
  end
113
124
 
114
125
  @instructions << (i =
@@ -121,7 +132,7 @@ module Origami
121
132
  end
122
133
  )
123
134
 
124
- i.update_state(@gs)
135
+ i.render(@canvas)
125
136
  end
126
137
 
127
138
  self
@@ -152,11 +163,11 @@ module Origami
152
163
  set_line_join(line_join)
153
164
  set_dash_pattern(dash_pattern)
154
165
 
155
- if @gs.text_state.is_in_text_object?
156
- @instructions << PDF::Instruction.new('ET').update_state(@gs)
166
+ if @canvas.gs.text_state.is_in_text_object?
167
+ @instructions << PDF::Instruction.new('ET').render(@canvas)
157
168
  end
158
169
 
159
- @instructions << PDF::Instruction.new('re', x,y,width,height).update_state(@gs)
170
+ @instructions << PDF::Instruction.new('re', x,y,width,height).render(@canvas)
160
171
 
161
172
  @instructions << (i =
162
173
  if stroke and not fill
@@ -168,7 +179,7 @@ module Origami
168
179
  end
169
180
  )
170
181
 
171
- i.update_state(@gs)
182
+ i.render(@canvas)
172
183
 
173
184
  self
174
185
  end
@@ -194,10 +205,10 @@ module Origami
194
205
  rise = attr[:rise]
195
206
  rendering = attr[:rendering]
196
207
 
197
- @instructions << PDF::Instruction.new('ET').update_state(@gs) if (x or y) and @gs.text_state.is_in_text_object?
208
+ @instructions << PDF::Instruction.new('ET').render(@canvas) if (x or y) and @canvas.gs.text_state.is_in_text_object?
198
209
 
199
- unless @gs.text_state.is_in_text_object?
200
- @instructions << PDF::Instruction.new('BT').update_state(@gs)
210
+ unless @canvas.gs.text_state.is_in_text_object?
211
+ @instructions << PDF::Instruction.new('BT').render(@canvas)
201
212
  end
202
213
 
203
214
  set_text_font(font, size)
@@ -219,15 +230,15 @@ module Origami
219
230
 
220
231
  def paint_shading(shade)
221
232
  load! if @instructions.nil?
222
- @instructions << PDF::Instruction.new('sh', shade).update_state(@gs)
233
+ @instructions << PDF::Instruction.new('sh', shade).render(@canvas)
223
234
 
224
235
  self
225
236
  end
226
237
 
227
238
  def set_text_font(fontname, size)
228
239
  load! if @instructions.nil?
229
- if fontname != @gs.text_state.font or size != @gs.text_state.font_size
230
- @instructions << PDF::Instruction.new('Tf', fontname, size).update_state(@gs)
240
+ if fontname != @canvas.gs.text_state.font or size != @canvas.gs.text_state.font_size
241
+ @instructions << PDF::Instruction.new('Tf', fontname, size).render(@canvas)
231
242
  end
232
243
 
233
244
  self
@@ -235,15 +246,15 @@ module Origami
235
246
 
236
247
  def set_text_pos(tx,ty)
237
248
  load! if @instructions.nil?
238
- @instructions << PDF::Instruction.new('Td', tx, ty).update_state(@gs)
249
+ @instructions << PDF::Instruction.new('Td', tx, ty).render(@canvas)
239
250
 
240
251
  self
241
252
  end
242
253
 
243
254
  def set_text_leading(leading)
244
255
  load! if @instructions.nil?
245
- if leading != @gs.text_state.leading
246
- @instructions << PDF::Instruction.new('TL', leading).update_state(@gs)
256
+ if leading != @canvas.gs.text_state.leading
257
+ @instructions << PDF::Instruction.new('TL', leading).render(@canvas)
247
258
  end
248
259
 
249
260
  self
@@ -251,8 +262,8 @@ module Origami
251
262
 
252
263
  def set_text_rendering(rendering)
253
264
  load! if @instructions.nil?
254
- if rendering != @gs.text_state.rendering_mode
255
- @instructions << PDF::Instruction.new('Tr', rendering).update_state(@gs)
265
+ if rendering != @canvas.gs.text_state.rendering_mode
266
+ @instructions << PDF::Instruction.new('Tr', rendering).render(@canvas)
256
267
  end
257
268
 
258
269
  self
@@ -260,8 +271,8 @@ module Origami
260
271
 
261
272
  def set_text_rise(rise)
262
273
  load! if @instructions.nil?
263
- if rise != @gs.text_state.text_rise
264
- @instructions << PDF::Instruction.new('Ts', rise).update_state(@gs)
274
+ if rise != @canvas.gs.text_state.text_rise
275
+ @instructions << PDF::Instruction.new('Ts', rise).render(@canvas)
265
276
  end
266
277
 
267
278
  self
@@ -269,8 +280,8 @@ module Origami
269
280
 
270
281
  def set_text_scale(scaling)
271
282
  load! if @instructions.nil?
272
- if scale != @gs.text_state.scaling
273
- @instructions << PDF::Instruction.new('Tz', scaling).update_state(@gs)
283
+ if scale != @canvas.gs.text_state.scaling
284
+ @instructions << PDF::Instruction.new('Tz', scaling).render(@canvas)
274
285
  end
275
286
 
276
287
  self
@@ -278,8 +289,8 @@ module Origami
278
289
 
279
290
  def set_text_word_spacing(word_spacing)
280
291
  load! if @instructions.nil?
281
- if word_spacing != @gs.text_state.word_spacing
282
- @instructions << PDF::Instruction.new('Tw', word_spacing).update_state(@gs)
292
+ if word_spacing != @canvas.gs.text_state.word_spacing
293
+ @instructions << PDF::Instruction.new('Tw', word_spacing).render(@canvas)
283
294
  end
284
295
 
285
296
  self
@@ -287,8 +298,8 @@ module Origami
287
298
 
288
299
  def set_text_char_spacing(char_spacing)
289
300
  load! if @instructions.nil?
290
- if char_spacing != @gs.text_state.char_spacing
291
- @instructions << PDF::Instruction.new('Tc', char_spacing).update_state(@gs)
301
+ if char_spacing != @canvas.gs.text_state.char_spacing
302
+ @instructions << PDF::Instruction.new('Tc', char_spacing).render(@canvas)
292
303
  end
293
304
 
294
305
  self
@@ -302,25 +313,25 @@ module Origami
302
313
  r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
303
314
  g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
304
315
  b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
305
- PDF::Instruction.new('rg', r, g, b) if @gs.nonstroking_color != [r,g,b]
316
+ PDF::Instruction.new('rg', r, g, b) if @canvas.gs.nonstroking_color != [r,g,b]
306
317
 
307
318
  elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
308
319
  c = (color.respond_to?(:c) ? color.c : color[0]).to_f
309
320
  m = (color.respond_to?(:m) ? color.m : color[1]).to_f
310
321
  y = (color.respond_to?(:y) ? color.y : color[2]).to_f
311
322
  k = (color.respond_to?(:k) ? color.k : color[3]).to_f
312
- PDF::Instruction.new('k', c, m, y, k) if @gs.nonstroking_color != [c,m,y,k]
323
+ PDF::Instruction.new('k', c, m, y, k) if @canvas.gs.nonstroking_color != [c,m,y,k]
313
324
 
314
325
  elsif color.respond_to?:g or (0.0..1.0) === color
315
326
  g = color.respond_to?(:g) ? color.g : color
316
- PDF::Instruction.new('g', g) if @gs.nonstroking_color != [ g ]
327
+ PDF::Instruction.new('g', g) if @canvas.gs.nonstroking_color != [ g ]
317
328
 
318
329
  else
319
330
  raise TypeError, "Invalid color : #{color}"
320
331
  end
321
332
  )
322
333
 
323
- i.update_state(@gs) if i
334
+ i.render(@canvas) if i
324
335
  self
325
336
  end
326
337
 
@@ -332,32 +343,32 @@ module Origami
332
343
  r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
333
344
  g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
334
345
  b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
335
- PDF::Instruction.new('RG', r, g, b) if @gs.stroking_color != [r,g,b]
346
+ PDF::Instruction.new('RG', r, g, b) if @canvas.gs.stroking_color != [r,g,b]
336
347
 
337
348
  elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
338
349
  c = (color.respond_to?(:c) ? color.c : color[0]).to_f
339
350
  m = (color.respond_to?(:m) ? color.m : color[1]).to_f
340
351
  y = (color.respond_to?(:y) ? color.y : color[2]).to_f
341
352
  k = (color.respond_to?(:k) ? color.k : color[3]).to_f
342
- PDF::Instruction.new('K', c, m, y, k) if @gs.stroking_color != [c,m,y,k]
353
+ PDF::Instruction.new('K', c, m, y, k) if @canvas.gs.stroking_color != [c,m,y,k]
343
354
 
344
355
  elsif color.respond_to?:g or (0.0..1.0) === color
345
356
  g = color.respond_to?(:g) ? color.g : color
346
- PDF::Instruction.new('G', g) if @gs.stroking_color != [ g ]
357
+ PDF::Instruction.new('G', g) if @canvas.gs.stroking_color != [ g ]
347
358
 
348
359
  else
349
360
  raise TypeError, "Invalid color : #{color}"
350
361
  end
351
362
  )
352
363
 
353
- i.update_state(@gs) if i
364
+ i.render(@canvas) if i
354
365
  self
355
366
  end
356
367
 
357
368
  def set_dash_pattern(pattern)
358
369
  load! if @instructions.nil?
359
- unless @gs.dash_pattern.eql? pattern
360
- @instructions << PDF::Instruction.new('d', pattern.array, pattern.phase).update_state(@gs)
370
+ unless @canvas.gs.dash_pattern.eql? pattern
371
+ @instructions << PDF::Instruction.new('d', pattern.array, pattern.phase).render(@canvas)
361
372
  end
362
373
 
363
374
  self
@@ -365,8 +376,8 @@ module Origami
365
376
 
366
377
  def set_line_width(width)
367
378
  load! if @instructions.nil?
368
- if @gs.line_width != width
369
- @instructions << PDF::Instruction.new('w', width).update_state(@gs)
379
+ if @canvas.gs.line_width != width
380
+ @instructions << PDF::Instruction.new('w', width).render(@canvas)
370
381
  end
371
382
 
372
383
  self
@@ -374,8 +385,8 @@ module Origami
374
385
 
375
386
  def set_line_cap(cap)
376
387
  load! if @instructions.nil?
377
- if @gs.line_cap != cap
378
- @instructions << PDF::Instruction.new('J', cap).update_state(@gs)
388
+ if @canvas.gs.line_cap != cap
389
+ @instructions << PDF::Instruction.new('J', cap).render(@canvas)
379
390
  end
380
391
 
381
392
  self
@@ -383,8 +394,8 @@ module Origami
383
394
 
384
395
  def set_line_join(join)
385
396
  load! if @instructions.nil?
386
- if @gs.line_join != join
387
- @instructions << PDF::Instruction.new('j', join).update_state(@gs)
397
+ if @canvas.gs.line_join != join
398
+ @instructions << PDF::Instruction.new('j', join).render(@canvas)
388
399
  end
389
400
 
390
401
  self
@@ -397,7 +408,11 @@ module Origami
397
408
 
398
409
  code = StringScanner.new self.data
399
410
  @instructions = []
400
- @instructions << PDF::Instruction.parse(code) until code.eos?
411
+
412
+ until code.eos?
413
+ insn = PDF::Instruction.parse(code)
414
+ @instructions << insn if insn
415
+ end
401
416
 
402
417
  self
403
418
  end
@@ -406,9 +421,9 @@ module Origami
406
421
 
407
422
  lines = text.split("\n").map!{|line| line.to_s}
408
423
 
409
- @instructions << PDF::Instruction.new('Tj', lines.slice!(0)).update_state(@gs)
424
+ @instructions << PDF::Instruction.new('Tj', lines.slice!(0)).render(@canvas)
410
425
  lines.each do |line|
411
- @instructions << PDF::Instruction.new("'", line).update_state(@gs)
426
+ @instructions << PDF::Instruction.new("'", line).render(@canvas)
412
427
  end
413
428
 
414
429
  end
@@ -0,0 +1,135 @@
1
+ =begin
2
+
3
+ = File
4
+ javascript.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ class PDF
29
+ begin
30
+ require 'johnson'
31
+
32
+ class JavaScriptEngine < Johnson::SpiderMonkey::Runtime
33
+
34
+ class DocumentObject
35
+ attr_reader :author, :creator, :creationDate, :keywords, :modDate, :producer, :subject, :title
36
+
37
+ def initialize(pdf)
38
+ @pdf = pdf
39
+
40
+ @author = @pdf.author || ''
41
+ @creator = @pdf.creator || ''
42
+ @keywords = @pdf.keywords || ''
43
+ @producer = @pdf.producer || ''
44
+ @subject = @pdf.subject || ''
45
+ end
46
+
47
+ def to_s
48
+ "[object Doc]"
49
+ end
50
+ end
51
+
52
+ class ApplicationObject
53
+ DEFAULT_VIEWER_VERSION = 9
54
+
55
+ attr_reader :viewerVersion
56
+ attr_reader :viewerVariation
57
+
58
+ def initialize
59
+ @viewerVersion = DEFAULT_VIEWER_VERSION
60
+ @viewerVariation = @viewerType = "Reader"
61
+ end
62
+
63
+ def to_s
64
+ "[object App]"
65
+ end
66
+ end
67
+
68
+ class ConsoleObject
69
+ def println(msg)
70
+ puts msg.to_s
71
+ end
72
+
73
+ def show; end
74
+ def clear; end
75
+ def hide; end
76
+
77
+ def to_s
78
+ "[object Console]"
79
+ end
80
+ end
81
+
82
+ class UtilObject
83
+ def to_s
84
+ "[object Util]"
85
+ end
86
+ end
87
+
88
+ def initialize(pdf, options = {})
89
+ super()
90
+
91
+ self['app'] = ApplicationObject.new
92
+ if options.has_key?(:viewerVersion)
93
+ self['app'].instance_variable_set :@viewerVersion, options[:viewerVersion]
94
+ end
95
+
96
+ self['console'] = ConsoleObject.new
97
+ self['util'] = UtilObject.new
98
+
99
+ # Johnson includes the Ruby namespace in the global scope.
100
+ # Unsets that for obvious security reasons.
101
+ self['Ruby'] = nil
102
+
103
+ # Hack the 'this' object to point to the DocumentObject
104
+ @doc_obj = self['doc'] = DocumentObject.new(pdf)
105
+ evaluate('this.doc.eval = function(script) {eval(script)}')
106
+ evaluate('this.doc = undefined')
107
+ end
108
+
109
+ def exec(script)
110
+ @doc_obj.eval(script)
111
+ end
112
+
113
+ end
114
+
115
+ rescue LoadError
116
+ end
117
+ end
118
+
119
+ if defined?(PDF::JavaScriptEngine)
120
+ module String
121
+ def eval_as_js(options = {})
122
+ runtime = options[:runtime] || PDF::JavaScriptEngine.new(self.pdf, options)
123
+ runtime.exec(self.value)
124
+ end
125
+ end
126
+
127
+ class Stream
128
+ def eval_as_js(options = {})
129
+ runtime = options[:runtime] || PDF::JavaScriptEngine.new(self.pdf, options)
130
+ runtime.exec(self.data)
131
+ end
132
+ end
133
+ end
134
+
135
+ end
@@ -50,6 +50,15 @@ module Origami
50
50
  get_doc_attr :Info
51
51
  end
52
52
 
53
+ def title; get_document_info_field(:Title) end
54
+ def author; get_document_info_field(:Author) end
55
+ def subject; get_document_info_field(:Subject) end
56
+ def keywords; get_document_info_field(:Keywords) end
57
+ def creator; get_document_info_field(:Creator) end
58
+ def producer; get_document_info_field(:Producer) end
59
+ def creation_date; get_document_info_field(:CreationDate) end
60
+ def mod_date; get_document_info_field(:ModDate) end
61
+
53
62
  #
54
63
  # Returns a Hash of the information found in the metadata stream
55
64
  #
@@ -81,6 +90,21 @@ module Origami
81
90
  end
82
91
  end
83
92
 
93
+ private
94
+
95
+ def get_document_info_field(field) #:nodoc:
96
+ if has_document_info?
97
+ doc_info = get_document_info
98
+
99
+ if doc_info.has_key?(field)
100
+ case obj = get_document_info[field].solve
101
+ when String then return obj.value
102
+ when Stream then return obj.data
103
+ end
104
+ end
105
+ end
106
+ end
107
+
84
108
  end
85
109
 
86
110
  #