origami 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -1
- data/origami/dictionary.rb +11 -1
- data/origami/filters/runlength.rb +1 -1
- data/origami/javascript.rb +584 -203
- data/origami/pdf.rb +4 -2
- metadata +4 -4
data/README
CHANGED
data/origami/dictionary.rb
CHANGED
@@ -166,7 +166,17 @@ module Origami
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def [](key)
|
169
|
-
|
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)
|
data/origami/javascript.rb
CHANGED
@@ -25,305 +25,686 @@
|
|
25
25
|
|
26
26
|
module Origami
|
27
27
|
|
28
|
-
|
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
|
-
|
43
|
+
module JavaScript
|
31
44
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
45
|
+
module Platforms
|
46
|
+
WINDOWS = "WIN"
|
47
|
+
UNIX = "UNIX"
|
48
|
+
MAC = "MAC"
|
49
|
+
end
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
module Viewers
|
52
|
+
ADOBE_READER = "Reader"
|
53
|
+
end
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
#end
|
46
|
-
end
|
55
|
+
class MissingArgError < Exception
|
56
|
+
def initialize; super("Missing required argument.") end
|
57
|
+
end
|
47
58
|
|
48
|
-
|
49
|
-
|
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
|
-
|
68
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
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
|
-
|
86
|
-
|
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
|
-
|
94
|
-
|
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
|
-
(
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
119
|
-
|
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
|
-
|
122
|
-
file_desc = @pdf.resolve_name(Names::Root::EMBEDDEDFILES, cName)
|
166
|
+
raise NotAllowedError
|
123
167
|
|
124
|
-
|
125
|
-
|
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
|
-
|
134
|
-
|
180
|
+
class AcroTimer < AcrobatObject
|
181
|
+
def initialize(engine, timeout, code, repeat)
|
135
182
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
146
|
-
|
193
|
+
class TimeOut < AcroTimer
|
194
|
+
def initialize(engine, timeout, code)
|
195
|
+
super(engine, timeout, code, false)
|
196
|
+
end
|
197
|
+
end
|
147
198
|
|
148
|
-
|
199
|
+
class Interval < AcroTimer
|
200
|
+
def initialize(engine, timeout, code)
|
201
|
+
super(engine, timeout, code, true)
|
202
|
+
end
|
149
203
|
end
|
150
204
|
|
151
|
-
|
152
|
-
|
205
|
+
class ReadStream < AcrobatObject
|
206
|
+
def initialize(engine, data)
|
207
|
+
super(engine)
|
153
208
|
|
154
|
-
|
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
|
-
|
159
|
-
attr_reader :platform, :viewerVariation, :viewerVersion
|
218
|
+
class Acrohelp < AcrobatObject; end
|
160
219
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
end
|
220
|
+
class Global < AcrobatObject
|
221
|
+
def initialize(engine)
|
222
|
+
super(engine)
|
165
223
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
235
|
+
def [](name)
|
236
|
+
@vars[name][:value] if @vars.include?(name)
|
237
|
+
end
|
176
238
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
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
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
195
|
-
|
196
|
-
@field = field
|
197
|
-
end
|
276
|
+
def initialize(engine, pdf)
|
277
|
+
super(engine)
|
198
278
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
205
|
-
@field[:V].solve.value if @field.has_key?(:V)
|
206
|
-
end
|
336
|
+
acro_method 'closeDoc'
|
207
337
|
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
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
|
-
|
261
|
-
|
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
|
-
|
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
|
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
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
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
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
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
|
-
|
304
|
-
|
305
|
-
|
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
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
696
|
+
js_engine.exec(code)
|
319
697
|
end
|
320
698
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
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
|
+
|
data/origami/pdf.rb
CHANGED
@@ -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.
|
61
|
-
REVISION = "$Revision: rev
|
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:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
- 1
|
9
8
|
- 2
|
10
|
-
|
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-
|
18
|
+
date: 2011-09-29 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|