origami 1.0.2

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 (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