origami 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/COPYING.LESSER +165 -0
  2. data/README +77 -0
  3. data/VERSION +1 -0
  4. data/bin/config/pdfcop.conf.yml +237 -0
  5. data/bin/gui/about.rb +46 -0
  6. data/bin/gui/config.rb +132 -0
  7. data/bin/gui/file.rb +385 -0
  8. data/bin/gui/hexdump.rb +74 -0
  9. data/bin/gui/hexview.rb +91 -0
  10. data/bin/gui/imgview.rb +72 -0
  11. data/bin/gui/menu.rb +392 -0
  12. data/bin/gui/properties.rb +132 -0
  13. data/bin/gui/signing.rb +635 -0
  14. data/bin/gui/textview.rb +107 -0
  15. data/bin/gui/treeview.rb +409 -0
  16. data/bin/gui/walker.rb +282 -0
  17. data/bin/gui/xrefs.rb +79 -0
  18. data/bin/pdf2graph +121 -0
  19. data/bin/pdf2ruby +353 -0
  20. data/bin/pdfcocoon +104 -0
  21. data/bin/pdfcop +455 -0
  22. data/bin/pdfdecompress +104 -0
  23. data/bin/pdfdecrypt +95 -0
  24. data/bin/pdfencrypt +112 -0
  25. data/bin/pdfextract +221 -0
  26. data/bin/pdfmetadata +123 -0
  27. data/bin/pdfsh +13 -0
  28. data/bin/pdfwalker +7 -0
  29. data/bin/shell/.irbrc +104 -0
  30. data/bin/shell/console.rb +136 -0
  31. data/bin/shell/hexdump.rb +83 -0
  32. data/origami.rb +36 -0
  33. data/origami/3d.rb +239 -0
  34. data/origami/acroform.rb +321 -0
  35. data/origami/actions.rb +299 -0
  36. data/origami/adobe/fdf.rb +259 -0
  37. data/origami/adobe/ppklite.rb +489 -0
  38. data/origami/annotations.rb +775 -0
  39. data/origami/array.rb +187 -0
  40. data/origami/boolean.rb +101 -0
  41. data/origami/catalog.rb +486 -0
  42. data/origami/destinations.rb +213 -0
  43. data/origami/dictionary.rb +188 -0
  44. data/origami/docmdp.rb +96 -0
  45. data/origami/encryption.rb +1293 -0
  46. data/origami/export.rb +283 -0
  47. data/origami/file.rb +222 -0
  48. data/origami/filters.rb +250 -0
  49. data/origami/filters/ascii.rb +189 -0
  50. data/origami/filters/ccitt.rb +515 -0
  51. data/origami/filters/crypt.rb +47 -0
  52. data/origami/filters/dct.rb +61 -0
  53. data/origami/filters/flate.rb +112 -0
  54. data/origami/filters/jbig2.rb +63 -0
  55. data/origami/filters/jpx.rb +53 -0
  56. data/origami/filters/lzw.rb +195 -0
  57. data/origami/filters/predictors.rb +276 -0
  58. data/origami/filters/runlength.rb +117 -0
  59. data/origami/font.rb +209 -0
  60. data/origami/functions.rb +93 -0
  61. data/origami/graphics.rb +33 -0
  62. data/origami/graphics/colors.rb +191 -0
  63. data/origami/graphics/instruction.rb +126 -0
  64. data/origami/graphics/path.rb +154 -0
  65. data/origami/graphics/patterns.rb +180 -0
  66. data/origami/graphics/state.rb +164 -0
  67. data/origami/graphics/text.rb +224 -0
  68. data/origami/graphics/xobject.rb +493 -0
  69. data/origami/header.rb +90 -0
  70. data/origami/linearization.rb +318 -0
  71. data/origami/metadata.rb +114 -0
  72. data/origami/name.rb +170 -0
  73. data/origami/null.rb +75 -0
  74. data/origami/numeric.rb +188 -0
  75. data/origami/obfuscation.rb +233 -0
  76. data/origami/object.rb +527 -0
  77. data/origami/outline.rb +59 -0
  78. data/origami/page.rb +559 -0
  79. data/origami/parser.rb +268 -0
  80. data/origami/parsers/fdf.rb +45 -0
  81. data/origami/parsers/pdf.rb +27 -0
  82. data/origami/parsers/pdf/linear.rb +113 -0
  83. data/origami/parsers/ppklite.rb +86 -0
  84. data/origami/pdf.rb +1144 -0
  85. data/origami/reference.rb +113 -0
  86. data/origami/signature.rb +474 -0
  87. data/origami/stream.rb +575 -0
  88. data/origami/string.rb +416 -0
  89. data/origami/trailer.rb +173 -0
  90. data/origami/webcapture.rb +87 -0
  91. data/origami/xfa.rb +3027 -0
  92. data/origami/xreftable.rb +447 -0
  93. data/templates/patterns.rb +66 -0
  94. data/templates/widgets.rb +173 -0
  95. data/templates/xdp.rb +92 -0
  96. data/tests/dataset/test.dummycrt +28 -0
  97. data/tests/dataset/test.dummykey +27 -0
  98. data/tests/tc_actions.rb +32 -0
  99. data/tests/tc_annotations.rb +85 -0
  100. data/tests/tc_pages.rb +37 -0
  101. data/tests/tc_pdfattach.rb +24 -0
  102. data/tests/tc_pdfencrypt.rb +110 -0
  103. data/tests/tc_pdfnew.rb +32 -0
  104. data/tests/tc_pdfparse.rb +98 -0
  105. data/tests/tc_pdfsig.rb +37 -0
  106. data/tests/tc_streams.rb +129 -0
  107. data/tests/ts_pdf.rb +45 -0
  108. metadata +193 -0
@@ -0,0 +1,187 @@
1
+ =begin
2
+
3
+ = File
4
+ array.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume DelugrÈ <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+
27
+ module Origami
28
+
29
+ class InvalidArrayObjectError < InvalidObjectError #:nodoc:
30
+ end
31
+
32
+ #
33
+ # Class representing an Array Object.
34
+ # Arrays contain a set of Object.
35
+ #
36
+ class Array < ::Array
37
+ include Origami::Object
38
+
39
+ TOKENS = %w{ [ ] } #:nodoc:
40
+ @@regexp_open = Regexp.new(WHITESPACES + Regexp.escape(TOKENS.first) + WHITESPACES)
41
+ @@regexp_close = Regexp.new(WHITESPACES + Regexp.escape(TOKENS.last) + WHITESPACES)
42
+
43
+ attr_reader :strings_cache, :names_cache, :xref_cache
44
+
45
+ #
46
+ # Creates a new PDF Array Object.
47
+ # _data_:: An array of objects.
48
+ #
49
+ def initialize(data = [])
50
+ raise TypeError, "Expected type Array, received #{data.class}." unless data.is_a?(::Array)
51
+ super()
52
+
53
+ @strings_cache = []
54
+ @names_cache = []
55
+ @xref_cache = {}
56
+
57
+ i = 0
58
+ while i < data.size
59
+ case val = data[i].to_o
60
+ when String then @strings_cache.push(val)
61
+ when Name then @names_cache.push(val)
62
+ when Reference then
63
+ (@xref_cache[val] ||= []).push(self)
64
+ when Dictionary,Array then
65
+ @strings_cache.concat(val.strings_cache)
66
+ @names_cache.concat(val.names_cache)
67
+ @xref_cache.update(val.xref_cache) do |ref, cache1, cache2|
68
+ cache1.concat(cache2)
69
+ end
70
+
71
+ val.strings_cache.clear
72
+ val.names_cache.clear
73
+ val.xref_cache.clear
74
+ end
75
+
76
+ self[i] = val
77
+ i = i + 1
78
+ end
79
+
80
+ end
81
+
82
+ def pre_build
83
+ self.map!{|obj| obj.to_o}
84
+
85
+ super
86
+ end
87
+
88
+ def self.parse(stream) #:nodoc:
89
+ data = []
90
+ offset = stream.pos
91
+
92
+ if not stream.skip(@@regexp_open)
93
+ raise InvalidArrayObjectError, "No token '#{TOKENS.first}' found"
94
+ end
95
+
96
+ while stream.skip(@@regexp_close).nil? do
97
+
98
+ type = Object.typeof(stream)
99
+ if type.nil?
100
+ raise InvalidArrayObjectError, "Bad embedded object format"
101
+ end
102
+
103
+ value = type.parse(stream)
104
+ data << value
105
+ end
106
+
107
+ array = Array.new(data)
108
+ array.file_offset = offset
109
+
110
+ array
111
+ end
112
+
113
+ #
114
+ # Converts self into a Ruby array.
115
+ #
116
+ def to_a
117
+ super.map { |item|
118
+ item.is_a?(Origami::Object) ? item.value : item
119
+ }
120
+ end
121
+
122
+ def to_s #:nodoc:
123
+ content = "#{TOKENS.first} "
124
+ self.each { |entry|
125
+ content << entry.to_o.to_s + ' '
126
+ }
127
+ content << TOKENS.last
128
+
129
+ super(content)
130
+ end
131
+
132
+ def +(other)
133
+
134
+ a = Origami::Array.new(self.to_a + other.to_a, is_indirect?)
135
+ a.no, a.generation = @no, @generation
136
+
137
+ return a
138
+ end
139
+
140
+ def <<(item)
141
+ obj = item.to_o
142
+ obj.parent = self unless obj.is_indirect?
143
+
144
+ super(obj)
145
+ end
146
+
147
+ def []=(key,val)
148
+ key, val = key.to_o, val.to_o
149
+ super(key.to_o,val.to_o)
150
+
151
+ val.parent = self unless val.is_indirect? or val.parent.equal?(self)
152
+
153
+ val
154
+ end
155
+
156
+ alias value to_a
157
+
158
+ def real_type ; Origami::Array end
159
+
160
+ end
161
+
162
+ #
163
+ # Class representing a location on a page or a bounding box.
164
+ #
165
+ class Rectangle < Array
166
+
167
+ class << self
168
+
169
+ def [](coords)
170
+ corners = coords.values_at(:llx, :lly, :urx, :ury)
171
+
172
+ unless corners.all? { |corner| corner.is_a?(Numeric) }
173
+ raise TypeError, "All coords must be numbers"
174
+ end
175
+
176
+ Rectangle.new(*corners)
177
+ end
178
+
179
+ end
180
+
181
+ def initialize(lowerleftx, lowerlefty, upperrightx, upperrighty)
182
+ super([ lowerleftx, lowerlefty, upperrightx, upperrighty ])
183
+ end
184
+
185
+ end
186
+
187
+ end
@@ -0,0 +1,101 @@
1
+ =begin
2
+
3
+ = File
4
+ boolean.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume DelugrÈ <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ class InvalidBooleanObjectError < InvalidObjectError #:nodoc:
29
+ end
30
+
31
+ #
32
+ # Class representing a Boolean Object.
33
+ # A Boolean Object can be *true* or *false*.
34
+ #
35
+ class Boolean
36
+
37
+ include Origami::Object
38
+
39
+ TOKENS = [ %w{ true false } ] #:nodoc:
40
+
41
+ @@regexp = Regexp.new(WHITESPACES + "(#{TOKENS.first.join('|')})")
42
+
43
+ #
44
+ # Creates a new Boolean value.
45
+ # _value_:: *true* or *false*.
46
+ #
47
+ def initialize(value)
48
+
49
+ unless value.is_a?(TrueClass) or value.is_a?(FalseClass)
50
+ raise TypeError, "Expected type TrueClass or FalseClass, received #{value.class}."
51
+ end
52
+
53
+ super()
54
+
55
+ @value = (value == nil || value == false) ? false : true
56
+ end
57
+
58
+ def to_s #:nodoc:
59
+ super(@value.to_s)
60
+ end
61
+
62
+ def self.parse(stream) #:nodoc:
63
+
64
+ offset = stream.pos
65
+
66
+ if stream.scan(@@regexp).nil?
67
+ raise InvalidBooleanObjectError
68
+ end
69
+
70
+ value = stream[2] == "true" ? true : false
71
+
72
+ bool = Boolean.new(value)
73
+ bool.file_offset = offset
74
+
75
+ bool
76
+ end
77
+
78
+ #
79
+ # Converts self into a Ruby boolean, that is TrueClass or FalseClass instance.
80
+ #
81
+ def value
82
+ @value
83
+ end
84
+
85
+ def real_type ; Boolean end
86
+
87
+ def false?
88
+ @value == false
89
+ end
90
+
91
+ def true?
92
+ @value == true
93
+ end
94
+
95
+ def ==(bool)
96
+ @value == bool
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,486 @@
1
+ =begin
2
+
3
+ = File
4
+ catalog.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ class PDF
29
+
30
+ #
31
+ # Sets PDF extension level and version. Only supported values are "1.7" and 3.
32
+ #
33
+ def set_extension_level(version, level)
34
+ exts = (self.Catalog.Extensions ||= Extensions.new)
35
+
36
+ exts[:ADBE] = DeveloperExtension.new
37
+ exts[:ADBE].BaseVersion = Name.new(version)
38
+ exts[:ADBE].ExtensionLevel = level
39
+
40
+ self
41
+ end
42
+
43
+ #
44
+ # Returns the current Catalog Dictionary.
45
+ #
46
+ def Catalog
47
+ cat = get_doc_attr(:Root)
48
+
49
+ case cat
50
+ when Catalog then
51
+ cat
52
+ when Dictionary then
53
+ casted = Catalog.new(cat)
54
+ casted.no, casted.generation = cat.no, cat.generation
55
+ casted.set_indirect(true)
56
+ casted.set_pdf(self)
57
+
58
+ casted
59
+ else
60
+ raise InvalidPDFError, "Broken catalog"
61
+ end
62
+ end
63
+
64
+ #
65
+ # Sets the current Catalog Dictionary.
66
+ #
67
+ def Catalog=(cat)
68
+ #unless cat.is_a?(Catalog)
69
+ # raise TypeError, "Expected type Catalog, received #{cat.class}"
70
+ #end
71
+ cat = Catalog.new(cat) unless cat.is_a? Catalog
72
+
73
+ if @revisions.last.trailer.Root
74
+ delete_object(@revisions.last.trailer[:Root])
75
+ end
76
+
77
+ @revisions.last.trailer.Root = self << cat
78
+ end
79
+
80
+ #
81
+ # Sets an action to run on document opening.
82
+ # _action_:: An Action Object.
83
+ #
84
+ def onDocumentOpen(action)
85
+
86
+ unless action.is_a?(Action) or action.is_a?(Destination) or action.is_a?(Reference)
87
+ raise TypeError, "An Action object must be passed."
88
+ end
89
+
90
+ unless self.Catalog
91
+ raise InvalidPDFError, "A catalog object must exist to add this action."
92
+ end
93
+
94
+ self.Catalog.OpenAction = action
95
+
96
+ self
97
+ end
98
+
99
+ #
100
+ # Sets an action to run on document closing.
101
+ # _action_:: A JavaScript Action Object.
102
+ #
103
+ def onDocumentClose(action)
104
+
105
+ unless action.is_a?(Action::JavaScript) or action.is_a?(Reference)
106
+ raise TypeError, "An Action::JavaScript object must be passed."
107
+ end
108
+
109
+ unless self.Catalog
110
+ raise InvalidPDFError, "A catalog object must exist to add this action."
111
+ end
112
+
113
+ self.Catalog.AA ||= CatalogAdditionalActions.new
114
+ self.Catalog.AA.WC = action
115
+
116
+ self
117
+ end
118
+
119
+ #
120
+ # Sets an action to run on document printing.
121
+ # _action_:: A JavaScript Action Object.
122
+ #
123
+ def onDocumentPrint(action)
124
+
125
+ unless action.is_a?(Action::JavaScript) or action.is_a?(Reference)
126
+ raise TypeError, "An Action::JavaScript object must be passed."
127
+ end
128
+
129
+ unless self.Catalog
130
+ raise InvalidPDFError, "A catalog object must exist to add this action."
131
+ end
132
+
133
+ self.Catalog.AA ||= CatalogAdditionalActions.new
134
+ self.Catalog.AA.WP = action
135
+
136
+ end
137
+
138
+ #
139
+ # Registers an object into a specific Names root dictionary.
140
+ # _root_:: The root dictionary (see Names::Root)
141
+ # _name_:: The value name.
142
+ # _value_:: The value to associate with this name.
143
+ #
144
+ def register(root, name, value)
145
+ self.Catalog.Names ||= Names.new
146
+
147
+ value.set_indirect(true) unless value.is_a? Reference
148
+
149
+ namesroot = self.Catalog.Names[root]
150
+ if namesroot.nil?
151
+ names = NameTreeNode.new(:Names => []).set_indirect(true)
152
+ self.Catalog.Names[root] = names
153
+ names.Names << name << value
154
+ else
155
+ namesroot.solve[:Names] << name << value
156
+ end
157
+ end
158
+
159
+ def each_name(root, &b)
160
+ namesroot = get_names_root(root)
161
+ return if namesroot.nil?
162
+
163
+ each_name_from_node(namesroot, [], &b)
164
+ self
165
+ end
166
+
167
+ #
168
+ # Retrieve the corresponding value associated with _name_ in
169
+ # the specified _root_ name directory, or nil if the value does
170
+ # not exist.
171
+ #
172
+ def resolve_name(root, name)
173
+ namesroot = get_names_root(root)
174
+ return nil if namesroot.nil?
175
+
176
+ resolve_name_from_node(namesroot, name)
177
+ end
178
+
179
+ #
180
+ # Returns a Hash of all names under specified _root_ name directory.
181
+ # Returns nil if the directory does not exist.
182
+ #
183
+ def ls_names(root)
184
+ namesroot = get_names_root(root)
185
+ return {} if namesroot.nil?
186
+
187
+ names = names_from_node(namesroot)
188
+ if names.length % 2 != 0
189
+ return InvalidNameTreeError, "Odd number of elements"
190
+ end
191
+
192
+ Hash[*names]
193
+ end
194
+
195
+ private
196
+
197
+ def names_from_node(node, browsed_nodes = []) #:nodoc:
198
+ children = []
199
+
200
+ unless browsed_nodes.any? {|browsed| browsed.equal?(node)}
201
+ browsed_nodes.push(node)
202
+ if node.has_key?(:Names) # leaf node
203
+ children.concat(node[:Names].solve)
204
+ elsif node.has_key?(:Kids) # intermediate node
205
+ node[:Kids].solve.each do |kid|
206
+ children.concat(names_from_node(kid.solve, browsed_nodes))
207
+ end
208
+ end
209
+ end
210
+
211
+ children
212
+ end
213
+
214
+ def resolve_name_from_node(node, name, browsed_nodes = []) #:nodoc:
215
+ unless browsed_nodes.any? {|browsed| browsed.equal?(node)}
216
+ browsed_nodes.push(node)
217
+
218
+ if node.has_key?(:Names) # leaf node
219
+ limits = node[:Limits]
220
+
221
+ if limits
222
+ limits = limits.solve
223
+ min, max = limits[0].value, limits[1].value
224
+ if (min..max) === name.to_str
225
+ names = Hash[*node[:Names].solve]
226
+ target = names[name]
227
+ return target && target.solve
228
+ end
229
+ else
230
+ names = Hash[*node[:Names].solve]
231
+ target = names[name]
232
+ return target && target.solve
233
+ end
234
+
235
+ elsif node.has_key?(:Kids) # intermediate node
236
+ node[:Kids].solve.each do |kid|
237
+ kid = kid.solve
238
+ limits = kid[:Limits].solve
239
+ min, max = limits[0].value, limits[1].value
240
+
241
+ if (min..max) === name.to_str
242
+ return resolve_name_from_node(kid, name, browsed_nodes)
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ def each_name_from_node(node, browsed_nodes = [], &b) #:nodoc:
250
+ if node.has_key?(:Names) # leaf node
251
+ names = Hash[*node[:Names].solve]
252
+ names.each_pair do |name, value|
253
+ b.call(name, value.solve)
254
+ end
255
+ elsif node.has_key?(:Kids) # intermediate node
256
+ node[:Kids].solve.each do |kid|
257
+ each_name_from_node(kid.solve, browsed_nodes, &b)
258
+ end
259
+ end
260
+ end
261
+
262
+ def get_names_root(root) #:nodoc:
263
+ namedirs = self.Catalog.Names
264
+ return nil if namedirs.nil? or namedirs[root].nil?
265
+
266
+ namedirs[root].solve
267
+ end
268
+ end
269
+
270
+ module PageLayout #:nodoc:
271
+ SINGLE = :SinglePage
272
+ ONE_COLUMN = :OneColumn
273
+ TWO_COLUMN_LEFT = :TwoColumnLeft
274
+ TWO_COLUMN_RIGHT = :TwoColumnRight
275
+ TWO_PAGE_LEFT = :TwoPageLeft
276
+ TWO_PAGE_RIGHT = :TwoPageRight
277
+ end
278
+
279
+ module PageMode #:nodoc:
280
+ NONE = :UseNone
281
+ OUTLINES = :UseOutlines
282
+ THUMBS = :UseThumbs
283
+ FULLSCREEN = :FullScreen
284
+ OPTIONAL_CONTENT = :UseOC
285
+ ATTACHMENTS = :UseAttachments
286
+ end
287
+
288
+ #
289
+ # Class representing the Catalog Dictionary of a PDF file.
290
+ #
291
+ class Catalog < Dictionary
292
+
293
+ include StandardObject
294
+
295
+ field :Type, :Type => Name, :Default => :Catalog, :Required => true
296
+ field :Version, :Type => Name, :Version => "1.4"
297
+ field :Pages, :Type => Dictionary, :Required => true
298
+ field :PageLabels, :Type => Dictionary, :Version => "1.3"
299
+ field :Names, :Type => Dictionary, :Version => "1.2"
300
+ field :Dests, :Type => Dictionary, :Version => "1.1"
301
+ field :ViewerPreferences, :Type => Dictionary, :Version => "1.2"
302
+ field :PageLayout, :Type => Name, :Default => PageLayout::SINGLE
303
+ field :PageMode, :Type => Name, :Default => PageMode::NONE
304
+ field :Outlines, :Type => Dictionary
305
+ field :Threads, :Type => Array, :Version => "1.1"
306
+ field :OpenAction, :Type => [ Array, Dictionary ], :Version => "1.1"
307
+ field :AA, :Type => Dictionary, :Version => "1.4"
308
+ field :URI, :Type => Dictionary, :Version => "1.1"
309
+ field :AcroForm, :Type => Dictionary, :Version => "1.2"
310
+ field :Metadata, :Type => Stream, :Version => "1.4"
311
+ field :StructTreeRoot, :Type => Dictionary, :Version => "1.3"
312
+ field :MarkInfo, :Type => Dictionary, :Version => "1.4"
313
+ field :Lang, :Type => String, :Version => "1.4"
314
+ field :SpiderInfo, :Type => Dictionary, :Version => "1.3"
315
+ field :OutputIntents, :Type => Array, :Version => "1.4"
316
+ field :PieceInfo, :Type => Dictionary, :Version => "1.4"
317
+ field :OCProperties, :Type => Dictionary, :Version => "1.5"
318
+ field :Perms, :Type => Dictionary, :Version => "1.5"
319
+ field :Legal, :Type => Dictionary, :Version => "1.5"
320
+ field :Requirements, :Type => Array, :Version => "1.7"
321
+ field :Collection, :Type => Dictionary, :Version => "1.7"
322
+ field :NeedsRendering, :Type => Boolean, :Version => "1.7", :Default => false
323
+ field :Extensions, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
324
+
325
+ def initialize(hash = {})
326
+ set_indirect(true)
327
+
328
+ super(hash)
329
+ end
330
+
331
+ end
332
+
333
+ #
334
+ # Class representing additional actions which can be associated with a Catalog.
335
+ #
336
+ class CatalogAdditionalActions < Dictionary
337
+ include StandardObject
338
+
339
+ field :WC, :Type => Dictionary, :Version => "1.4"
340
+ field :WS, :Type => Dictionary, :Version => "1.4"
341
+ field :DS, :Type => Dictionary, :Version => "1.4"
342
+ field :WP, :Type => Dictionary, :Version => "1.4"
343
+ field :DP, :Type => Dictionary, :Version => "1.4"
344
+ end
345
+
346
+ class InvalidNameTreeError < Exception #:nodoc:
347
+ end
348
+
349
+ #
350
+ # Class representing the Names Dictionary of a PDF file.
351
+ #
352
+ class Names < Dictionary
353
+ include StandardObject
354
+
355
+ #
356
+ # Defines constants for Names tree root entries.
357
+ #
358
+ module Root
359
+ DESTS = :Dests
360
+ AP = :AP
361
+ JAVASCRIPT = :JavaScript
362
+ PAGES = :Pages
363
+ TEMPLATES = :Templates
364
+ IDS = :IDS
365
+ URLS = :URLS
366
+ EMBEDDEDFILES = :EmbeddedFiles
367
+ ALTERNATEPRESENTATIONS = :AlternatePresentations
368
+ RENDITIONS = :Renditions
369
+ XFARESOURCES = :XFAResources
370
+ end
371
+
372
+ field Root::DESTS, :Type => Dictionary, :Version => "1.2"
373
+ field Root::AP, :Type => Dictionary, :Version => "1.3"
374
+ field Root::JAVASCRIPT, :Type => Dictionary, :Version => "1.3"
375
+ field Root::PAGES, :Type => Dictionary, :Version => "1.3"
376
+ field Root::TEMPLATES, :Type => Dictionary, :Version => "1.3"
377
+ field Root::IDS, :Type => Dictionary, :Version => "1.3"
378
+ field Root::URLS, :Type => Dictionary, :Version => "1.3"
379
+ field Root::EMBEDDEDFILES, :Type => Dictionary, :Version => "1.4"
380
+ field Root::ALTERNATEPRESENTATIONS, :Type => Dictionary, :Version => "1.4"
381
+ field Root::RENDITIONS, :Type => Dictionary, :Version => "1.5"
382
+ field Root::XFARESOURCES, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
383
+ end
384
+
385
+ #
386
+ # Class representing a node in a Name tree.
387
+ #
388
+ class NameTreeNode < Dictionary
389
+ include StandardObject
390
+
391
+ field :Kids, :Type => Array
392
+ field :Names, :Type => Array
393
+ field :Limits, :Type => Array
394
+ end
395
+
396
+ #
397
+ # Class representing a leaf in a Name tree.
398
+ #
399
+ class NameLeaf < Origami::Array
400
+
401
+ #
402
+ # Creates a new leaf in a Name tree.
403
+ # _hash_:: A hash of couples, associating a Name with an Reference.
404
+ #
405
+ def initialize(hash = {})
406
+
407
+ names = []
408
+ hash.each_pair do |k,v|
409
+ names << k.to_o << v.to_o
410
+ end
411
+
412
+ super(names)
413
+ end
414
+ end
415
+
416
+ #
417
+ # Class representing the ViewerPreferences Dictionary of a PDF.
418
+ # This dictionary modifies the way the UI looks when the file is opened in a viewer.
419
+ #
420
+ class ViewerPreferences < Dictionary
421
+ include StandardObject
422
+
423
+ field :HideToolbar, :Type => Boolean, :Default => false
424
+ field :HideMenubar, :Type => Boolean, :Default => false
425
+ field :HideWindowUI, :Type => Boolean, :Default => false
426
+ field :FitWindow, :Type => Boolean, :Default => false
427
+ field :CenterWindow, :Type => Boolean, :Default => false
428
+ field :DisplayDocTitle, :Type => Boolean, :Default => false, :Version => "1.4"
429
+ field :NonFullScreenPageMode, :Type => Name, :Default => :UseNone
430
+ field :Direction, :Type => Name, :Default => :L2R
431
+ field :ViewArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
432
+ field :ViewClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
433
+ field :PrintArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
434
+ field :PrintClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
435
+ field :PrintScaling, :Type => Name, :Default => :AppDefault, :Version => "1.6"
436
+ field :Duplex, :Type => Name, :Default => :Simplex, :Version => "1.7"
437
+ field :PickTrayByPDFSize, :Type => Boolean, :Version => "1.7"
438
+ field :PrintPageRange, :Type => Array, :Version => "1.7"
439
+ field :NumCopies, :Type => Integer, :Version => "1.7"
440
+ field :Enforce, :Type => Array, :Version => "1.7", :ExtensionLevel => 3
441
+
442
+ end
443
+
444
+ class Requirement < Dictionary
445
+ include StandardObject
446
+
447
+ class Handler < Dictionary
448
+ include StandardObject
449
+
450
+ module Type
451
+ JS = :JS
452
+ NOOP = :NoOp
453
+ end
454
+
455
+ field :Type, :Type => Name, :Default => :ReqHandler
456
+ field :S, :Type => Name, :Default => Type::NOOP, :Required => true
457
+ field :Script, :Type => ByteString
458
+ end
459
+
460
+ field :Type, :Type => Name, :Default => :Requirement
461
+ field :S, :Type => Name, :Default => :EnableJavaScripts, :Version => "1.7", :Required => true
462
+ field :RH, :Type => Array
463
+ end
464
+
465
+ #
466
+ # Class representing an extension Dictionary.
467
+ #
468
+ class Extensions < Dictionary
469
+ include StandardObject
470
+
471
+ field :Type, :Type => Name, :Default => :Extensions
472
+ end
473
+
474
+ #
475
+ # Class representing a developer extension.
476
+ #
477
+ class DeveloperExtension < Dictionary
478
+ include StandardObject
479
+
480
+ field :Type, :Type => Name, :Default => :DeveloperExtensions
481
+ field :BaseVersion, :Type => Name, :Required => true
482
+ field :ExtensionLevel, :Type => Integer, :Required => true
483
+
484
+ end
485
+
486
+ end