origami 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,101 +1,91 @@
1
1
  =begin
2
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 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
- 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
-
23
+ class InvalidBooleanObjectError < InvalidObjectError #:nodoc:
24
+ end
25
+
43
26
  #
44
- # Creates a new Boolean value.
45
- # _value_:: *true* or *false*.
27
+ # Class representing a Boolean Object.
28
+ # A Boolean Object can be *true* or *false*.
46
29
  #
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, parser = nil) #:nodoc:
30
+ class Boolean
31
+ include Origami::Object
63
32
 
64
- offset = stream.pos
65
-
66
- if stream.scan(@@regexp).nil?
67
- raise InvalidBooleanObjectError
68
- end
33
+ TOKENS = %w{ true false } #:nodoc:
34
+ @@regexp = Regexp.new(WHITESPACES + "(?<value>#{Regexp.union(TOKENS)})")
69
35
 
70
- value = stream[2] == "true" ? true : false
71
-
72
- bool = Boolean.new(value)
73
- bool.file_offset = offset
36
+ #
37
+ # Creates a new Boolean value.
38
+ # _value_:: *true* or *false*.
39
+ #
40
+ def initialize(value)
41
+ unless value.is_a?(TrueClass) or value.is_a?(FalseClass)
42
+ raise TypeError, "Expected type TrueClass or FalseClass, received #{value.class}."
43
+ end
74
44
 
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
45
+ super()
84
46
 
85
- def self.native_type ; Boolean end
86
-
87
- def false?
88
- @value == false
89
- end
90
-
91
- def true?
92
- @value == true
93
- end
47
+ @value = (value == true)
48
+ end
94
49
 
95
- def ==(bool)
96
- @value == bool
97
- end
50
+ def to_s #:nodoc:
51
+ super(@value.to_s)
52
+ end
53
+
54
+ def self.parse(stream, parser = nil) #:nodoc:
55
+ offset = stream.pos
56
+
57
+ if stream.scan(@@regexp).nil?
58
+ raise InvalidBooleanObjectError
59
+ end
60
+
61
+ value = (stream['value'] == "true")
62
+
63
+ bool = Boolean.new(value)
64
+ bool.file_offset = offset
98
65
 
99
- end
66
+ bool
67
+ end
68
+
69
+ #
70
+ # Converts self into a Ruby boolean, that is TrueClass or FalseClass instance.
71
+ #
72
+ def value
73
+ @value
74
+ end
75
+
76
+ def self.native_type ; Boolean end
77
+
78
+ def false?
79
+ @value == false
80
+ end
81
+
82
+ def true?
83
+ @value == true
84
+ end
85
+
86
+ def ==(bool)
87
+ @value == bool
88
+ end
89
+ end
100
90
 
101
91
  end
@@ -1,485 +1,448 @@
1
1
  =begin
2
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 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
- class PDF
23
+ class PDF
24
+ #
25
+ # Sets PDF extension level and version. Only supported values are "1.7" and 3.
26
+ #
27
+ def set_extension_level(version, level)
28
+ exts = (self.Catalog.Extensions ||= Extensions.new)
29
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)
30
+ exts[:ADBE] = DeveloperExtension.new
31
+ exts[:ADBE].BaseVersion = Name.new(version)
32
+ exts[:ADBE].ExtensionLevel = level
35
33
 
36
- exts[:ADBE] = DeveloperExtension.new
37
- exts[:ADBE].BaseVersion = Name.new(version)
38
- exts[:ADBE].ExtensionLevel = level
34
+ self
35
+ end
39
36
 
40
- self
41
- end
37
+ #
38
+ # Returns the current Catalog Dictionary.
39
+ #
40
+ def Catalog
41
+ cat = trailer_key(:Root)
42
+
43
+ case cat
44
+ when Catalog then
45
+ cat
46
+ when Dictionary then
47
+ cat.cast_to(Catalog)
48
+ else
49
+ raise InvalidPDFError, "Broken catalog"
50
+ end
51
+ end
42
52
 
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
53
+ #
54
+ # Sets the current Catalog Dictionary.
55
+ #
56
+ def Catalog=(cat)
57
+ cat = cat.cast_to(Catalog) unless cat.is_a? Catalog
58
+
59
+ delete_object(@revisions.last.trailer[:Root]) if @revisions.last.trailer[:Root]
60
+
61
+ @revisions.last.trailer.Root = self << cat
62
+ end
63
+
64
+ #
65
+ # Sets an action to run on document opening.
66
+ # _action_:: An Action Object.
67
+ #
68
+ def onDocumentOpen(action)
69
+ unless action.is_a?(Action) or action.is_a?(Destination) or action.is_a?(Reference)
70
+ raise TypeError, "An Action object must be passed."
71
+ end
72
+
73
+ unless self.Catalog
74
+ raise InvalidPDFError, "A catalog object must exist to add this action."
75
+ end
76
+
77
+ self.Catalog.OpenAction = action
78
+
79
+ self
80
+ end
81
+
82
+ #
83
+ # Sets an action to run on document closing.
84
+ # _action_:: A JavaScript Action Object.
85
+ #
86
+ def onDocumentClose(action)
87
+ unless action.is_a?(Action::JavaScript) or action.is_a?(Reference)
88
+ raise TypeError, "An Action::JavaScript object must be passed."
89
+ end
90
+
91
+ unless self.Catalog
92
+ raise InvalidPDFError, "A catalog object must exist to add this action."
93
+ end
94
+
95
+ self.Catalog.AA ||= CatalogAdditionalActions.new
96
+ self.Catalog.AA.WC = action
97
+
98
+ self
99
+ end
100
+
101
+ #
102
+ # Sets an action to run on document printing.
103
+ # _action_:: A JavaScript Action Object.
104
+ #
105
+ def onDocumentPrint(action)
106
+ unless action.is_a?(Action::JavaScript) or action.is_a?(Reference)
107
+ raise TypeError, "An Action::JavaScript object must be passed."
108
+ end
109
+
110
+ unless self.Catalog
111
+ raise InvalidPDFError, "A catalog object must exist to add this action."
112
+ end
113
+
114
+ self.Catalog.AA ||= CatalogAdditionalActions.new
115
+ self.Catalog.AA.WP = action
116
+
117
+ self
118
+ end
119
+
120
+ #
121
+ # Registers an object into a specific Names root dictionary.
122
+ # _root_:: The root dictionary (see Names::Root)
123
+ # _name_:: The value name.
124
+ # _value_:: The value to associate with this name.
125
+ #
126
+ def register(root, name, value)
127
+ self.Catalog.Names ||= Names.new
128
+
129
+ value.set_indirect(true) unless value.is_a?(Reference)
130
+
131
+ namesroot = self.Catalog.Names[root]
132
+ if namesroot.nil?
133
+ names = NameTreeNode.new(:Names => []).set_indirect(true)
134
+ self.Catalog.Names[root] = names
135
+ names.Names << name << value
136
+ else
137
+ namesroot.solve[:Names] << name << value
138
+ end
139
+ end
140
+
141
+ #
142
+ # Retrieve the corresponding value associated with _name_ in
143
+ # the specified _root_ name directory, or nil if the value does
144
+ # not exist.
145
+ #
146
+ def resolve_name(root, name)
147
+ namesroot = get_names_root(root)
148
+ return nil if namesroot.nil?
149
+
150
+ resolve_name_from_node(namesroot, name)
151
+ end
152
+
153
+ #
154
+ # Returns a Hash of all names under the specified _root_ name directory.
155
+ #
156
+ def names(root)
157
+ self.each_name(root).to_h
158
+ end
159
+
160
+ #
161
+ # Returns an Enumerator of all names under the specified _root_ name directory.
162
+ #
163
+ def each_name(root, &block)
164
+ return enum_for(__method__, root) unless block_given?
165
+
166
+ names_root = get_names_root(root)
167
+ return if names_root.nil?
168
+
169
+ names_from_node(names_root, &block)
170
+ self
171
+ end
172
+
173
+ private
174
+
175
+ def names_from_node(node, browsed_nodes: [], &block) #:nodoc:
176
+ return if browsed_nodes.any?{|browsed| browsed.equal?(node)}
177
+ raise InvalidNameTreeError, "node is not a dictionary" unless node.is_a?(Dictionary)
178
+
179
+ browsed_nodes.push(node)
180
+
181
+ if node.has_key?(:Names) # leaf node
182
+ names = node.Names
183
+ raise InvalidNameTreeError, "Names must be an Array" unless names.is_a?(Array)
184
+ raise InvalidNameTreeError, "Odd number of elements" if names.length.odd?
185
+
186
+ for i in 0...names.length/2
187
+ yield(names[i * 2].solve, names[i * 2 + 1].solve)
188
+ end
189
+
190
+ elsif node.has_key?(:Kids) # intermediate node
191
+ node.Kids.each do |kid|
192
+ names_from_node(kid.solve, browsed_nodes: browsed_nodes, &block)
193
+ end
194
+ end
195
+ end
196
+
197
+ def resolve_name_from_node(node, name, browsed_nodes: []) #:nodoc:
198
+ return if browsed_nodes.any?{|browsed| browsed.equal?(node)}
199
+ raise InvalidNameTreeError, "node is not a Dictionary" unless node.is_a?(Dictionary)
200
+
201
+ browsed_nodes.push(node)
202
+
203
+ if node.has_key?(:Names) # leaf node
204
+ limits = node.Limits
205
+ names = node.Names
206
+
207
+ raise InvalidNameTreeError, "Names must be an Array" unless names.is_a?(Array)
208
+ raise InvalidNameTreeError, "Odd number of elements" if names.length.odd?
209
+
210
+ if limits.is_a?(Array)
211
+ raise InvalidNameTreeError, "Invalid Limits array" unless limits.length == 2
212
+
213
+ min, max = limits[0].value, limits[1].value
214
+ if name.to_str >= min and name.to_str <= max
215
+ names = Hash[*names]
216
+ target = names[name]
217
+ return target && target.solve
218
+ end
219
+ else
220
+ names = Hash[*names]
221
+ target = names[name]
222
+ return target && target.solve
223
+ end
224
+
225
+ elsif node.has_key?(:Kids) # intermediate node
226
+ raise InvalidNameTreeError, "Kids must be an Array" unless node.Kids.is_a?(Array)
227
+
228
+ node.Kids.each do |kid|
229
+ kid = kid.solve
230
+ limits = kid.Limits
231
+ unless limits.is_a?(Array) and limits.length == 2
232
+ raise InvalidNameTreeError, "Invalid Limits array"
233
+ end
234
+
235
+ min, max = limits[0].value, limits[1].value
236
+
237
+ if name.to_str >= min and name.to_str <= max
238
+ return resolve_name_from_node(kid, name, browsed_nodes: browsed_nodes)
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ def get_names_root(root) #:nodoc:
245
+ namedirs = self.Catalog.Names
246
+ return nil if namedirs.nil? or namedirs[root].nil?
247
+
248
+ namedirs[root].solve
249
+ end
78
250
  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
251
+
252
+ module PageLayout #:nodoc:
253
+ SINGLE = :SinglePage
254
+ ONE_COLUMN = :OneColumn
255
+ TWO_COLUMN_LEFT = :TwoColumnLeft
256
+ TWO_COLUMN_RIGHT = :TwoColumnRight
257
+ TWO_PAGE_LEFT = :TwoPageLeft
258
+ TWO_PAGE_RIGHT = :TwoPageRight
97
259
  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
260
+
261
+ module PageMode #:nodoc:
262
+ NONE = :UseNone
263
+ OUTLINES = :UseOutlines
264
+ THUMBS = :UseThumbs
265
+ FULLSCREEN = :FullScreen
266
+ OPTIONAL_CONTENT = :UseOC
267
+ ATTACHMENTS = :UseAttachments
117
268
  end
118
-
269
+
119
270
  #
120
- # Sets an action to run on document printing.
121
- # _action_:: A JavaScript Action Object.
271
+ # Class representing additional actions which can be associated with a Catalog.
122
272
  #
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
-
273
+ class CatalogAdditionalActions < Dictionary
274
+ include StandardObject
275
+
276
+ field :WC, :Type => Action, :Version => "1.4"
277
+ field :WS, :Type => Action, :Version => "1.4"
278
+ field :DS, :Type => Action, :Version => "1.4"
279
+ field :WP, :Type => Action, :Version => "1.4"
280
+ field :DP, :Type => Action, :Version => "1.4"
136
281
  end
137
282
 
138
283
  #
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.
284
+ # Class representing the Names Dictionary of a PDF file.
143
285
  #
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
286
+ class Names < Dictionary
287
+ include StandardObject
288
+
289
+ #
290
+ # Defines constants for Names tree root entries.
291
+ #
292
+ DESTINATIONS = :Dests
293
+ AP = :AP
294
+ JAVASCRIPT = :JavaScript
295
+ PAGES = :Pages
296
+ TEMPLATES = :Templates
297
+ IDS = :IDS
298
+ URLS = :URLS
299
+ EMBEDDED_FILES = :EmbeddedFiles
300
+ ALTERNATE_PRESENTATIONS = :AlternatePresentations
301
+ RENDITIONS = :Renditions
302
+ XFA_RESOURCES = :XFAResources
303
+
304
+ field DESTINATIONS, :Type => NameTreeNode.of([DestinationDictionary, Destination]), :Version => "1.2"
305
+ field AP, :Type => NameTreeNode.of(Annotation::AppearanceStream), :Version => "1.3"
306
+ field JAVASCRIPT, :Type => NameTreeNode.of(Action::JavaScript), :Version => "1.3"
307
+ field PAGES, :Type => NameTreeNode.of(Page), :Version => "1.3"
308
+ field TEMPLATES, :Type => NameTreeNode.of(Page), :Version => "1.3"
309
+ field IDS, :Type => NameTreeNode.of(WebCapture::ContentSet), :Version => "1.3"
310
+ field URLS, :Type => NameTreeNode.of(WebCapture::ContentSet), :Version => "1.3"
311
+ field EMBEDDED_FILES, :Type => NameTreeNode.of(FileSpec), :Version => "1.4"
312
+ field ALTERNATE_PRESENTATIONS, :Type => NameTreeNode, :Version => "1.4"
313
+ field RENDITIONS, :Type => NameTreeNode, :Version => "1.5"
314
+ field XFA_RESOURCES, :Type => NameTreeNode.of(XFAStream), :Version => "1.7", :ExtensionLevel => 3
165
315
  end
166
316
 
167
317
  #
168
- # Retrieve the corresponding value associated with _name_ in
169
- # the specified _root_ name directory, or nil if the value does
170
- # not exist.
318
+ # Class representing a leaf in a Name tree.
171
319
  #
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)
320
+ class NameLeaf < Array.of(String, Object)
321
+
322
+ #
323
+ # Creates a new leaf in a Name tree.
324
+ # _hash_:: A hash of couples, associating a Name with an Reference.
325
+ #
326
+ def initialize(hash = {})
327
+ super(hash.flat_map {|name, obj| [name.dup, obj]})
328
+ end
177
329
  end
178
330
 
179
331
  #
180
- # Returns a Hash of all names under specified _root_ name directory.
181
- # Returns nil if the directory does not exist.
332
+ # Class representing the ViewerPreferences Dictionary of a PDF.
333
+ # This dictionary modifies the way the UI looks when the file is opened in a viewer.
182
334
  #
183
- def ls_names(root)
184
- namesroot = get_names_root(root)
185
- return {} if namesroot.nil?
335
+ class ViewerPreferences < Dictionary
336
+ include StandardObject
186
337
 
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)
204
- elsif node.has_key?(:Kids) # intermediate node
205
- node.Kids.each do |kid|
206
- children.concat(names_from_node(kid.solve, browsed_nodes))
207
- end
338
+ # Valid values for the Enforce field.
339
+ module Enforce
340
+ PRINT_SCALING = :PrintScaling
208
341
  end
209
- end
210
342
 
211
- children
343
+ field :HideToolbar, :Type => Boolean, :Default => false
344
+ field :HideMenubar, :Type => Boolean, :Default => false
345
+ field :HideWindowUI, :Type => Boolean, :Default => false
346
+ field :FitWindow, :Type => Boolean, :Default => false
347
+ field :CenterWindow, :Type => Boolean, :Default => false
348
+ field :DisplayDocTitle, :Type => Boolean, :Default => false, :Version => "1.4"
349
+ field :NonFullScreenPageMode, :Type => Name, :Default => :UseNone
350
+ field :Direction, :Type => Name, :Default => :L2R
351
+ field :ViewArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
352
+ field :ViewClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
353
+ field :PrintArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
354
+ field :PrintClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
355
+ field :PrintScaling, :Type => Name, :Default => :AppDefault, :Version => "1.6"
356
+ field :Duplex, :Type => Name, :Default => :Simplex, :Version => "1.7"
357
+ field :PickTrayByPDFSize, :Type => Boolean, :Version => "1.7"
358
+ field :PrintPageRange, :Type => Array.of(Integer), :Version => "1.7"
359
+ field :NumCopies, :Type => Integer, :Version => "1.7"
360
+ field :Enforce, :Type => Array.of(Name), :Version => "1.7", :ExtensionLevel => 3
212
361
  end
213
362
 
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)
363
+ class Requirement < Dictionary
364
+ include StandardObject
217
365
 
218
- if node.has_key?(:Names) # leaf node
219
- limits = node.Limits
366
+ class Handler < Dictionary
367
+ include StandardObject
220
368
 
221
- if limits
222
- min, max = limits[0].value, limits[1].value
223
- if (min..max) === name.to_str
224
- names = Hash[*node.Names]
225
- target = names[name]
226
- return target && target.solve
227
- end
228
- else
229
- names = Hash[*node.Names]
230
- target = names[name]
231
- return target && target.solve
232
- end
233
-
234
- elsif node.has_key?(:Kids) # intermediate node
235
- node.Kids.each do |kid|
236
- kid = kid.solve
237
- limits = kid.Limits
238
- min, max = limits[0].value, limits[1].value
239
-
240
- if (min..max) === name.to_str
241
- return resolve_name_from_node(kid, name, browsed_nodes)
369
+ module Type
370
+ JS = :JS
371
+ NOOP = :NoOp
242
372
  end
243
- end
244
- end
245
- end
246
- end
247
373
 
248
- def each_name_from_node(node, browsed_nodes = [], &b) #:nodoc:
249
- if node.has_key?(:Names) # leaf node
250
- names = Hash[*node.Names]
251
- names.each_pair do |name, value|
252
- b.call(name, value.solve)
253
- end
254
- elsif node.has_key?(:Kids) # intermediate node
255
- node.Kids.each do |kid|
256
- each_name_from_node(kid.solve, browsed_nodes, &b)
374
+ field :Type, :Type => Name, :Default => :ReqHandler
375
+ field :S, :Type => Name, :Default => Type::NOOP, :Required => true
376
+ field :Script, :Type => String
257
377
  end
258
- end
378
+
379
+ field :Type, :Type => Name, :Default => :Requirement
380
+ field :S, :Type => Name, :Default => :EnableJavaScripts, :Version => "1.7", :Required => true
381
+ field :RH, :Type => Array.of(Handler)
259
382
  end
260
383
 
261
- def get_names_root(root) #:nodoc:
262
- namedirs = self.Catalog.Names
263
- return nil if namedirs.nil? or namedirs[root].nil?
384
+ #
385
+ # Class representing a developer extension.
386
+ #
387
+ class DeveloperExtension < Dictionary
388
+ include StandardObject
264
389
 
265
- namedirs[root].solve
390
+ field :Type, :Type => Name, :Default => :DeveloperExtensions
391
+ field :BaseVersion, :Type => Name, :Required => true
392
+ field :ExtensionLevel, :Type => Integer, :Required => true
266
393
  end
267
- end
268
-
269
- module PageLayout #:nodoc:
270
- SINGLE = :SinglePage
271
- ONE_COLUMN = :OneColumn
272
- TWO_COLUMN_LEFT = :TwoColumnLeft
273
- TWO_COLUMN_RIGHT = :TwoColumnRight
274
- TWO_PAGE_LEFT = :TwoPageLeft
275
- TWO_PAGE_RIGHT = :TwoPageRight
276
- end
277
-
278
- module PageMode #:nodoc:
279
- NONE = :UseNone
280
- OUTLINES = :UseOutlines
281
- THUMBS = :UseThumbs
282
- FULLSCREEN = :FullScreen
283
- OPTIONAL_CONTENT = :UseOC
284
- ATTACHMENTS = :UseAttachments
285
- end
286
-
287
- #
288
- # Class representing additional actions which can be associated with a Catalog.
289
- #
290
- class CatalogAdditionalActions < Dictionary
291
- include StandardObject
292
-
293
- field :WC, :Type => Dictionary, :Version => "1.4"
294
- field :WS, :Type => Dictionary, :Version => "1.4"
295
- field :DS, :Type => Dictionary, :Version => "1.4"
296
- field :WP, :Type => Dictionary, :Version => "1.4"
297
- field :DP, :Type => Dictionary, :Version => "1.4"
298
- end
299
-
300
- class InvalidNameTreeError < Exception #:nodoc:
301
- end
302
-
303
- #
304
- # Class representing the Names Dictionary of a PDF file.
305
- #
306
- class Names < Dictionary
307
- include StandardObject
308
-
394
+
309
395
  #
310
- # Defines constants for Names tree root entries.
396
+ # Class representing an extension Dictionary.
311
397
  #
312
- module Root
313
- DESTS = :Dests
314
- AP = :AP
315
- JAVASCRIPT = :JavaScript
316
- PAGES = :Pages
317
- TEMPLATES = :Templates
318
- IDS = :IDS
319
- URLS = :URLS
320
- EMBEDDEDFILES = :EmbeddedFiles
321
- ALTERNATEPRESENTATIONS = :AlternatePresentations
322
- RENDITIONS = :Renditions
323
- XFARESOURCES = :XFAResources
398
+ class Extensions < Dictionary
399
+ include StandardObject
400
+
401
+ field :Type, :Type => Name, :Default => :Extensions
402
+ field :ADBE, :Type => DeveloperExtension
324
403
  end
325
404
 
326
- field Root::DESTS, :Type => Dictionary, :Version => "1.2"
327
- field Root::AP, :Type => Dictionary, :Version => "1.3"
328
- field Root::JAVASCRIPT, :Type => Dictionary, :Version => "1.3"
329
- field Root::PAGES, :Type => Dictionary, :Version => "1.3"
330
- field Root::TEMPLATES, :Type => Dictionary, :Version => "1.3"
331
- field Root::IDS, :Type => Dictionary, :Version => "1.3"
332
- field Root::URLS, :Type => Dictionary, :Version => "1.3"
333
- field Root::EMBEDDEDFILES, :Type => Dictionary, :Version => "1.4"
334
- field Root::ALTERNATEPRESENTATIONS, :Type => Dictionary, :Version => "1.4"
335
- field Root::RENDITIONS, :Type => Dictionary, :Version => "1.5"
336
- field Root::XFARESOURCES, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
337
- end
338
-
339
- #
340
- # Class representing a node in a Name tree.
341
- #
342
- class NameTreeNode < Dictionary
343
- include StandardObject
344
-
345
- field :Kids, :Type => Array
346
- field :Names, :Type => Array
347
- field :Limits, :Type => Array
348
- end
349
-
350
- #
351
- # Class representing a leaf in a Name tree.
352
- #
353
- class NameLeaf < Origami::Array
354
-
355
405
  #
356
- # Creates a new leaf in a Name tree.
357
- # _hash_:: A hash of couples, associating a Name with an Reference.
406
+ # Class representing the Catalog Dictionary of a PDF file.
358
407
  #
359
- def initialize(hash = {})
360
-
361
- names = []
362
- hash.each_pair do |k,v|
363
- names << k.to_o << v.to_o
364
- end
365
-
366
- super(names)
367
- end
368
- end
369
-
370
- #
371
- # Class representing the ViewerPreferences Dictionary of a PDF.
372
- # This dictionary modifies the way the UI looks when the file is opened in a viewer.
373
- #
374
- class ViewerPreferences < Dictionary
375
- include StandardObject
376
-
377
- field :HideToolbar, :Type => Boolean, :Default => false
378
- field :HideMenubar, :Type => Boolean, :Default => false
379
- field :HideWindowUI, :Type => Boolean, :Default => false
380
- field :FitWindow, :Type => Boolean, :Default => false
381
- field :CenterWindow, :Type => Boolean, :Default => false
382
- field :DisplayDocTitle, :Type => Boolean, :Default => false, :Version => "1.4"
383
- field :NonFullScreenPageMode, :Type => Name, :Default => :UseNone
384
- field :Direction, :Type => Name, :Default => :L2R
385
- field :ViewArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
386
- field :ViewClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
387
- field :PrintArea, :Type => Name, :Default => :CropBox, :Version => "1.4"
388
- field :PrintClip, :Type => Name, :Default => :CropBox, :Version => "1.4"
389
- field :PrintScaling, :Type => Name, :Default => :AppDefault, :Version => "1.6"
390
- field :Duplex, :Type => Name, :Default => :Simplex, :Version => "1.7"
391
- field :PickTrayByPDFSize, :Type => Boolean, :Version => "1.7"
392
- field :PrintPageRange, :Type => Array, :Version => "1.7"
393
- field :NumCopies, :Type => Integer, :Version => "1.7"
394
- field :Enforce, :Type => Array, :Version => "1.7", :ExtensionLevel => 3
395
-
396
- end
397
-
398
- class Requirement < Dictionary
399
- include StandardObject
400
-
401
- class Handler < Dictionary
402
- include StandardObject
403
-
404
- module Type
405
- JS = :JS
406
- NOOP = :NoOp
407
- end
408
-
409
- field :Type, :Type => Name, :Default => :ReqHandler
410
- field :S, :Type => Name, :Default => Type::NOOP, :Required => true
411
- field :Script, :Type => ByteString
408
+ class Catalog < Dictionary
409
+ include StandardObject
410
+
411
+ field :Type, :Type => Name, :Default => :Catalog, :Required => true
412
+ field :Version, :Type => Name, :Version => "1.4"
413
+ field :Pages, :Type => PageTreeNode, :Required => true
414
+ field :PageLabels, :Type => NumberTreeNode.of(PageLabel), :Version => "1.3"
415
+ field :Names, :Type => Names, :Version => "1.2"
416
+ field :Dests, :Type => Dictionary, :Version => "1.1"
417
+ field :ViewerPreferences, :Type => ViewerPreferences, :Version => "1.2"
418
+ field :PageLayout, :Type => Name, :Default => PageLayout::SINGLE
419
+ field :PageMode, :Type => Name, :Default => PageMode::NONE
420
+ field :Outlines, :Type => Outline
421
+ field :Threads, :Type => Array, :Version => "1.1"
422
+ field :OpenAction, :Type => [ Array, Dictionary ], :Version => "1.1"
423
+ field :AA, :Type => CatalogAdditionalActions, :Version => "1.4"
424
+ field :URI, :Type => Dictionary, :Version => "1.1"
425
+ field :AcroForm, :Type => InteractiveForm, :Version => "1.2"
426
+ field :Metadata, :Type => MetadataStream, :Version => "1.4"
427
+ field :StructTreeRoot, :Type => Dictionary, :Version => "1.3"
428
+ field :MarkInfo, :Type => Dictionary, :Version => "1.4"
429
+ field :Lang, :Type => String, :Version => "1.4"
430
+ field :SpiderInfo, :Type => WebCapture::SpiderInfo, :Version => "1.3"
431
+ field :OutputIntents, :Type => Array.of(OutputIntent), :Version => "1.4"
432
+ field :PieceInfo, :Type => Dictionary, :Version => "1.4"
433
+ field :OCProperties, :Type => Dictionary, :Version => "1.5"
434
+ field :Perms, :Type => Dictionary, :Version => "1.5"
435
+ field :Legal, :Type => Dictionary, :Version => "1.5"
436
+ field :Requirements, :Type => Array.of(Requirement), :Version => "1.7"
437
+ field :Collection, :Type => Collection, :Version => "1.7"
438
+ field :NeedsRendering, :Type => Boolean, :Version => "1.7", :Default => false
439
+ field :Extensions, :Type => Extensions, :Version => "1.7", :ExtensionLevel => 3
440
+
441
+ def initialize(hash = {}, parser = nil)
442
+ set_indirect(true)
443
+
444
+ super(hash, parser)
445
+ end
412
446
  end
413
447
 
414
- field :Type, :Type => Name, :Default => :Requirement
415
- field :S, :Type => Name, :Default => :EnableJavaScripts, :Version => "1.7", :Required => true
416
- field :RH, :Type => Array
417
- end
418
-
419
- #
420
- # Class representing an extension Dictionary.
421
- #
422
- class Extensions < Dictionary
423
- include StandardObject
424
-
425
- field :Type, :Type => Name, :Default => :Extensions
426
- end
427
-
428
- #
429
- # Class representing a developer extension.
430
- #
431
- class DeveloperExtension < Dictionary
432
- include StandardObject
433
-
434
- field :Type, :Type => Name, :Default => :DeveloperExtensions
435
- field :BaseVersion, :Type => Name, :Required => true
436
- field :ExtensionLevel, :Type => Integer, :Required => true
437
-
438
- end
439
-
440
- #
441
- # Class representing the Catalog Dictionary of a PDF file.
442
- #
443
- class Catalog < Dictionary
444
-
445
- include StandardObject
446
-
447
- field :Type, :Type => Name, :Default => :Catalog, :Required => true
448
- field :Version, :Type => Name, :Version => "1.4"
449
- field :Pages, :Type => Dictionary, :Required => true
450
- field :PageLabels, :Type => Dictionary, :Version => "1.3"
451
- field :Names, :Type => Dictionary, :Version => "1.2"
452
- field :Dests, :Type => Dictionary, :Version => "1.1"
453
- field :ViewerPreferences, :Type => ViewerPreferences, :Version => "1.2"
454
- field :PageLayout, :Type => Name, :Default => PageLayout::SINGLE
455
- field :PageMode, :Type => Name, :Default => PageMode::NONE
456
- field :Outlines, :Type => Dictionary
457
- field :Threads, :Type => Array, :Version => "1.1"
458
- field :OpenAction, :Type => [ Array, Dictionary ], :Version => "1.1"
459
- field :AA, :Type => Dictionary, :Version => "1.4"
460
- field :URI, :Type => Dictionary, :Version => "1.1"
461
- field :AcroForm, :Type => Dictionary, :Version => "1.2"
462
- field :Metadata, :Type => Stream, :Version => "1.4"
463
- field :StructTreeRoot, :Type => Dictionary, :Version => "1.3"
464
- field :MarkInfo, :Type => Dictionary, :Version => "1.4"
465
- field :Lang, :Type => String, :Version => "1.4"
466
- field :SpiderInfo, :Type => Dictionary, :Version => "1.3"
467
- field :OutputIntents, :Type => Array, :Version => "1.4"
468
- field :PieceInfo, :Type => Dictionary, :Version => "1.4"
469
- field :OCProperties, :Type => Dictionary, :Version => "1.5"
470
- field :Perms, :Type => Dictionary, :Version => "1.5"
471
- field :Legal, :Type => Dictionary, :Version => "1.5"
472
- field :Requirements, :Type => Array, :Version => "1.7"
473
- field :Collection, :Type => Dictionary, :Version => "1.7"
474
- field :NeedsRendering, :Type => Boolean, :Version => "1.7", :Default => false
475
- field :Extensions, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
476
-
477
- def initialize(hash = {})
478
- set_indirect(true)
479
-
480
- super(hash)
481
- end
482
-
483
- end
484
-
485
448
  end