origami 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -12,12 +12,13 @@ DESCRIPTION
12
12
 
13
13
  VERSION
14
14
 
15
- 1.1
15
+ 1.2
16
16
 
17
17
  OPTIONAL DEPENDENCIES
18
18
 
19
19
  - Ruby-GTK2 (only for GUI), http://ruby-gnome2.sourceforge.jp/
20
20
  - Ruby with OpenSSL support
21
+ - TheRubyRacer gem (only for JavaScript support)
21
22
 
22
23
  INSTALL
23
24
 
@@ -166,7 +166,17 @@ module Origami
166
166
  end
167
167
 
168
168
  def [](key)
169
- super(key.to_o)
169
+ #if key.is_a?(::Array) and key.size == 1
170
+ # follow = true
171
+ # key = key.first
172
+ #end
173
+
174
+ val = super(key.to_o)
175
+ #if follow and val.is_a?(Reference)
176
+ # val.solve
177
+ #else
178
+ # val
179
+ #end
170
180
  end
171
181
 
172
182
  def has_key?(key)
@@ -97,7 +97,7 @@ module Origami
97
97
  result = ""
98
98
  until stream[i].ord == EOD do
99
99
 
100
- length = stream[i]
100
+ length = stream[i].ord
101
101
  if length < EOD
102
102
  result << stream[i + 1, length + 1]
103
103
  i = i + length + 2
@@ -25,305 +25,686 @@
25
25
 
26
26
  module Origami
27
27
 
28
- class PDF
28
+ begin
29
+ require 'v8'
30
+
31
+ class V8::Object
32
+ #def inspect
33
+ # case self
34
+ # when V8::Array,V8::Function then super
35
+ # else
36
+ # "{#{self.to_a.map{|k,v| "#{k}:#{v.inspect}"}.join(', ')}}"
37
+ # end
38
+ #end
39
+ end
40
+
41
+ class PDF
29
42
 
30
- module JavaScript
43
+ module JavaScript
31
44
 
32
- module Platforms
33
- WINDOWS = "WIN"
34
- UNIX = "UNIX"
35
- MAC = "MAC"
36
- end
45
+ module Platforms
46
+ WINDOWS = "WIN"
47
+ UNIX = "UNIX"
48
+ MAC = "MAC"
49
+ end
37
50
 
38
- module Viewers
39
- ADOBE_READER = "Reader"
40
- end
51
+ module Viewers
52
+ ADOBE_READER = "Reader"
53
+ end
41
54
 
42
- class AcrobatObject
43
- #def to_s
44
- # "[object #{self.class.to_s.split('::').last}]"
45
- #end
46
- end
55
+ class MissingArgError < Exception
56
+ def initialize; super("Missing required argument.") end
57
+ end
47
58
 
48
- class Doc < AcrobatObject
49
- attr_reader :info
50
- attr_accessor :disclosed
51
- attr_reader :hidden
52
-
53
- class Info < AcrobatObject
54
- def initialize(doc)
55
- @doc = doc
56
- end
57
-
58
- def title; @doc.title.to_s end
59
- def author; @doc.author.to_s end
60
- def subject; @doc.subject.to_s end
61
- def keywords; @doc.keywords.to_s end
62
- def creator; @doc.creator.to_s end
63
- def creationDate; @doc.creation_date.to_s end
64
- def modDate; @doc.mod_date.to_s end
59
+ class TypeError < Exception
60
+ def initialize; super("Incorrect argument type.") end
65
61
  end
66
62
 
67
- def initialize(pdf)
68
- @pdf = pdf
69
- @disclosed = false
70
- @hidden = false
71
- @info = Info.new(pdf)
63
+ class InvalidArgsError < Exception
64
+ def initialize; super("Incorrect arguments.") end
72
65
  end
73
66
 
74
- def numFields
75
- fields = @pdf.fields
76
- if fields.nil?
77
- 0
78
- else
79
- fields.size
80
- end
67
+ class NotAllowedError < Exception
68
+ def initialize; super("Security settings prevent access to this property or method.") end
81
69
  end
82
70
 
83
- def numPages; @pdf.pages.size end
71
+ class HelpError < Exception
72
+ def initialize; super("Help") end
73
+ end
74
+
75
+ class GeneralError < Exception
76
+ def initialize; super("Operation failed.") end
77
+ end
84
78
 
85
- def title; @info.title end
86
- def author; @info.author end
87
- def subject; @info.subject end
88
- def keywords; @info.keywords end
89
- def creator; @info.creator end
90
- def creationDate; @info.creationDate end
91
- def modDate; @info.modDate end
79
+ class Arg
80
+ attr_reader :name, :type, :required, :default
92
81
 
93
- def metadata
94
- meta = @pdf.Catalog.Metadata
82
+ def initialize(declare = {})
83
+ @name = declare[:name]
84
+ @type = declare[:type]
85
+ @required = declare[:required]
86
+ @default = declare[:default]
87
+ end
95
88
 
96
- (meta.data if meta.is_a?(Stream)).to_s
89
+ def self.[](declare = {})
90
+ self.new(declare)
91
+ end
92
+
93
+ def self.inspect(obj)
94
+ case obj
95
+ when V8::Function then "function #{obj.name}"
96
+ when V8::Array then obj.to_a.inspect
97
+ when V8::Object
98
+ "{#{obj.to_a.map{|k,v| "#{k}:#{Arg.inspect(v)}"}.join(', ')}}"
99
+ else
100
+ obj.inspect
101
+ end
102
+ end
103
+
97
104
  end
98
105
 
99
- def filesize; @pdf.original_filesize end
100
- def path; @pdf.original_filename end
101
- def documentFileName; File.basename(self.path) end
102
- def URL; "file://#{self.path}" end
103
- def baseURL; '' end
104
-
105
- def dataObjects
106
- data_objs = []
107
- @pdf.ls_names(Names::Root::EMBEDDEDFILES).each do |name, file_desc|
108
- if file_desc
109
- ef = file_desc[:EF].solve
110
- if ef
111
- f = ef[:F].solve
112
- data_objs.push Data.new(name, f.data.size) if f.is_a?(Stream)
106
+ class AcrobatObject
107
+ def initialize(engine)
108
+ @engine = engine
109
+ end
110
+
111
+ def self.check_method_args(args, def_args)
112
+ if args.first.is_a?(V8::Object)
113
+ args = args.first
114
+ members = args.entries.map{|k,v| k}
115
+ argv = []
116
+ def_args.each do |def_arg|
117
+ raise MissingArgError if def_arg.required and not members.include?(def_arg.name)
118
+
119
+ if members.include?(def_arg.name)
120
+ arg = args[def_arg.name]
121
+ raise TypeError if def_arg.type and not arg.is_a?(def_arg.type)
122
+ else
123
+ arg = def_arg.default
124
+ end
125
+
126
+ argv.push(arg)
127
+ end
128
+
129
+ args = argv
130
+ else
131
+ i = 0
132
+ def_args.each do |def_arg|
133
+ raise MissingArgError if def_arg.required and i >= args.length
134
+ raise TypeError if def_arg.type and not args[i].is_a?(def_arg.type)
135
+
136
+ args.push(def_arg.default) if i >= args.length
137
+
138
+ i = i + 1
113
139
  end
114
140
  end
115
141
 
142
+ args
116
143
  end
117
-
118
- data_objs
119
- end
144
+
145
+ def self.acro_method(name, *def_args, &b)
146
+ define_method(name) do |*args|
147
+ if @engine.options[:log_method_calls]
148
+ @engine.options[:console].puts(
149
+ "LOG: #{self.class}.#{name}(#{args.map{|arg| Arg.inspect(arg)}.join(',')})"
150
+ )
151
+ end
152
+
153
+ args = AcrobatObject.check_method_args(args, def_args)
154
+ self.instance_exec(*args, &b) if b
155
+ end
156
+ end
157
+
158
+ def self.acro_method_protected(name, *def_args, &b)
159
+ define_method(name) do |*args|
160
+ if @engine.options[:log_method_calls]
161
+ @engine.options[:console].puts(
162
+ "LOG: #{self.class}.#{name}(#{args.map{|arg| arg.inspect}.join(',')})"
163
+ )
164
+ end
120
165
 
121
- def getDataObject(cName)
122
- file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
166
+ raise NotAllowedError
123
167
 
124
- if file_desc
125
- ef = file_desc[:EF].solve
126
- if ef
127
- f = ef[:F].solve
128
- Data.new(cName, f.data.size) if f.is_a?(Stream)
168
+ args = AcrobatObject.check_method_args(args, def_args)
169
+ self.instance_exec(*args, &b) if b
129
170
  end
130
171
  end
172
+
173
+ def to_s
174
+ "[object #{self.class.to_s.split('::').last}]"
175
+ end
176
+ alias inspect to_s
177
+
131
178
  end
132
179
 
133
- def getDataObjectContents(cName, bAllowAuth = false)
134
- file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
180
+ class AcroTimer < AcrobatObject
181
+ def initialize(engine, timeout, code, repeat)
135
182
 
136
- if file_desc
137
- ef = file_desc[:EF].solve
138
- if ef
139
- f = ef[:F].solve
140
- ReadStream.new(f.data) if f.is_a?(Stream)
183
+ @thr = Thread.start(engine, timeout, code, repeat) do
184
+ loop do
185
+ sleep(timeout / 1000.0)
186
+ engine.exec(code)
187
+ break if not repeat
188
+ end
141
189
  end
142
190
  end
143
191
  end
144
192
 
145
- def getField(cName)
146
- field = @pdf.get_field(cName)
193
+ class TimeOut < AcroTimer
194
+ def initialize(engine, timeout, code)
195
+ super(engine, timeout, code, false)
196
+ end
197
+ end
147
198
 
148
- Field.new(field) if field
199
+ class Interval < AcroTimer
200
+ def initialize(engine, timeout, code)
201
+ super(engine, timeout, code, true)
202
+ end
149
203
  end
150
204
 
151
- def getNthFieldName(nIndex)
152
- fields = @pdf.fields
205
+ class ReadStream < AcrobatObject
206
+ def initialize(engine, data)
207
+ super(engine)
153
208
 
154
- (Field.new(fields[nIndex]).name if fields and fields[nIndex]).to_s
209
+ @data = data
210
+ end
211
+
212
+ acro_method 'read',
213
+ Arg[:name => 'nBytes', :type => Numeric, :required => true] do |nBytes|
214
+ @data.slice!(0, nBytes)
215
+ end
155
216
  end
156
- end
157
217
 
158
- class App < AcrobatObject
159
- attr_reader :platform, :viewerVariation, :viewerVersion
218
+ class Acrohelp < AcrobatObject; end
160
219
 
161
- def initialize(platform, viewerVariation, viewerVersion)
162
- @platform = platform
163
- @viewerVariation, @viewerVersion = viewerVariation, viewerVersion
164
- end
220
+ class Global < AcrobatObject
221
+ def initialize(engine)
222
+ super(engine)
165
223
 
166
- def response(params)
167
- puts params.class
168
- gets
169
- end
170
- end
224
+ @vars = {}
225
+ end
226
+
227
+ def []=(name, value)
228
+ @vars[name] ||= {:callbacks => []}
229
+ @vars[name][:value] = value
230
+ @vars[name][:callbacks].each do |callback|
231
+ callback.call(value)
232
+ end
233
+ end
171
234
 
172
- class Console < AcrobatObject
173
- def initialize(output = STDOUT)
174
- @output = output
175
- end
235
+ def [](name)
236
+ @vars[name][:value] if @vars.include?(name)
237
+ end
176
238
 
177
- def println(msg)
178
- @output.puts msg
179
- end
180
- end
239
+ acro_method 'setPersistent',
240
+ Arg[:name => 'cVariable', :required => true],
241
+ Arg[:name => 'bPersist', :required => true] do |cVariable, bPersist|
242
+ raise GeneralError unless @vars.include?(cVariable)
243
+ end
181
244
 
182
- class Util < AcrobatObject
183
- def streamFromString(cString, cCharset = 'utf-8')
184
- ReadStream.new(cString.to_s)
245
+ acro_method 'subscribe',
246
+ Arg[:name => 'cVariable', :required => true],
247
+ Arg[:name => 'fCallback', :type => V8::Function, :required => true] do |cVariable, fCallback|
248
+ if @vars.include?(cVariable)
249
+ @vars[cVariable][:callbacks].push(fCallback)
250
+ fCallback.call(@vars[cVariable][:value])
251
+ end
252
+ end
185
253
  end
186
254
 
187
- def stringFromStream(oStream, cCharset = 'utf-8')
188
- if oStream.is_a?(ReadStream)
189
- oStream.instance_variable_get(:@data).dup
255
+ class Doc < AcrobatObject
256
+ attr_reader :info
257
+ attr_accessor :disclosed
258
+ attr_reader :hidden
259
+
260
+ class Info < AcrobatObject
261
+ def initialize(engine, doc)
262
+ super(engine)
263
+
264
+ @doc = doc
265
+ end
266
+
267
+ def title; @doc.title.to_s end
268
+ def author; @doc.author.to_s end
269
+ def subject; @doc.subject.to_s end
270
+ def keywords; @doc.keywords.to_s end
271
+ def creator; @doc.creator.to_s end
272
+ def creationDate; @doc.creation_date.to_s end
273
+ def modDate; @doc.mod_date.to_s end
190
274
  end
191
- end
192
- end
193
275
 
194
- class Field < AcrobatObject
195
- def initialize(field)
196
- @field = field
197
- end
276
+ def initialize(engine, pdf)
277
+ super(engine)
198
278
 
199
- def doc; Doc.new(@field.pdf) end
200
- def name
201
- (@field[:T].solve.value if @field.has_key?(:T)).to_s
202
- end
279
+ @pdf = pdf
280
+ @disclosed = false
281
+ @hidden = false
282
+ @info = Info.new(@engine, pdf)
283
+ end
284
+
285
+ ### PROPERTIES ###
286
+
287
+ def numFields
288
+ fields = @pdf.fields
289
+ if fields.nil?
290
+ 0
291
+ else
292
+ fields.size
293
+ end
294
+ end
295
+
296
+ def numPages; @pdf.pages.size end
297
+
298
+ def title; @info.title end
299
+ def author; @info.author end
300
+ def subject; @info.subject end
301
+ def keywords; @info.keywords end
302
+ def creator; @info.creator end
303
+ def creationDate; @info.creationDate end
304
+ def modDate; @info.modDate end
305
+
306
+ def metadata
307
+ meta = @pdf.Catalog.Metadata
308
+
309
+ (meta.data if meta.is_a?(Stream)).to_s
310
+ end
311
+
312
+ def filesize; @pdf.original_filesize end
313
+ def path; @pdf.original_filename.to_s end
314
+ def documentFileName; File.basename(self.path) end
315
+ def URL; "file://#{self.path}" end
316
+ def baseURL; '' end
317
+
318
+ def dataObjects
319
+ data_objs = []
320
+ @pdf.ls_names(Names::Root::EMBEDDEDFILES).each do |name, file_desc|
321
+ if file_desc
322
+ ef = file_desc[:EF].solve
323
+ if ef
324
+ f = ef[:F].solve
325
+ data_objs.push Data.new(@engine, name, f.data.size) if f.is_a?(Stream)
326
+ end
327
+ end
328
+
329
+ end
330
+
331
+ data_objs
332
+ end
333
+
334
+ ### METHODS ###
203
335
 
204
- def value
205
- @field[:V].solve.value if @field.has_key?(:V)
206
- end
336
+ acro_method 'closeDoc'
207
337
 
208
- def valueAsString
209
- self.value.to_s
210
- end
338
+ acro_method 'getDataObject',
339
+ Arg[:name => 'cName', :type => ::String, :required => true] do |cName|
340
+ file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
211
341
 
212
- def type
213
- (if @field.has_key?(:FT)
214
- case @field[:FT].solve.value
215
- when PDF::Field::Type::BUTTON
216
- if @fields.has_key?(:Ff)
217
- flags = @fields[:Ff].solve.value
218
-
219
- if (flags & Origami::Annotation::Widget::Button::Flags::PUSHBUTTON) != 0
220
- 'button'
221
- elsif (flags & Origami::Annotation::Widget::Button::Flags::RADIO) != 0
222
- 'radiobox'
223
- else
224
- 'checkbox'
225
- end
342
+ if file_desc
343
+ ef = file_desc[:EF].solve
344
+ if ef
345
+ f = ef[:F].solve
346
+ else raise TypeError
226
347
  end
227
- when PDF::Field::Type::TEXT then 'text'
228
- when PDF::Field::Type::SIGNATURE then 'signature'
229
- when PDF::Field::Type::CHOICE
230
- if @field.has_key?(:Ff)
231
- if (@field[:Ff].solve.value & Origami::Annotation::Widget::Choice::Flags::COMBO).zero?
232
- 'listbox'
348
+ else raise TypeError
349
+ end
350
+
351
+ Data.new(@engine, cName, f.data.size) if f.is_a?(Stream)
352
+ end
353
+
354
+ acro_method 'getDataObjectContents',
355
+ Arg[:name => 'cName', :type => ::String, :required => true],
356
+ Arg[:name => 'bAllowAuth', :default => false] do |cName, bAllowAuth|
357
+ file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
358
+
359
+ if file_desc
360
+ ef = file_desc[:EF].solve
361
+ if ef
362
+ f = ef[:F].solve
363
+ else raise TypeError
364
+ end
365
+ else raise TypeError
366
+ end
367
+
368
+ ReadStream.new(@engine, f.data) if f.is_a?(Stream)
369
+ end
370
+
371
+ acro_method 'exportDataObject',
372
+ Arg[:name => 'cName', :type => ::String, :required => true],
373
+ Arg[:name => 'cDIPath' ],
374
+ Arg[:name => 'bAllowAuth'],
375
+ Arg[:name => 'nLaunch'] do |cName, cDIPath, bAllowAuth, nLaunch|
376
+ file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
377
+
378
+ if file_desc
379
+ ef = file_desc[:EF].solve
380
+ if ef
381
+ f = ef[:F].solve
382
+ else raise TypeError
383
+ end
384
+ else raise TypeError
385
+ end
386
+
387
+ raise TypeError if f.nil?
388
+ end
389
+
390
+ acro_method 'getField',
391
+ Arg[:name => 'cName', :type => ::Object, :required => true] do |cName|
392
+ field = @pdf.get_field(cName)
393
+
394
+ Field.new(@engine, field) if field
395
+ end
396
+
397
+ acro_method 'getNthFieldName',
398
+ Arg[:name => 'nIndex', :type => ::Object, :required => true] do |nIndex|
399
+ nIndex =
400
+ case nIndex
401
+ when false then 0
402
+ when true then 1
233
403
  else
234
- 'combobox'
235
- end
404
+ @engine.parseInt.call(nIndex)
236
405
  end
406
+
407
+ raise TypeError if (nIndex.is_a?(Float) and nIndex.nan?) or nIndex < 0
408
+ fields = @pdf.fields
409
+
410
+ (Field.new(@engine, fields[nIndex]).name if fields and fields[nIndex]).to_s
237
411
  end
238
- end).to_s
239
412
  end
240
413
 
241
- end
414
+ class App < AcrobatObject
415
+ attr_reader :platform, :viewerVariation, :viewerVersion
416
+
417
+ def platform; @engine.options[:platform] end
418
+ def viewerType; @engine.options[:viewerType] end
419
+ def viewerVariation; @engine.options[:viewerVariation] end
420
+ def viewerVersion; @engine.options[:viewerVersion] end
421
+
422
+ def activeDocs; [] end
423
+
424
+ ### METHODS ###
425
+
426
+ acro_method 'setInterval',
427
+ Arg[:name => 'cExpr', :required => true],
428
+ Arg[:name => 'nMilliseconds', :type => Numeric, :required => true] do |cExpr, nMilliseconds|
429
+ cExpr = cExpr.is_a?(::String) ? cExpr : ''
430
+ Interval.new(@engine, nMilliseconds, cExpr)
431
+ end
242
432
 
243
- class Data < AcrobatObject
244
- attr_reader :name, :path, :size
245
- attr_reader :creationDate, :modDate
246
- attr_reader :description, :MIMEType
433
+ acro_method 'setTimeOut',
434
+ Arg[:name => 'cExpr', :required => true],
435
+ Arg[:name => 'nMilliseconds', :type => Numeric, :required => true] do |cExpr, nMilliseconds|
436
+ cExpr = cExpr.is_a?(::String) ? cExpr : ''
437
+ TimeOut.new(@engine, nMilliseconds, cExpr)
438
+ end
439
+
440
+ acro_method 'clearInterval',
441
+ Arg[:name => 'oInterval', :type => Interval, :required => true] do |oInterval|
442
+ oInterval.instance_variable_get(:@thr).terminate
443
+ nil
444
+ end
445
+
446
+ acro_method 'clearTimeOut',
447
+ Arg[:name => 'oInterval', :type => TimeOut, :required => true] do |oInterval|
448
+ oInterval.instance_variable_get(:@thr).terminate
449
+ nil
450
+ end
247
451
 
248
- def initialize(name, size, path = nil, creationDate = nil, modDate = nil, description = nil, mimeType = nil)
249
- @name, @path, @size = name, path, size
250
- @creationDate, @modDate = creationDate, modDate
251
- @description, @MIMEType = description, mimeType
452
+ acro_method_protected 'addMenuItem'
453
+ acro_method_protected 'addSubMenu'
454
+ acro_method 'addToolButton'
455
+ acro_method_protected 'beginPriv'
456
+ acro_method 'beep'
457
+ acro_method_protected 'browseForDoc'
458
+ acro_method_protected 'endPriv'
252
459
  end
253
- end
254
460
 
255
- class ReadStream < AcrobatObject
256
- def initialize(data)
257
- @data = data
461
+ class Console < AcrobatObject
462
+ def println(*args)
463
+ raise MissingArgError unless args.length > 0
464
+
465
+ @engine.options[:console].puts(args.first.to_s)
466
+ end
467
+
468
+ acro_method 'show'
469
+ acro_method 'clear'
470
+ acro_method 'hide'
258
471
  end
259
472
 
260
- def read(n)
261
- @data.slice!(0, n)
473
+ class Util < AcrobatObject
474
+ acro_method 'streamFromString',
475
+ Arg[:name => 'cString', :type => ::Object, :required => true],
476
+ Arg[:name => 'cCharset', :type => ::Object, :default => 'utf-8'] do |cString, cCharset|
477
+
478
+ ReadStream.new(@engine, cString.to_s)
479
+ end
480
+
481
+ acro_method 'stringFromStream',
482
+ Arg[:name => 'oStream', :type => ReadStream, :required => true],
483
+ Arg[:name => 'cCharset', :type => ::Object, :default => 'utf-8'] do |oStream, cCharset|
484
+
485
+ oStream.instance_variable_get(:@data).dup
486
+ end
262
487
  end
488
+
489
+ class Field < AcrobatObject
490
+ def initialize(engine, field)
491
+ super(engine)
492
+
493
+ @field = field
494
+ end
495
+
496
+ def doc; Doc.new(@field.pdf) end
497
+ def name
498
+ (@field[:T].solve.value if @field.has_key?(:T)).to_s
499
+ end
500
+
501
+ def value
502
+ @field[:V].solve.value if @field.has_key?(:V)
503
+ end
504
+
505
+ def valueAsString
506
+ self.value.to_s
507
+ end
508
+
509
+ def type
510
+ (if @field.has_key?(:FT)
511
+ case @field[:FT].solve.value
512
+ when PDF::Field::Type::BUTTON
513
+ if @fields.has_key?(:Ff)
514
+ flags = @fields[:Ff].solve.value
515
+
516
+ if (flags & Origami::Annotation::Widget::Button::Flags::PUSHBUTTON) != 0
517
+ 'button'
518
+ elsif (flags & Origami::Annotation::Widget::Button::Flags::RADIO) != 0
519
+ 'radiobox'
520
+ else
521
+ 'checkbox'
522
+ end
523
+ end
524
+ when PDF::Field::Type::TEXT then 'text'
525
+ when PDF::Field::Type::SIGNATURE then 'signature'
526
+ when PDF::Field::Type::CHOICE
527
+ if @field.has_key?(:Ff)
528
+ if (@field[:Ff].solve.value & Origami::Annotation::Widget::Choice::Flags::COMBO).zero?
529
+ 'listbox'
530
+ else
531
+ 'combobox'
532
+ end
533
+ end
534
+ end
535
+ end).to_s
536
+ end
537
+
538
+ end
539
+
540
+ class Data < AcrobatObject
541
+ attr_reader :name, :path, :size
542
+ attr_reader :creationDate, :modDate
543
+ attr_reader :description, :MIMEType
544
+
545
+ def initialize(engine, name, size, path = nil, creationDate = nil, modDate = nil, description = nil, mimeType = nil)
546
+
547
+ super(engine)
548
+
549
+ @name, @path, @size = name, path, size
550
+ @creationDate, @modDate = creationDate, modDate
551
+ @description, @MIMEType = description, mimeType
552
+ end
553
+ end
554
+
263
555
  end
264
- end
265
556
 
266
- begin
267
- require 'v8'
557
+ class JavaScript::EngineError < Exception; end
268
558
 
269
559
  class JavaScript::Engine
270
560
 
561
+ attr_reader :global
271
562
  attr_reader :context
563
+ attr_reader :options
564
+ attr_reader :parseInt
272
565
 
273
- def initialize(pdf, params = {})
274
- options =
566
+ def initialize(pdf)
567
+ @options =
275
568
  {
276
569
  :viewerVersion => JavaScript::Platforms::WINDOWS,
570
+ :viewerType => JavaScript::Viewers::ADOBE_READER,
277
571
  :viewerVariation => JavaScript::Viewers::ADOBE_READER,
278
- :platform => 9
279
- }.update(params)
280
-
281
- doc = JavaScript::Doc.new(pdf)
282
- app = JavaScript::App.new(options[:platform], options[:viewerVariation], options[:viewerVersion])
283
- util = JavaScript::Util.new
284
- console = JavaScript::Console.new
285
-
286
- @context = V8::Context.new(:with => doc)
572
+ :platform => 9,
573
+ :console => STDOUT,
574
+ :log_method_calls => false
575
+ }
576
+
577
+ @global = JavaScript::Doc.new(self, pdf)
578
+ app = JavaScript::App.new(self)
579
+ acrohelp = JavaScript::Acrohelp.new(self)
580
+ global = JavaScript::Global.new(self)
581
+ console = JavaScript::Console.new(self)
582
+ util = JavaScript::Util.new(self)
583
+
584
+ @context = V8::Context.new(:with => @global)
287
585
  @context['app'] = app
586
+ @context['acrohelp'] = acrohelp
288
587
  @context['console'] = console
588
+ @context['global'] = global
289
589
  @context['util'] = util
590
+
591
+ @parseInt = @context['parseInt']
592
+ @hooks = {}
290
593
  end
291
594
 
595
+ #
596
+ # Evaluates a JavaScript code in the current context.
597
+ #
292
598
  def exec(script)
293
599
  @context.eval(script)
294
600
  end
295
- end
296
601
 
297
- rescue LoadError
298
- end
299
- end
602
+ #
603
+ # Set a hook on a JavaScript method.
604
+ #
605
+ def hook(name, &callback)
606
+ ns = name.split('.')
607
+ previous = @context
608
+
609
+ ns.each do |n|
610
+ raise JavaScript::EngineError, "#{name} does not exist" if previous.nil?
611
+ previous = previous[n]
612
+ end
613
+
614
+ case previous
615
+ when V8::Function, UnboundMethod, nil then
616
+ @context[name] = lambda do |*args|
617
+ callback[previous, *args]
618
+ end
619
+
620
+ @hooks[name] = [previous, callback]
621
+ else
622
+ raise JavaScript::EngineError, "#{name} is not a function"
623
+ end
624
+ end
625
+
626
+ #
627
+ # Removes an existing hook on a JavaScript method.
628
+ #
629
+ def unhook(name)
630
+ if @hooks.has_key?(name)
631
+ @context[name] = @hooks[name][0]
632
+ end
633
+ end
634
+
635
+ #
636
+ # Returns an Hash of all defined members in specified object name.
637
+ #
638
+ def members(obj)
639
+ members = {}
640
+ list = @context.eval <<-JS
641
+ (function(base){
642
+ var members = [];
643
+ for (var i in base) members.push([i, base[i]]);
644
+ return members;
645
+ })(#{obj})
646
+ JS
647
+
648
+ list.each do |var|
649
+ members[var[0]] = var[1]
650
+ end
651
+
652
+ members
653
+ end
654
+
655
+ #
656
+ # Returns all members in the global scope.
657
+ #
658
+ def scope
659
+ members('this')
660
+ end
300
661
 
301
- if defined?(PDF::JavaScript::Engine)
662
+ #
663
+ # Binds the V8 remote debugging agent on the specified TCP _port_.
664
+ #
665
+ def enable_debugger(port)
666
+ V8::C::Debug.EnableAgent("Origami", port)
667
+ end
668
+ end
669
+
670
+ end
671
+
302
672
  module String
303
- def eval_as_js(options = {})
304
- runtime = options[:runtime] || PDF::JavaScript::Engine.new(self.pdf, options)
305
- runtime.exec(self.value)
673
+ #
674
+ # Evaluates the current String as JavaScript.
675
+ #
676
+ def eval_js
677
+ self.pdf.eval_js(self.value)
306
678
  end
307
679
  end
308
680
 
309
681
  class Stream
310
- def eval_as_js(options = {})
311
- runtime = options[:runtime] || PDF::JavaScript::Engine.new(self.pdf, options)
312
- runtime.exec(self.data)
682
+ #
683
+ # Evaluates the current Stream as JavaScript.
684
+ #
685
+ def eval_js
686
+ self.pdf.eval_js(self.data)
313
687
  end
314
688
  end
315
689
 
316
690
  class PDF
691
+
692
+ #
693
+ # Executes a JavaScript script in the current document context.
694
+ #
317
695
  def eval_js(code)
318
- get_js_engine.exec(code)
696
+ js_engine.exec(code)
319
697
  end
320
698
 
321
- private
322
-
323
- def get_js_engine(options = {})
324
- @js_engine ||= PDF::JavaScript::Engine.new(self, options)
699
+ #
700
+ # Returns the JavaScript engine (if JavaScript support is present).
701
+ #
702
+ def js_engine
703
+ @js_engine ||= PDF::JavaScript::Engine.new(self)
325
704
  end
326
705
  end
706
+
707
+ rescue LoadError
327
708
  end
328
-
329
709
  end
710
+
@@ -54,11 +54,12 @@ require 'origami/encryption'
54
54
  require 'origami/linearization'
55
55
  require 'origami/obfuscation'
56
56
  require 'origami/xfa'
57
+ require 'origami/javascript'
57
58
 
58
59
  module Origami
59
60
 
60
- VERSION = "1.1.2"
61
- REVISION = "$Revision: rev 122/, 2011/09/26 12:12:39 darko $" #:nodoc:
61
+ VERSION = "1.2.0"
62
+ REVISION = "$Revision: rev 125/, 2011/09/29 15:18:36 darko $" #:nodoc:
62
63
 
63
64
  #
64
65
  # Global options for Origami.
@@ -179,6 +180,7 @@ module Origami
179
180
  # Reads and parses a PDF file from disk.
180
181
  #
181
182
  def read(filename, options = {:verbosity => Parser::VERBOSE_INSANE})
183
+ filename = File.expand_path(filename) if filename.is_a?(::String)
182
184
  PDF::LinearParser.new(options).parse(filename)
183
185
  end
184
186
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origami
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 1
9
8
  - 2
10
- version: 1.1.2
9
+ - 0
10
+ version: 1.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Guillaume Delugr\xC3\xA9"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-26 00:00:00 +02:00
18
+ date: 2011-09-29 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21