origami-docspring 2.2.0 → 2.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/examples/attachments/attachment.rb +7 -8
- data/examples/attachments/nested_document.rb +6 -5
- data/examples/encryption/encryption.rb +5 -4
- data/examples/events/events.rb +7 -6
- data/examples/flash/flash.rb +10 -9
- data/examples/forms/javascript.rb +14 -13
- data/examples/forms/xfa.rb +67 -66
- data/examples/javascript/hello_world.rb +6 -5
- data/examples/javascript/js_emulation.rb +26 -26
- data/examples/loop/goto.rb +12 -11
- data/examples/loop/named.rb +17 -16
- data/examples/signature/signature.rb +11 -11
- data/examples/uri/javascript.rb +25 -24
- data/examples/uri/open-uri.rb +5 -4
- data/examples/uri/submitform.rb +11 -10
- data/lib/origami/3d.rb +330 -334
- data/lib/origami/acroform.rb +267 -268
- data/lib/origami/actions.rb +266 -278
- data/lib/origami/annotations.rb +659 -670
- data/lib/origami/array.rb +192 -196
- data/lib/origami/boolean.rb +66 -70
- data/lib/origami/catalog.rb +360 -363
- data/lib/origami/collections.rb +132 -133
- data/lib/origami/compound.rb +125 -129
- data/lib/origami/destinations.rb +226 -237
- data/lib/origami/dictionary.rb +155 -154
- data/lib/origami/encryption.rb +967 -923
- data/lib/origami/extensions/fdf.rb +270 -275
- data/lib/origami/extensions/ppklite.rb +323 -328
- data/lib/origami/filespec.rb +170 -173
- data/lib/origami/filters/ascii.rb +162 -167
- data/lib/origami/filters/ccitt/tables.rb +248 -252
- data/lib/origami/filters/ccitt.rb +309 -312
- data/lib/origami/filters/crypt.rb +31 -34
- data/lib/origami/filters/dct.rb +47 -50
- data/lib/origami/filters/flate.rb +57 -60
- data/lib/origami/filters/jbig2.rb +50 -53
- data/lib/origami/filters/jpx.rb +40 -43
- data/lib/origami/filters/lzw.rb +151 -155
- data/lib/origami/filters/predictors.rb +250 -255
- data/lib/origami/filters/runlength.rb +111 -115
- data/lib/origami/filters.rb +319 -325
- data/lib/origami/font.rb +173 -177
- data/lib/origami/functions.rb +62 -66
- data/lib/origami/graphics/colors.rb +203 -208
- data/lib/origami/graphics/instruction.rb +79 -81
- data/lib/origami/graphics/path.rb +141 -144
- data/lib/origami/graphics/patterns.rb +156 -160
- data/lib/origami/graphics/render.rb +51 -47
- data/lib/origami/graphics/state.rb +144 -142
- data/lib/origami/graphics/text.rb +185 -188
- data/lib/origami/graphics/xobject.rb +818 -804
- data/lib/origami/graphics.rb +25 -26
- data/lib/origami/header.rb +63 -65
- data/lib/origami/javascript.rb +718 -651
- data/lib/origami/linearization.rb +284 -285
- data/lib/origami/metadata.rb +156 -135
- data/lib/origami/name.rb +98 -100
- data/lib/origami/null.rb +49 -51
- data/lib/origami/numeric.rb +133 -135
- data/lib/origami/obfuscation.rb +180 -182
- data/lib/origami/object.rb +634 -631
- data/lib/origami/optionalcontent.rb +147 -149
- data/lib/origami/outline.rb +46 -48
- data/lib/origami/outputintents.rb +76 -77
- data/lib/origami/page.rb +637 -596
- data/lib/origami/parser.rb +214 -221
- data/lib/origami/parsers/fdf.rb +44 -45
- data/lib/origami/parsers/pdf/lazy.rb +147 -154
- data/lib/origami/parsers/pdf/linear.rb +104 -109
- data/lib/origami/parsers/pdf.rb +109 -107
- data/lib/origami/parsers/ppklite.rb +44 -46
- data/lib/origami/pdf.rb +886 -896
- data/lib/origami/reference.rb +116 -120
- data/lib/origami/signature.rb +617 -625
- data/lib/origami/stream.rb +560 -558
- data/lib/origami/string.rb +366 -368
- data/lib/origami/template/patterns.rb +50 -52
- data/lib/origami/template/widgets.rb +111 -114
- data/lib/origami/trailer.rb +153 -157
- data/lib/origami/tree.rb +55 -57
- data/lib/origami/version.rb +19 -19
- data/lib/origami/webcapture.rb +87 -90
- data/lib/origami/xfa/config.rb +409 -414
- data/lib/origami/xfa/connectionset.rb +113 -117
- data/lib/origami/xfa/datasets.rb +38 -42
- data/lib/origami/xfa/localeset.rb +33 -37
- data/lib/origami/xfa/package.rb +49 -52
- data/lib/origami/xfa/pdf.rb +54 -59
- data/lib/origami/xfa/signature.rb +33 -37
- data/lib/origami/xfa/sourceset.rb +34 -38
- data/lib/origami/xfa/stylesheet.rb +35 -39
- data/lib/origami/xfa/template.rb +1630 -1634
- data/lib/origami/xfa/xdc.rb +33 -37
- data/lib/origami/xfa/xfa.rb +132 -123
- data/lib/origami/xfa/xfdf.rb +34 -38
- data/lib/origami/xfa/xmpmeta.rb +34 -38
- data/lib/origami/xfa.rb +50 -53
- data/lib/origami/xreftable.rb +462 -462
- data/lib/origami.rb +37 -38
- data/test/test_actions.rb +22 -20
- data/test/test_annotations.rb +54 -52
- data/test/test_forms.rb +23 -21
- data/test/test_native_types.rb +82 -78
- data/test/test_object_tree.rb +25 -24
- data/test/test_pages.rb +43 -41
- data/test/test_pdf.rb +2 -0
- data/test/test_pdf_attachment.rb +23 -21
- data/test/test_pdf_create.rb +16 -15
- data/test/test_pdf_encrypt.rb +69 -66
- data/test/test_pdf_parse.rb +131 -129
- data/test/test_pdf_parse_lazy.rb +53 -53
- data/test/test_pdf_sign.rb +67 -67
- data/test/test_streams.rb +145 -143
- data/test/test_xrefs.rb +46 -45
- metadata +64 -8
data/lib/origami/javascript.rb
CHANGED
@@ -1,713 +1,780 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# This file is part of Origami, PDF manipulation framework for Ruby
|
5
|
+
# Copyright (C) 2016 Guillaume Delugré.
|
6
|
+
#
|
7
|
+
# Origami is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# Origami is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#
|
2
20
|
|
3
|
-
|
4
|
-
|
21
|
+
module Origami
|
22
|
+
begin
|
23
|
+
require 'v8'
|
24
|
+
|
25
|
+
class PDF
|
26
|
+
module JavaScript
|
27
|
+
module Platforms
|
28
|
+
WINDOWS = "WIN"
|
29
|
+
UNIX = "UNIX"
|
30
|
+
MAC = "MAC"
|
31
|
+
end
|
5
32
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
(at your option) any later version.
|
33
|
+
module Viewers
|
34
|
+
ADOBE_READER = "Reader"
|
35
|
+
end
|
10
36
|
|
11
|
-
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU Lesser General Public License for more details.
|
37
|
+
class Error < Origami::Error; end
|
15
38
|
|
16
|
-
|
17
|
-
|
39
|
+
class MissingArgError < Error
|
40
|
+
def initialize
|
41
|
+
super("Missing required argument.")
|
42
|
+
end
|
43
|
+
end
|
18
44
|
|
19
|
-
|
45
|
+
class TypeError < Error
|
46
|
+
def initialize
|
47
|
+
super("Incorrect argument type.")
|
48
|
+
end
|
49
|
+
end
|
20
50
|
|
21
|
-
|
51
|
+
class InvalidArgsError < Error
|
52
|
+
def initialize
|
53
|
+
super("Incorrect arguments.")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class NotAllowedError < Error
|
58
|
+
def initialize
|
59
|
+
super("Security settings prevent access to this property or method.")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class HelpError < Error
|
64
|
+
def initialize
|
65
|
+
super("Help")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class GeneralError < Error
|
70
|
+
def initialize
|
71
|
+
super("Operation failed.")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Arg
|
76
|
+
attr_reader :name, :type, :required, :default
|
77
|
+
|
78
|
+
def initialize(declare = {})
|
79
|
+
@name = declare[:name]
|
80
|
+
@type = declare[:type]
|
81
|
+
@required = declare[:required]
|
82
|
+
@default = declare[:default]
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.[](declare = {})
|
86
|
+
new(declare)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.inspect(obj)
|
90
|
+
case obj
|
91
|
+
when V8::Function then "function #{obj.name}"
|
92
|
+
when V8::Array then obj.to_a.inspect
|
93
|
+
when V8::Object
|
94
|
+
"{#{obj.to_a.map { |k, v| "#{k}:#{Arg.inspect(v)}" }.join(", ")}}"
|
95
|
+
else
|
96
|
+
obj.inspect
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class AcrobatObject
|
102
|
+
def initialize(engine)
|
103
|
+
@engine = engine
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.check_method_args(args, def_args)
|
107
|
+
if args.first.is_a?(V8::Object)
|
108
|
+
check_method_named_args(args.first, def_args)
|
109
|
+
else
|
110
|
+
check_method_ordered_args(args, def_args)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.check_method_named_args(object, def_args)
|
115
|
+
members = object.entries.map { |k, _| k }
|
116
|
+
argv = []
|
117
|
+
def_args.each do |def_arg|
|
118
|
+
raise MissingArgError if def_arg.required && !members.include?(def_arg.name)
|
119
|
+
|
120
|
+
if members.include?(def_arg.name)
|
121
|
+
arg = object[def_arg.name]
|
122
|
+
raise TypeError if def_arg.type && !arg.is_a?(def_arg.type)
|
123
|
+
else
|
124
|
+
arg = def_arg.default
|
125
|
+
end
|
126
|
+
|
127
|
+
argv.push(arg)
|
128
|
+
end
|
129
|
+
|
130
|
+
argv
|
131
|
+
end
|
132
|
+
private_class_method :check_method_named_args
|
133
|
+
|
134
|
+
def self.check_method_ordered_args(args, def_args)
|
135
|
+
def_args.each_with_index do |def_arg, index|
|
136
|
+
raise MissingArgError if def_arg.required && (index >= args.length)
|
137
|
+
raise TypeError if def_arg.type && !args[index].is_a?(def_arg.type)
|
138
|
+
|
139
|
+
args.push(def_arg.default) if index >= args.length
|
140
|
+
end
|
141
|
+
|
142
|
+
args
|
143
|
+
end
|
144
|
+
private_class_method :check_method_ordered_args
|
145
|
+
|
146
|
+
def self.acro_method(name, *def_args, &b)
|
147
|
+
define_method(name) do |*args|
|
148
|
+
if @engine.options[:log_method_calls]
|
149
|
+
@engine.options[:console].puts(
|
150
|
+
"LOG: #{self.class}.#{name}(#{args.map { |arg| Arg.inspect(arg) }.join(",")})"
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
args = AcrobatObject.check_method_args(args, def_args)
|
155
|
+
instance_exec(*args, &b) if b
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.acro_method_protected(name, *def_args, &b)
|
160
|
+
define_method(name) do |*args|
|
161
|
+
if @engine.options[:log_method_calls]
|
162
|
+
@engine.options[:console].puts(
|
163
|
+
"LOG: #{self.class}.#{name}(#{args.map { |arg| arg.inspect }.join(",")})"
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
unless @engine.privileged?
|
168
|
+
raise NotAllowedError, "Security settings prevent access to this property or method."
|
169
|
+
end
|
170
|
+
|
171
|
+
args = AcrobatObject.check_method_args(args, def_args)
|
172
|
+
instance_exec(*args, &b) if b
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
"[object #{self.class.to_s.split("::").last}]"
|
178
|
+
end
|
179
|
+
alias_method :inspect, :to_s
|
180
|
+
end
|
181
|
+
|
182
|
+
class AcroTimer < AcrobatObject
|
183
|
+
def initialize(engine, timeout, code, repeat)
|
184
|
+
@thr = Thread.start(engine, timeout, code, repeat) do
|
185
|
+
loop do
|
186
|
+
sleep(timeout / 1000.0)
|
187
|
+
engine.exec(code.to_s)
|
188
|
+
break if !repeat
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
22
193
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
module Viewers
|
36
|
-
ADOBE_READER = "Reader"
|
37
|
-
end
|
38
|
-
|
39
|
-
class Error < Origami::Error; end
|
40
|
-
|
41
|
-
class MissingArgError < Error
|
42
|
-
def initialize; super("Missing required argument.") end
|
43
|
-
end
|
44
|
-
|
45
|
-
class TypeError < Error
|
46
|
-
def initialize; super("Incorrect argument type.") end
|
47
|
-
end
|
48
|
-
|
49
|
-
class InvalidArgsError < Error
|
50
|
-
def initialize; super("Incorrect arguments.") end
|
51
|
-
end
|
52
|
-
|
53
|
-
class NotAllowedError < Error
|
54
|
-
def initialize; super("Security settings prevent access to this property or method.") end
|
55
|
-
end
|
56
|
-
|
57
|
-
class HelpError < Error
|
58
|
-
def initialize; super("Help") end
|
59
|
-
end
|
60
|
-
|
61
|
-
class GeneralError < Error
|
62
|
-
def initialize; super("Operation failed.") end
|
63
|
-
end
|
64
|
-
|
65
|
-
class Arg
|
66
|
-
attr_reader :name, :type, :required, :default
|
67
|
-
|
68
|
-
def initialize(declare = {})
|
69
|
-
@name = declare[:name]
|
70
|
-
@type = declare[:type]
|
71
|
-
@required = declare[:required]
|
72
|
-
@default = declare[:default]
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.[](declare = {})
|
76
|
-
self.new(declare)
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.inspect(obj)
|
80
|
-
case obj
|
81
|
-
when V8::Function then "function #{obj.name}"
|
82
|
-
when V8::Array then obj.to_a.inspect
|
83
|
-
when V8::Object
|
84
|
-
"{#{obj.to_a.map{|k,v| "#{k}:#{Arg.inspect(v)}"}.join(', ')}}"
|
85
|
-
else
|
86
|
-
obj.inspect
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class AcrobatObject
|
92
|
-
def initialize(engine)
|
93
|
-
@engine = engine
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.check_method_args(args, def_args)
|
97
|
-
if args.first.is_a?(V8::Object)
|
98
|
-
check_method_named_args(args.first, def_args)
|
99
|
-
else
|
100
|
-
check_method_ordered_args(args, def_args)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.check_method_named_args(object, def_args)
|
105
|
-
members = object.entries.map {|k, _| k}
|
106
|
-
argv = []
|
107
|
-
def_args.each do |def_arg|
|
108
|
-
raise MissingArgError if def_arg.required and not members.include?(def_arg.name)
|
109
|
-
|
110
|
-
if members.include?(def_arg.name)
|
111
|
-
arg = object[def_arg.name]
|
112
|
-
raise TypeError if def_arg.type and not arg.is_a?(def_arg.type)
|
113
|
-
else
|
114
|
-
arg = def_arg.default
|
115
|
-
end
|
116
|
-
|
117
|
-
argv.push(arg)
|
118
|
-
end
|
119
|
-
|
120
|
-
argv
|
121
|
-
end
|
122
|
-
private_class_method :check_method_named_args
|
123
|
-
|
124
|
-
def self.check_method_ordered_args(args, def_args)
|
125
|
-
def_args.each_with_index do |def_arg, index|
|
126
|
-
raise MissingArgError if def_arg.required and index >= args.length
|
127
|
-
raise TypeError if def_arg.type and not args[index].is_a?(def_arg.type)
|
128
|
-
|
129
|
-
args.push(def_arg.default) if index >= args.length
|
130
|
-
end
|
131
|
-
|
132
|
-
args
|
133
|
-
end
|
134
|
-
private_class_method :check_method_ordered_args
|
135
|
-
|
136
|
-
def self.acro_method(name, *def_args, &b)
|
137
|
-
define_method(name) do |*args|
|
138
|
-
if @engine.options[:log_method_calls]
|
139
|
-
@engine.options[:console].puts(
|
140
|
-
"LOG: #{self.class}.#{name}(#{args.map{|arg| Arg.inspect(arg)}.join(',')})"
|
141
|
-
)
|
142
|
-
end
|
143
|
-
|
144
|
-
args = AcrobatObject.check_method_args(args, def_args)
|
145
|
-
self.instance_exec(*args, &b) if b
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def self.acro_method_protected(name, *def_args, &b)
|
150
|
-
define_method(name) do |*args|
|
151
|
-
if @engine.options[:log_method_calls]
|
152
|
-
@engine.options[:console].puts(
|
153
|
-
"LOG: #{self.class}.#{name}(#{args.map{|arg| arg.inspect}.join(',')})"
|
154
|
-
)
|
155
|
-
end
|
156
|
-
|
157
|
-
unless @engine.privileged?
|
158
|
-
raise NotAllowedError, "Security settings prevent access to this property or method."
|
159
|
-
end
|
160
|
-
|
161
|
-
args = AcrobatObject.check_method_args(args, def_args)
|
162
|
-
self.instance_exec(*args, &b) if b
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def to_s
|
167
|
-
"[object #{self.class.to_s.split('::').last}]"
|
168
|
-
end
|
169
|
-
alias inspect to_s
|
170
|
-
end
|
171
|
-
|
172
|
-
class AcroTimer < AcrobatObject
|
173
|
-
def initialize(engine, timeout, code, repeat)
|
174
|
-
@thr = Thread.start(engine, timeout, code, repeat) do
|
175
|
-
loop do
|
176
|
-
sleep(timeout / 1000.0)
|
177
|
-
engine.exec(code.to_s)
|
178
|
-
break if not repeat
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
class TimeOut < AcroTimer
|
185
|
-
def initialize(engine, timeout, code)
|
186
|
-
super(engine, timeout, code, false)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
class Interval < AcroTimer
|
191
|
-
def initialize(engine, timeout, code)
|
192
|
-
super(engine, timeout, code, true)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
class ReadStream < AcrobatObject
|
197
|
-
def initialize(engine, data)
|
198
|
-
super(engine)
|
199
|
-
|
200
|
-
@data = data
|
201
|
-
end
|
202
|
-
|
203
|
-
acro_method 'read', Arg[name: 'nBytes', type: Numeric, required: true] do |nBytes|
|
204
|
-
@data.slice!(0, nBytes).unpack("H*")[0]
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
class Acrohelp < AcrobatObject; end
|
209
|
-
|
210
|
-
class Global < AcrobatObject
|
211
|
-
def initialize(engine)
|
212
|
-
super(engine)
|
213
|
-
|
214
|
-
@vars = {}
|
215
|
-
end
|
216
|
-
|
217
|
-
def []=(name, value)
|
218
|
-
@vars[name] ||= {callbacks: []}
|
219
|
-
@vars[name][:value] = value
|
220
|
-
@vars[name][:callbacks].each do |callback|
|
221
|
-
callback.call(value)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def [](name)
|
226
|
-
@vars[name][:value] if @vars.include?(name)
|
227
|
-
end
|
228
|
-
|
229
|
-
acro_method 'setPersistent',
|
230
|
-
Arg[name: 'cVariable', required: true],
|
231
|
-
Arg[name: 'bPersist', required: true] do |cVariable, _bPersist|
|
232
|
-
|
233
|
-
raise GeneralError unless @vars.include?(cVariable)
|
234
|
-
end
|
235
|
-
|
236
|
-
acro_method 'subscribe',
|
237
|
-
Arg[name: 'cVariable', required: true],
|
238
|
-
Arg[name: 'fCallback', type: V8::Function, require: true] do |cVariable, fCallback|
|
239
|
-
|
240
|
-
if @vars.include?(cVariable)
|
241
|
-
@vars[cVariable][:callbacks].push(fCallback)
|
242
|
-
fCallback.call(@vars[cVariable][:value])
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
class Doc < AcrobatObject
|
248
|
-
attr_reader :info
|
249
|
-
attr_accessor :disclosed
|
250
|
-
attr_reader :hidden
|
251
|
-
|
252
|
-
attr_reader :app, :acrohelp, :global, :console, :util
|
253
|
-
|
254
|
-
class Info < AcrobatObject
|
255
|
-
def initialize(engine, doc)
|
256
|
-
super(engine)
|
257
|
-
|
258
|
-
@doc = doc
|
259
|
-
end
|
260
|
-
|
261
|
-
def title; @doc.title.to_s end
|
262
|
-
def author; @doc.author.to_s end
|
263
|
-
def subject; @doc.subject.to_s end
|
264
|
-
def keywords; @doc.keywords.to_s end
|
265
|
-
def creator; @doc.creator.to_s end
|
266
|
-
def creationDate; @doc.creation_date.to_s end
|
267
|
-
def modDate; @doc.mod_date.to_s end
|
268
|
-
end
|
269
|
-
|
270
|
-
def initialize(*args)
|
271
|
-
engine, pdf = args # XXX: Bypass therubyracer bug #238. Temporary.
|
272
|
-
super(engine)
|
273
|
-
|
274
|
-
@pdf = pdf
|
275
|
-
@disclosed = false
|
276
|
-
@hidden = false
|
277
|
-
@info = Info.new(@engine, pdf)
|
278
|
-
|
279
|
-
@app = JavaScript::App.new(@engine)
|
280
|
-
@acrohelp = JavaScript::Acrohelp.new(@engine)
|
281
|
-
@global = JavaScript::Global.new(@engine)
|
282
|
-
@console = JavaScript::Console.new(@engine)
|
283
|
-
@util = JavaScript::Util.new(@engine)
|
284
|
-
end
|
285
|
-
|
286
|
-
### PROPERTIES ###
|
287
|
-
|
288
|
-
def numFields
|
289
|
-
fields = @pdf.fields
|
290
|
-
|
291
|
-
fields.size
|
292
|
-
end
|
293
|
-
|
294
|
-
def numPages; @pdf.pages.size end
|
295
|
-
|
296
|
-
def title; @info.title end
|
297
|
-
def author; @info.author end
|
298
|
-
def subject; @info.subject end
|
299
|
-
def keywords; @info.keywords end
|
300
|
-
def creator; @info.creator end
|
301
|
-
def creationDate; @info.creationDate end
|
302
|
-
def modDate; @info.modDate end
|
303
|
-
|
304
|
-
def metadata
|
305
|
-
meta = @pdf.Catalog.Metadata
|
306
|
-
|
307
|
-
(meta.data if meta.is_a?(Stream)).to_s
|
308
|
-
end
|
309
|
-
|
310
|
-
def filesize; @pdf.original_filesize end
|
311
|
-
def path; @pdf.original_filename.to_s end
|
312
|
-
def documentFileName; File.basename(self.path) end
|
313
|
-
def URL; "file://#{self.path}" end
|
314
|
-
def baseURL; '' end
|
315
|
-
|
316
|
-
def dataObjects
|
317
|
-
data_objs = []
|
318
|
-
@pdf.each_attachment do |name, file_desc|
|
319
|
-
if file_desc and file_desc.EF and (f = file_desc.EF.F)
|
320
|
-
data_objs.push Data.new(@engine, name, f.data.size) if f.is_a?(Stream)
|
321
|
-
end
|
322
|
-
end
|
194
|
+
class TimeOut < AcroTimer
|
195
|
+
def initialize(engine, timeout, code)
|
196
|
+
super(engine, timeout, code, false)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class Interval < AcroTimer
|
201
|
+
def initialize(engine, timeout, code)
|
202
|
+
super(engine, timeout, code, true)
|
203
|
+
end
|
204
|
+
end
|
323
205
|
|
324
|
-
|
325
|
-
|
206
|
+
class ReadStream < AcrobatObject
|
207
|
+
def initialize(engine, data)
|
208
|
+
super(engine)
|
326
209
|
|
327
|
-
|
210
|
+
@data = data
|
211
|
+
end
|
212
|
+
|
213
|
+
acro_method 'read', Arg[name: 'nBytes', type: Numeric, required: true] do |nBytes|
|
214
|
+
@data.slice!(0, nBytes).unpack1("H*")
|
215
|
+
end
|
216
|
+
end
|
328
217
|
|
329
|
-
|
218
|
+
class Acrohelp < AcrobatObject; end
|
330
219
|
|
331
|
-
|
332
|
-
|
220
|
+
class Global < AcrobatObject
|
221
|
+
def initialize(engine)
|
222
|
+
super
|
223
|
+
|
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
|
234
|
+
|
235
|
+
def [](name)
|
236
|
+
@vars[name][:value] if @vars.include?(name)
|
237
|
+
end
|
238
|
+
|
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
|
244
|
+
|
245
|
+
acro_method 'subscribe',
|
246
|
+
Arg[name: 'cVariable', required: true],
|
247
|
+
Arg[name: 'fCallback', type: V8::Function, require: 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
|
253
|
+
end
|
254
|
+
|
255
|
+
class Doc < AcrobatObject
|
256
|
+
attr_reader :info
|
257
|
+
attr_accessor :disclosed
|
258
|
+
attr_reader :hidden
|
259
|
+
|
260
|
+
attr_reader :app, :acrohelp, :global, :console, :util
|
261
|
+
|
262
|
+
class Info < AcrobatObject
|
263
|
+
def initialize(engine, doc)
|
264
|
+
super(engine)
|
265
|
+
|
266
|
+
@doc = doc
|
267
|
+
end
|
268
|
+
|
269
|
+
def title
|
270
|
+
@doc.title.to_s
|
271
|
+
end
|
333
272
|
|
334
|
-
|
273
|
+
def author
|
274
|
+
@doc.author.to_s
|
275
|
+
end
|
335
276
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
raise TypeError
|
340
|
-
end
|
341
|
-
end
|
277
|
+
def subject
|
278
|
+
@doc.subject.to_s
|
279
|
+
end
|
342
280
|
|
343
|
-
|
344
|
-
|
345
|
-
|
281
|
+
def keywords
|
282
|
+
@doc.keywords.to_s
|
283
|
+
end
|
346
284
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
ReadStream.new(@engine, f.data) if f.is_a?(Stream)
|
351
|
-
else
|
352
|
-
raise TypeError
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
acro_method 'exportDataObject',
|
357
|
-
Arg[name: 'cName', type: ::String, required: true],
|
358
|
-
Arg[name: 'cDIPath' ],
|
359
|
-
Arg[name: 'bAllowAuth'],
|
360
|
-
Arg[name: 'nLaunch'] do |cName, _cDIPath, _bAllowAuth, _nLaunch|
|
361
|
-
|
362
|
-
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
363
|
-
|
364
|
-
if file_desc and file_desc.EF and (f = file_desc.EF.F)
|
365
|
-
else
|
366
|
-
raise TypeError
|
367
|
-
end
|
285
|
+
def creator
|
286
|
+
@doc.creator.to_s
|
287
|
+
end
|
368
288
|
|
369
|
-
|
370
|
-
|
289
|
+
def creationDate
|
290
|
+
@doc.creation_date.to_s
|
291
|
+
end
|
371
292
|
|
372
|
-
|
373
|
-
|
293
|
+
def modDate
|
294
|
+
@doc.mod_date.to_s
|
295
|
+
end
|
296
|
+
end
|
374
297
|
|
375
|
-
|
298
|
+
def initialize(*args)
|
299
|
+
engine, pdf = args # XXX: Bypass therubyracer bug #238. Temporary.
|
300
|
+
super(engine)
|
376
301
|
|
377
|
-
|
378
|
-
|
302
|
+
@pdf = pdf
|
303
|
+
@disclosed = false
|
304
|
+
@hidden = false
|
305
|
+
@info = Info.new(@engine, pdf)
|
379
306
|
|
380
|
-
|
381
|
-
|
307
|
+
@app = JavaScript::App.new(@engine)
|
308
|
+
@acrohelp = JavaScript::Acrohelp.new(@engine)
|
309
|
+
@global = JavaScript::Global.new(@engine)
|
310
|
+
@console = JavaScript::Console.new(@engine)
|
311
|
+
@util = JavaScript::Util.new(@engine)
|
312
|
+
end
|
382
313
|
|
383
|
-
|
384
|
-
case nIndex
|
385
|
-
when false then 0
|
386
|
-
when true then 1
|
387
|
-
else
|
388
|
-
@engine.parseInt.call(nIndex)
|
389
|
-
end
|
314
|
+
### PROPERTIES ###
|
390
315
|
|
391
|
-
|
392
|
-
|
316
|
+
def numFields
|
317
|
+
fields = @pdf.fields
|
393
318
|
|
394
|
-
|
395
|
-
|
396
|
-
else
|
397
|
-
""
|
398
|
-
end
|
399
|
-
end
|
400
|
-
end
|
319
|
+
fields.size
|
320
|
+
end
|
401
321
|
|
402
|
-
|
322
|
+
def numPages
|
323
|
+
@pdf.pages.size
|
324
|
+
end
|
403
325
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
def viewerVersion; @engine.options[:viewerVersion] end
|
326
|
+
def title
|
327
|
+
@info.title
|
328
|
+
end
|
408
329
|
|
409
|
-
|
410
|
-
|
411
|
-
|
330
|
+
def author
|
331
|
+
@info.author
|
332
|
+
end
|
412
333
|
|
413
|
-
|
414
|
-
|
415
|
-
|
334
|
+
def subject
|
335
|
+
@info.subject
|
336
|
+
end
|
416
337
|
|
417
|
-
|
418
|
-
|
338
|
+
def keywords
|
339
|
+
@info.keywords
|
340
|
+
end
|
419
341
|
|
420
|
-
|
421
|
-
|
422
|
-
|
342
|
+
def creator
|
343
|
+
@info.creator
|
344
|
+
end
|
423
345
|
|
424
|
-
|
425
|
-
|
346
|
+
def creationDate
|
347
|
+
@info.creationDate
|
348
|
+
end
|
426
349
|
|
427
|
-
|
428
|
-
|
350
|
+
def modDate
|
351
|
+
@info.modDate
|
352
|
+
end
|
429
353
|
|
430
|
-
|
431
|
-
|
432
|
-
end
|
354
|
+
def metadata
|
355
|
+
meta = @pdf.Catalog.Metadata
|
433
356
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
oInterval.instance_variable_get(:@thr).terminate
|
438
|
-
nil
|
439
|
-
end
|
440
|
-
|
441
|
-
acro_method_protected 'addMenuItem'
|
442
|
-
acro_method_protected 'addSubMenu'
|
443
|
-
acro_method 'addToolButton'
|
444
|
-
acro_method_protected 'beginPriv'
|
445
|
-
acro_method 'beep'
|
446
|
-
acro_method_protected 'browseForDoc'
|
447
|
-
acro_method_protected 'endPriv'
|
448
|
-
end
|
449
|
-
|
450
|
-
class Console < AcrobatObject
|
451
|
-
def println(*args)
|
452
|
-
raise MissingArgError unless args.length > 0
|
357
|
+
(meta.data if meta.is_a?(Stream)).to_s
|
358
|
+
end
|
453
359
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
acro_method 'show'
|
458
|
-
acro_method 'clear'
|
459
|
-
acro_method 'hide'
|
460
|
-
end
|
360
|
+
def filesize
|
361
|
+
@pdf.original_filesize
|
362
|
+
end
|
461
363
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |cString, _cCharset|
|
364
|
+
def path
|
365
|
+
@pdf.original_filename.to_s
|
366
|
+
end
|
466
367
|
|
467
|
-
|
468
|
-
|
368
|
+
def documentFileName
|
369
|
+
File.basename(path)
|
370
|
+
end
|
469
371
|
|
470
|
-
|
471
|
-
|
472
|
-
|
372
|
+
def URL
|
373
|
+
"file://#{path}"
|
374
|
+
end
|
473
375
|
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
class Field < AcrobatObject
|
479
|
-
def initialize(engine, field)
|
480
|
-
super(engine)
|
481
|
-
|
482
|
-
@field = field
|
483
|
-
end
|
484
|
-
|
485
|
-
def doc; Doc.new(@field.document) end
|
486
|
-
def name
|
487
|
-
(@field.T.value if @field.has_key?(:T)).to_s
|
488
|
-
end
|
376
|
+
def baseURL
|
377
|
+
''
|
378
|
+
end
|
489
379
|
|
490
|
-
|
491
|
-
|
492
|
-
|
380
|
+
def dataObjects
|
381
|
+
data_objs = []
|
382
|
+
@pdf.each_attachment do |name, file_desc|
|
383
|
+
if file_desc&.EF && (f = file_desc.EF.F)
|
384
|
+
data_objs.push Data.new(@engine, name, f.data.size) if f.is_a?(Stream)
|
385
|
+
end
|
386
|
+
end
|
493
387
|
|
494
|
-
|
495
|
-
|
496
|
-
end
|
388
|
+
data_objs
|
389
|
+
end
|
497
390
|
|
498
|
-
|
499
|
-
return '' unless @field.key?(:FT)
|
391
|
+
### METHODS ###
|
500
392
|
|
501
|
-
|
502
|
-
case @field.FT.value
|
503
|
-
when PDF::Field::Type::BUTTON
|
504
|
-
button_type
|
393
|
+
acro_method 'closeDoc'
|
505
394
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
choice_type
|
510
|
-
end
|
511
|
-
|
512
|
-
type_name.to_s
|
513
|
-
end
|
514
|
-
|
515
|
-
private
|
516
|
-
|
517
|
-
def button_type
|
518
|
-
return if @field.key?(:Ff) and not @field.Ff.is_a?(Integer)
|
519
|
-
|
520
|
-
flags = @field.Ff.to_i
|
521
|
-
|
522
|
-
if (flags & Annotation::Widget::Button::Flags::PUSHBUTTON) != 0
|
523
|
-
'button'
|
524
|
-
elsif (flags & Annotation::Widget::Button::Flags::RADIO) != 0
|
525
|
-
'radiobox'
|
526
|
-
else
|
527
|
-
'checkbox'
|
528
|
-
end
|
529
|
-
end
|
530
|
-
|
531
|
-
def choice_type
|
532
|
-
return if @field.key?(:Ff) and not @field.Ff.is_a?(Integer)
|
533
|
-
|
534
|
-
if (@field.Ff.to_i & Annotation::Widget::Choice::Flags::COMBO) != 0
|
535
|
-
'combobox'
|
536
|
-
else
|
537
|
-
'listbox'
|
538
|
-
end
|
539
|
-
end
|
540
|
-
end
|
541
|
-
|
542
|
-
class Data < AcrobatObject
|
543
|
-
attr_reader :name, :path, :size
|
544
|
-
attr_reader :creationDate, :modDate
|
545
|
-
attr_reader :description, :MIMEType
|
546
|
-
|
547
|
-
def initialize(engine, name, size, **metadata)
|
548
|
-
super(engine)
|
395
|
+
acro_method 'getDataObject',
|
396
|
+
Arg[name: 'cName', type: ::String, required: true] do |cName|
|
397
|
+
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
549
398
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
end
|
555
|
-
end
|
399
|
+
if file_desc&.EF && (f = file_desc.EF.F)
|
400
|
+
Data.new(@engine, cName, f.data.size) if f.is_a?(Stream)
|
401
|
+
else
|
402
|
+
raise TypeError
|
556
403
|
end
|
404
|
+
end
|
557
405
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
@doc = JavaScript::Doc.new(self, pdf)
|
581
|
-
@context = V8::Context.new(with: @doc)
|
582
|
-
@privileged_mode = @options[:privileged_mode]
|
583
|
-
|
584
|
-
@parseInt = V8::Context.new['parseInt']
|
585
|
-
@hooks = {}
|
586
|
-
end
|
587
|
-
|
588
|
-
#
|
589
|
-
# Returns true if the engine is set to execute in privileged mode.
|
590
|
-
# Allows execution of security protected methods.
|
591
|
-
#
|
592
|
-
def privileged?
|
593
|
-
@privileged_mode
|
594
|
-
end
|
595
|
-
|
596
|
-
#
|
597
|
-
# Evaluates a JavaScript code in the current context.
|
598
|
-
#
|
599
|
-
def exec(script)
|
600
|
-
@context.eval(script)
|
601
|
-
end
|
602
|
-
|
603
|
-
#
|
604
|
-
# Set a hook on a JavaScript method.
|
605
|
-
#
|
606
|
-
def hook(name, &callback)
|
607
|
-
ns = name.split('.')
|
608
|
-
previous = @context
|
609
|
-
|
610
|
-
ns.each do |n|
|
611
|
-
raise JavaScript::EngineError, "#{name} does not exist" if previous.nil?
|
612
|
-
previous = previous[n]
|
613
|
-
end
|
614
|
-
|
615
|
-
case previous
|
616
|
-
when V8::Function, UnboundMethod, nil then
|
617
|
-
@context[name] = lambda do |*args|
|
618
|
-
callback[previous, *args]
|
619
|
-
end
|
620
|
-
|
621
|
-
@hooks[name] = [previous, callback]
|
622
|
-
else
|
623
|
-
raise JavaScript::EngineError, "#{name} is not a function"
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
#
|
628
|
-
# Removes an existing hook on a JavaScript method.
|
629
|
-
#
|
630
|
-
def unhook(name)
|
631
|
-
@context[name] = @hooks[name][0] if @hooks.has_key?(name)
|
632
|
-
end
|
633
|
-
|
634
|
-
#
|
635
|
-
# Returns an Hash of all defined members in specified object name.
|
636
|
-
#
|
637
|
-
def members(obj)
|
638
|
-
members = {}
|
639
|
-
list = @context.eval <<-JS
|
640
|
-
(function(base) {
|
641
|
-
var members = [];
|
642
|
-
for (var i in base) members.push([i, base[i]]);
|
643
|
-
return members;
|
644
|
-
})(#{obj})
|
645
|
-
JS
|
646
|
-
|
647
|
-
list.each do |var|
|
648
|
-
members[var[0]] = var[1]
|
649
|
-
end
|
650
|
-
|
651
|
-
members
|
652
|
-
end
|
653
|
-
|
654
|
-
#
|
655
|
-
# Returns all members in the global scope.
|
656
|
-
#
|
657
|
-
def scope
|
658
|
-
members('this')
|
659
|
-
end
|
660
|
-
|
661
|
-
#
|
662
|
-
# Binds the V8 remote debugging agent on the specified TCP _port_.
|
663
|
-
#
|
664
|
-
def enable_debugger(port = 5858)
|
665
|
-
V8::C::Debug.EnableAgent("Origami", port)
|
666
|
-
end
|
667
|
-
|
668
|
-
def debugger_break
|
669
|
-
exec 'debugger'
|
670
|
-
end
|
406
|
+
acro_method 'getDataObjectContents',
|
407
|
+
Arg[name: 'cName', type: ::String, required: true],
|
408
|
+
Arg[name: 'bAllowAuth', default: false] do |cName, _bAllowAuth|
|
409
|
+
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
410
|
+
|
411
|
+
if file_desc&.EF && (f = file_desc.EF.F)
|
412
|
+
ReadStream.new(@engine, f.data) if f.is_a?(Stream)
|
413
|
+
else
|
414
|
+
raise TypeError
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
acro_method 'exportDataObject',
|
419
|
+
Arg[name: 'cName', type: ::String, required: true],
|
420
|
+
Arg[name: 'cDIPath'],
|
421
|
+
Arg[name: 'bAllowAuth'],
|
422
|
+
Arg[name: 'nLaunch'] do |cName, _cDIPath, _bAllowAuth, _nLaunch|
|
423
|
+
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
424
|
+
|
425
|
+
if file_desc&.EF && (f = file_desc.EF.F)
|
426
|
+
else
|
427
|
+
raise TypeError
|
671
428
|
end
|
672
|
-
end
|
673
429
|
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
430
|
+
raise TypeError if f.nil?
|
431
|
+
end
|
432
|
+
|
433
|
+
acro_method 'getField',
|
434
|
+
Arg[name: 'cName', type: ::Object, required: true] do |cName|
|
435
|
+
field = @pdf.get_field(cName)
|
436
|
+
|
437
|
+
Field.new(@engine, field) if field
|
438
|
+
end
|
439
|
+
|
440
|
+
acro_method 'getNthFieldName',
|
441
|
+
Arg[name: 'nIndex', type: ::Object, required: true] do |nIndex|
|
442
|
+
nIndex =
|
443
|
+
case nIndex
|
444
|
+
when false then 0
|
445
|
+
when true then 1
|
446
|
+
else
|
447
|
+
@engine.parseInt.call(nIndex)
|
448
|
+
end
|
449
|
+
|
450
|
+
raise TypeError if (nIndex.is_a?(Float) && nIndex.nan?) || (nIndex < 0)
|
451
|
+
fields = @pdf.fields
|
452
|
+
|
453
|
+
if fields && (nIndex <= fields.size - 1)
|
454
|
+
Field.new(@engine, fields.take(nIndex + 1).last).name.to_s
|
455
|
+
else
|
456
|
+
""
|
680
457
|
end
|
458
|
+
end
|
681
459
|
end
|
682
460
|
|
683
|
-
class
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
461
|
+
class App < AcrobatObject
|
462
|
+
def platform
|
463
|
+
@engine.options[:platform]
|
464
|
+
end
|
465
|
+
|
466
|
+
def viewerType
|
467
|
+
@engine.options[:viewerType]
|
468
|
+
end
|
469
|
+
|
470
|
+
def viewerVariation
|
471
|
+
@engine.options[:viewerVariation]
|
472
|
+
end
|
473
|
+
|
474
|
+
def viewerVersion
|
475
|
+
@engine.options[:viewerVersion]
|
476
|
+
end
|
477
|
+
|
478
|
+
def activeDocs
|
479
|
+
[]
|
480
|
+
end
|
481
|
+
|
482
|
+
### METHODS ###
|
483
|
+
|
484
|
+
acro_method 'setInterval',
|
485
|
+
Arg[name: 'cExpr', required: true],
|
486
|
+
Arg[name: 'nMilliseconds', type: Numeric, required: true] do |cExpr, nMilliseconds|
|
487
|
+
Interval.new(@engine, nMilliseconds, cExpr)
|
488
|
+
end
|
489
|
+
|
490
|
+
acro_method 'setTimeOut',
|
491
|
+
Arg[name: 'cExpr', required: true],
|
492
|
+
Arg[name: 'nMilliseconds', type: Numeric, required: true] do |cExpr, nMilliseconds|
|
493
|
+
TimeOut.new(@engine, nMilliseconds, cExpr)
|
494
|
+
end
|
495
|
+
|
496
|
+
acro_method 'clearInterval',
|
497
|
+
Arg[name: 'oInterval', type: Interval, required: true] do |oInterval|
|
498
|
+
oInterval.instance_variable_get(:@thr).terminate
|
499
|
+
nil
|
500
|
+
end
|
501
|
+
|
502
|
+
acro_method 'clearTimeOut',
|
503
|
+
Arg[name: 'oInterval', type: TimeOut, required: true] do |oInterval|
|
504
|
+
oInterval.instance_variable_get(:@thr).terminate
|
505
|
+
nil
|
506
|
+
end
|
507
|
+
|
508
|
+
acro_method_protected 'addMenuItem'
|
509
|
+
acro_method_protected 'addSubMenu'
|
510
|
+
acro_method 'addToolButton'
|
511
|
+
acro_method_protected 'beginPriv'
|
512
|
+
acro_method 'beep'
|
513
|
+
acro_method_protected 'browseForDoc'
|
514
|
+
acro_method_protected 'endPriv'
|
690
515
|
end
|
691
516
|
|
692
|
-
class
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
517
|
+
class Console < AcrobatObject
|
518
|
+
def println(*args)
|
519
|
+
raise MissingArgError unless args.length > 0
|
520
|
+
|
521
|
+
@engine.options[:console].puts(args.first.to_s)
|
522
|
+
end
|
523
|
+
|
524
|
+
acro_method 'show'
|
525
|
+
acro_method 'clear'
|
526
|
+
acro_method 'hide'
|
527
|
+
end
|
528
|
+
|
529
|
+
class Util < AcrobatObject
|
530
|
+
acro_method 'streamFromString',
|
531
|
+
Arg[name: 'cString', type: ::Object, required: true],
|
532
|
+
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |cString, _cCharset|
|
533
|
+
ReadStream.new(@engine, cString.to_s)
|
534
|
+
end
|
535
|
+
|
536
|
+
acro_method 'stringFromStream',
|
537
|
+
Arg[name: 'oStream', type: ReadStream, required: true],
|
538
|
+
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |oStream, _cCharset|
|
539
|
+
oStream.instance_variable_get(:@data).dup
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
class Field < AcrobatObject
|
544
|
+
def initialize(engine, field)
|
545
|
+
super(engine)
|
546
|
+
|
547
|
+
@field = field
|
548
|
+
end
|
549
|
+
|
550
|
+
def doc
|
551
|
+
Doc.new(@field.document)
|
552
|
+
end
|
553
|
+
|
554
|
+
def name
|
555
|
+
(@field.T.value if @field.has_key?(:T)).to_s
|
556
|
+
end
|
557
|
+
|
558
|
+
def value
|
559
|
+
@field.V.value if @field.has_key?(:V)
|
560
|
+
end
|
561
|
+
|
562
|
+
def valueAsString
|
563
|
+
value.to_s
|
564
|
+
end
|
565
|
+
|
566
|
+
def type
|
567
|
+
return '' unless @field.key?(:FT)
|
568
|
+
|
569
|
+
type_name =
|
570
|
+
case @field.FT.value
|
571
|
+
when PDF::Field::Type::BUTTON
|
572
|
+
button_type
|
573
|
+
|
574
|
+
when PDF::Field::Type::TEXT then 'text'
|
575
|
+
when PDF::Field::Type::SIGNATURE then 'signature'
|
576
|
+
when PDF::Field::Type::CHOICE
|
577
|
+
choice_type
|
578
|
+
end
|
579
|
+
|
580
|
+
type_name.to_s
|
581
|
+
end
|
582
|
+
|
583
|
+
private
|
584
|
+
|
585
|
+
def button_type
|
586
|
+
return if @field.key?(:Ff) && !@field.Ff.is_a?(Integer)
|
587
|
+
|
588
|
+
flags = @field.Ff.to_i
|
589
|
+
|
590
|
+
if (flags & Annotation::Widget::Button::Flags::PUSHBUTTON) != 0
|
591
|
+
'button'
|
592
|
+
elsif (flags & Annotation::Widget::Button::Flags::RADIO) != 0
|
593
|
+
'radiobox'
|
594
|
+
else
|
595
|
+
'checkbox'
|
698
596
|
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def choice_type
|
600
|
+
return if @field.key?(:Ff) && !@field.Ff.is_a?(Integer)
|
699
601
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
@js_engine ||= PDF::JavaScript::Engine.new(self)
|
602
|
+
if (@field.Ff.to_i & Annotation::Widget::Choice::Flags::COMBO) != 0
|
603
|
+
'combobox'
|
604
|
+
else
|
605
|
+
'listbox'
|
705
606
|
end
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
class Data < AcrobatObject
|
611
|
+
attr_reader :name, :path, :size
|
612
|
+
attr_reader :creationDate, :modDate
|
613
|
+
attr_reader :description, :MIMEType
|
614
|
+
|
615
|
+
def initialize(engine, name, size, **metadata)
|
616
|
+
super(engine)
|
617
|
+
|
618
|
+
@name, @size = name, size
|
619
|
+
|
620
|
+
@path, @creationDate, @modDate,
|
621
|
+
@description, @MIMEType = metadata.values_at(:path, :creationDate, :modDate, :description, :MIMEType)
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
class JavaScript::EngineError < Origami::Error; end
|
627
|
+
|
628
|
+
class JavaScript::Engine
|
629
|
+
attr_reader :doc
|
630
|
+
attr_reader :context
|
631
|
+
attr_reader :options
|
632
|
+
attr_reader :privileged_mode
|
633
|
+
attr_reader :parseInt
|
634
|
+
|
635
|
+
def initialize(pdf)
|
636
|
+
@options =
|
637
|
+
{
|
638
|
+
formsVersion: 11.008,
|
639
|
+
viewerVersion: 11.008,
|
640
|
+
viewerType: JavaScript::Viewers::ADOBE_READER,
|
641
|
+
viewerVariation: JavaScript::Viewers::ADOBE_READER,
|
642
|
+
platform: JavaScript::Platforms::WINDOWS,
|
643
|
+
console: $stdout,
|
644
|
+
log_method_calls: false,
|
645
|
+
privileged_mode: false
|
646
|
+
}
|
647
|
+
|
648
|
+
@doc = JavaScript::Doc.new(self, pdf)
|
649
|
+
@context = V8::Context.new(with: @doc)
|
650
|
+
@privileged_mode = @options[:privileged_mode]
|
651
|
+
|
652
|
+
@parseInt = V8::Context.new['parseInt']
|
653
|
+
@hooks = {}
|
706
654
|
end
|
707
655
|
|
708
|
-
rescue LoadError
|
709
656
|
#
|
710
|
-
#
|
657
|
+
# Returns true if the engine is set to execute in privileged mode.
|
658
|
+
# Allows execution of security protected methods.
|
711
659
|
#
|
660
|
+
def privileged?
|
661
|
+
@privileged_mode
|
662
|
+
end
|
663
|
+
|
664
|
+
#
|
665
|
+
# Evaluates a JavaScript code in the current context.
|
666
|
+
#
|
667
|
+
def exec(script)
|
668
|
+
@context.eval(script)
|
669
|
+
end
|
670
|
+
|
671
|
+
#
|
672
|
+
# Set a hook on a JavaScript method.
|
673
|
+
#
|
674
|
+
def hook(name, &callback)
|
675
|
+
ns = name.split('.')
|
676
|
+
previous = @context
|
677
|
+
|
678
|
+
ns.each do |n|
|
679
|
+
raise JavaScript::EngineError, "#{name} does not exist" if previous.nil?
|
680
|
+
previous = previous[n]
|
681
|
+
end
|
682
|
+
|
683
|
+
case previous
|
684
|
+
when V8::Function, UnboundMethod, nil
|
685
|
+
@context[name] = lambda do |*args|
|
686
|
+
callback[previous, *args]
|
687
|
+
end
|
688
|
+
|
689
|
+
@hooks[name] = [previous, callback]
|
690
|
+
else
|
691
|
+
raise JavaScript::EngineError, "#{name} is not a function"
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
#
|
696
|
+
# Removes an existing hook on a JavaScript method.
|
697
|
+
#
|
698
|
+
def unhook(name)
|
699
|
+
@context[name] = @hooks[name][0] if @hooks.has_key?(name)
|
700
|
+
end
|
701
|
+
|
702
|
+
#
|
703
|
+
# Returns an Hash of all defined members in specified object name.
|
704
|
+
#
|
705
|
+
def members(obj)
|
706
|
+
members = {}
|
707
|
+
list = @context.eval <<-JS
|
708
|
+
(function(base) {
|
709
|
+
var members = [];
|
710
|
+
for (var i in base) members.push([i, base[i]]);
|
711
|
+
return members;
|
712
|
+
})(#{obj})
|
713
|
+
JS
|
714
|
+
|
715
|
+
list.each do |var|
|
716
|
+
members[var[0]] = var[1]
|
717
|
+
end
|
718
|
+
|
719
|
+
members
|
720
|
+
end
|
721
|
+
|
722
|
+
#
|
723
|
+
# Returns all members in the global scope.
|
724
|
+
#
|
725
|
+
def scope
|
726
|
+
members('this')
|
727
|
+
end
|
728
|
+
|
729
|
+
#
|
730
|
+
# Binds the V8 remote debugging agent on the specified TCP _port_.
|
731
|
+
#
|
732
|
+
def enable_debugger(port = 5858)
|
733
|
+
V8::C::Debug.EnableAgent("Origami", port)
|
734
|
+
end
|
735
|
+
|
736
|
+
def debugger_break
|
737
|
+
exec 'debugger'
|
738
|
+
end
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
module String
|
743
|
+
#
|
744
|
+
# Evaluates the current String as JavaScript.
|
745
|
+
#
|
746
|
+
def eval_js
|
747
|
+
document.eval_js(value)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
class Stream
|
752
|
+
#
|
753
|
+
# Evaluates the current Stream as JavaScript.
|
754
|
+
#
|
755
|
+
def eval_js
|
756
|
+
document.eval_js(data)
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
class PDF
|
761
|
+
#
|
762
|
+
# Executes a JavaScript script in the current document context.
|
763
|
+
#
|
764
|
+
def eval_js(code)
|
765
|
+
js_engine.exec(code)
|
766
|
+
end
|
767
|
+
|
768
|
+
#
|
769
|
+
# Returns the JavaScript engine (if JavaScript support is present).
|
770
|
+
#
|
771
|
+
def js_engine
|
772
|
+
@js_engine ||= PDF::JavaScript::Engine.new(self)
|
773
|
+
end
|
712
774
|
end
|
775
|
+
rescue LoadError
|
776
|
+
#
|
777
|
+
# V8 unavailable.
|
778
|
+
#
|
779
|
+
end
|
713
780
|
end
|