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