origami-docspring 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/examples/attachments/attachment.rb +7 -8
  4. data/examples/attachments/nested_document.rb +6 -5
  5. data/examples/encryption/encryption.rb +5 -4
  6. data/examples/events/events.rb +7 -6
  7. data/examples/flash/flash.rb +10 -9
  8. data/examples/forms/javascript.rb +14 -13
  9. data/examples/forms/xfa.rb +67 -66
  10. data/examples/javascript/hello_world.rb +6 -5
  11. data/examples/javascript/js_emulation.rb +26 -26
  12. data/examples/loop/goto.rb +12 -11
  13. data/examples/loop/named.rb +17 -16
  14. data/examples/signature/signature.rb +11 -11
  15. data/examples/uri/javascript.rb +25 -24
  16. data/examples/uri/open-uri.rb +5 -4
  17. data/examples/uri/submitform.rb +11 -10
  18. data/lib/origami/3d.rb +330 -334
  19. data/lib/origami/acroform.rb +267 -268
  20. data/lib/origami/actions.rb +266 -278
  21. data/lib/origami/annotations.rb +659 -670
  22. data/lib/origami/array.rb +192 -196
  23. data/lib/origami/boolean.rb +66 -70
  24. data/lib/origami/catalog.rb +360 -363
  25. data/lib/origami/collections.rb +132 -133
  26. data/lib/origami/compound.rb +125 -129
  27. data/lib/origami/destinations.rb +226 -237
  28. data/lib/origami/dictionary.rb +155 -154
  29. data/lib/origami/encryption.rb +967 -923
  30. data/lib/origami/extensions/fdf.rb +270 -275
  31. data/lib/origami/extensions/ppklite.rb +323 -328
  32. data/lib/origami/filespec.rb +170 -173
  33. data/lib/origami/filters/ascii.rb +162 -167
  34. data/lib/origami/filters/ccitt/tables.rb +248 -252
  35. data/lib/origami/filters/ccitt.rb +309 -312
  36. data/lib/origami/filters/crypt.rb +31 -34
  37. data/lib/origami/filters/dct.rb +47 -50
  38. data/lib/origami/filters/flate.rb +57 -60
  39. data/lib/origami/filters/jbig2.rb +50 -53
  40. data/lib/origami/filters/jpx.rb +40 -43
  41. data/lib/origami/filters/lzw.rb +151 -155
  42. data/lib/origami/filters/predictors.rb +250 -255
  43. data/lib/origami/filters/runlength.rb +111 -115
  44. data/lib/origami/filters.rb +319 -325
  45. data/lib/origami/font.rb +173 -177
  46. data/lib/origami/functions.rb +62 -66
  47. data/lib/origami/graphics/colors.rb +203 -208
  48. data/lib/origami/graphics/instruction.rb +79 -81
  49. data/lib/origami/graphics/path.rb +141 -144
  50. data/lib/origami/graphics/patterns.rb +156 -160
  51. data/lib/origami/graphics/render.rb +51 -47
  52. data/lib/origami/graphics/state.rb +144 -142
  53. data/lib/origami/graphics/text.rb +185 -188
  54. data/lib/origami/graphics/xobject.rb +818 -804
  55. data/lib/origami/graphics.rb +25 -26
  56. data/lib/origami/header.rb +63 -65
  57. data/lib/origami/javascript.rb +718 -651
  58. data/lib/origami/linearization.rb +284 -285
  59. data/lib/origami/metadata.rb +156 -135
  60. data/lib/origami/name.rb +98 -100
  61. data/lib/origami/null.rb +49 -51
  62. data/lib/origami/numeric.rb +133 -135
  63. data/lib/origami/obfuscation.rb +180 -182
  64. data/lib/origami/object.rb +634 -631
  65. data/lib/origami/optionalcontent.rb +147 -149
  66. data/lib/origami/outline.rb +46 -48
  67. data/lib/origami/outputintents.rb +76 -77
  68. data/lib/origami/page.rb +637 -596
  69. data/lib/origami/parser.rb +214 -221
  70. data/lib/origami/parsers/fdf.rb +44 -45
  71. data/lib/origami/parsers/pdf/lazy.rb +147 -154
  72. data/lib/origami/parsers/pdf/linear.rb +104 -109
  73. data/lib/origami/parsers/pdf.rb +109 -107
  74. data/lib/origami/parsers/ppklite.rb +44 -46
  75. data/lib/origami/pdf.rb +886 -896
  76. data/lib/origami/reference.rb +116 -120
  77. data/lib/origami/signature.rb +617 -625
  78. data/lib/origami/stream.rb +560 -558
  79. data/lib/origami/string.rb +366 -368
  80. data/lib/origami/template/patterns.rb +50 -52
  81. data/lib/origami/template/widgets.rb +111 -114
  82. data/lib/origami/trailer.rb +153 -157
  83. data/lib/origami/tree.rb +55 -57
  84. data/lib/origami/version.rb +19 -19
  85. data/lib/origami/webcapture.rb +87 -90
  86. data/lib/origami/xfa/config.rb +409 -414
  87. data/lib/origami/xfa/connectionset.rb +113 -117
  88. data/lib/origami/xfa/datasets.rb +38 -42
  89. data/lib/origami/xfa/localeset.rb +33 -37
  90. data/lib/origami/xfa/package.rb +49 -52
  91. data/lib/origami/xfa/pdf.rb +54 -59
  92. data/lib/origami/xfa/signature.rb +33 -37
  93. data/lib/origami/xfa/sourceset.rb +34 -38
  94. data/lib/origami/xfa/stylesheet.rb +35 -39
  95. data/lib/origami/xfa/template.rb +1630 -1634
  96. data/lib/origami/xfa/xdc.rb +33 -37
  97. data/lib/origami/xfa/xfa.rb +132 -123
  98. data/lib/origami/xfa/xfdf.rb +34 -38
  99. data/lib/origami/xfa/xmpmeta.rb +34 -38
  100. data/lib/origami/xfa.rb +50 -53
  101. data/lib/origami/xreftable.rb +462 -462
  102. data/lib/origami.rb +37 -38
  103. data/test/test_actions.rb +22 -20
  104. data/test/test_annotations.rb +54 -52
  105. data/test/test_forms.rb +23 -21
  106. data/test/test_native_types.rb +82 -78
  107. data/test/test_object_tree.rb +25 -24
  108. data/test/test_pages.rb +43 -41
  109. data/test/test_pdf.rb +2 -0
  110. data/test/test_pdf_attachment.rb +23 -21
  111. data/test/test_pdf_create.rb +16 -15
  112. data/test/test_pdf_encrypt.rb +69 -66
  113. data/test/test_pdf_parse.rb +131 -129
  114. data/test/test_pdf_parse_lazy.rb +53 -53
  115. data/test/test_pdf_sign.rb +67 -67
  116. data/test/test_streams.rb +145 -143
  117. data/test/test_xrefs.rb +46 -45
  118. metadata +64 -8
@@ -1,330 +1,329 @@
1
- =begin
2
-
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/>.
18
-
19
- =end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This file is part of Origami, PDF manipulation framework for Ruby
5
+ # Copyright (C) 2016 Guillaume Delugré.
6
+ #
7
+ # Origami is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Origami is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
20
 
21
21
  module Origami
22
+ class PDF
23
+ class LinearizationError < Error # :nodoc:
24
+ end
22
25
 
23
- class PDF
24
-
25
- class LinearizationError < Error #:nodoc:
26
- end
26
+ #
27
+ # Returns whether the current document is linearized.
28
+ #
29
+ def linearized?
30
+ begin
31
+ first_obj = @revisions.first.objects.min_by { |obj| obj.file_offset }
32
+ rescue
33
+ return false
34
+ end
35
+
36
+ @revisions.size > 1 and first_obj.is_a?(Dictionary) and first_obj.has_key? :Linearized
37
+ end
27
38
 
28
- #
29
- # Returns whether the current document is linearized.
30
- #
31
- def linearized?
32
- begin
33
- first_obj = @revisions.first.objects.min_by{|obj| obj.file_offset}
34
- rescue
35
- return false
36
- end
37
-
38
- @revisions.size > 1 and first_obj.is_a?(Dictionary) and first_obj.has_key? :Linearized
39
+ #
40
+ # Tries to delinearize the document if it has been linearized.
41
+ # This operation is xrefs destructive, should be fixed in the future to merge tables.
42
+ #
43
+ def delinearize!
44
+ raise LinearizationError, 'Not a linearized document' unless linearized?
45
+
46
+ #
47
+ # Saves the first trailer.
48
+ #
49
+ prev_trailer = @revisions.first.trailer
50
+
51
+ linear_dict = @revisions.first.objects.min_by { |obj| obj.file_offset }
52
+
53
+ #
54
+ # Removes hint streams used by linearization.
55
+ #
56
+ delete_hint_streams(linear_dict)
57
+
58
+ #
59
+ # Update the trailer.
60
+ #
61
+ last_trailer = (@revisions.last.trailer ||= Trailer.new)
62
+ last_trailer.dictionary ||= Dictionary.new
63
+
64
+ if prev_trailer.dictionary?
65
+ last_trailer.dictionary =
66
+ last_trailer.dictionary.merge(prev_trailer.dictionary)
67
+ else
68
+ xrefstm = @revisions.last.xrefstm
69
+ unless xrefstm.is_a?(XRefStream)
70
+ raise LinearizationError,
71
+ 'Cannot find trailer info while delinearizing document'
39
72
  end
40
73
 
41
- #
42
- # Tries to delinearize the document if it has been linearized.
43
- # This operation is xrefs destructive, should be fixed in the future to merge tables.
44
- #
45
- def delinearize!
46
- raise LinearizationError, 'Not a linearized document' unless self.linearized?
47
-
48
- #
49
- # Saves the first trailer.
50
- #
51
- prev_trailer = @revisions.first.trailer
52
-
53
- linear_dict = @revisions.first.objects.min_by{|obj| obj.file_offset}
54
-
55
- #
56
- # Removes hint streams used by linearization.
57
- #
58
- delete_hint_streams(linear_dict)
59
-
60
- #
61
- # Update the trailer.
62
- #
63
- last_trailer = (@revisions.last.trailer ||= Trailer.new)
64
- last_trailer.dictionary ||= Dictionary.new
65
-
66
- if prev_trailer.dictionary?
67
- last_trailer.dictionary =
68
- last_trailer.dictionary.merge(prev_trailer.dictionary)
69
- else
70
- xrefstm = @revisions.last.xrefstm
71
- raise LinearizationError,
72
- 'Cannot find trailer info while delinearizing document' unless xrefstm.is_a?(XRefStream)
73
-
74
- last_trailer.dictionary[:Root] = xrefstm[:Root]
75
- last_trailer.dictionary[:Encrypt] = xrefstm[:Encrypt]
76
- last_trailer.dictionary[:Info] = xrefstm[:Info]
77
- last_trailer.dictionary[:ID] = xrefstm[:ID]
78
- end
79
-
80
- #
81
- # Remove all xrefs.
82
- # Fix: Should be merged instead.
83
- #
84
- remove_xrefs
85
-
86
- #
87
- # Remove the linearization revision.
88
- #
89
- @revisions.first.body.delete(linear_dict.reference)
90
- @revisions.last.body.merge! @revisions.first.body
91
-
92
- remove_revision(0)
93
-
94
- self
95
- end
74
+ last_trailer.dictionary[:Root] = xrefstm[:Root]
75
+ last_trailer.dictionary[:Encrypt] = xrefstm[:Encrypt]
76
+ last_trailer.dictionary[:Info] = xrefstm[:Info]
77
+ last_trailer.dictionary[:ID] = xrefstm[:ID]
78
+ end
96
79
 
97
- private
80
+ #
81
+ # Remove all xrefs.
82
+ # Fix: Should be merged instead.
83
+ #
84
+ remove_xrefs
98
85
 
99
- #
100
- # Strip the document from Hint streams given a linearization dictionary.
101
- #
102
- def delete_hint_streams(linearization_dict)
103
- hints = linearization_dict[:H]
104
- return unless hints.is_a?(Array)
86
+ #
87
+ # Remove the linearization revision.
88
+ #
89
+ @revisions.first.body.delete(linear_dict.reference)
90
+ @revisions.last.body.merge! @revisions.first.body
105
91
 
106
- hints.each_slice(2) do |offset, _length|
107
- next unless offset.is_a?(Integer)
92
+ remove_revision(0)
108
93
 
109
- stream = get_object_by_offset(offset)
110
- delete_object(stream.reference) if stream.is_a?(Stream)
111
- end
112
- end
94
+ self
113
95
  end
114
96
 
97
+ private
98
+
115
99
  #
116
- # Class representing a linearization dictionary.
100
+ # Strip the document from Hint streams given a linearization dictionary.
117
101
  #
118
- class Linearization < Dictionary
119
- include StandardObject
120
-
121
- field :Linearized, :Type => Real, :Default => 1.0, :Required => true
122
- field :L, :Type => Integer, :Required => true
123
- field :H, :Type => Array.of(Integer), :Required => true
124
- field :O, :Type => Integer, :Required => true
125
- field :E, :Type => Integer, :Required => true
126
- field :N, :Type => Integer, :Required => true
127
- field :T, :Type => Integer, :Required => true
128
- field :P, :Type => Integer, :Default => 0
129
-
130
- def initialize(hash = {}, parser = nil)
131
- super(hash, parser)
132
-
133
- set_indirect(true)
134
- end
135
- end
102
+ def delete_hint_streams(linearization_dict)
103
+ hints = linearization_dict[:H]
104
+ return unless hints.is_a?(Array)
136
105
 
137
- class InvalidHintTableError < Error #:nodoc:
138
- end
106
+ hints.each_slice(2) do |offset, _length|
107
+ next unless offset.is_a?(Integer)
139
108
 
140
- module HintTable
141
- module ClassMethods
142
- def header_item_size(number, size)
143
- @header_items_size[number] = size
144
- end
109
+ stream = get_object_by_offset(offset)
110
+ delete_object(stream.reference) if stream.is_a?(Stream)
111
+ end
112
+ end
113
+ end
114
+
115
+ #
116
+ # Class representing a linearization dictionary.
117
+ #
118
+ class Linearization < Dictionary
119
+ include StandardObject
120
+
121
+ field :Linearized, Type: Real, Default: 1.0, Required: true
122
+ field :L, Type: Integer, Required: true
123
+ field :H, Type: Array.of(Integer), Required: true
124
+ field :O, Type: Integer, Required: true
125
+ field :E, Type: Integer, Required: true
126
+ field :N, Type: Integer, Required: true
127
+ field :T, Type: Integer, Required: true
128
+ field :P, Type: Integer, Default: 0
129
+
130
+ def initialize(hash = {}, parser = nil)
131
+ super
132
+
133
+ set_indirect(true)
134
+ end
135
+ end
145
136
 
146
- def get_header_item_size(number)
147
- @header_items_size[number]
148
- end
137
+ class InvalidHintTableError < Error # :nodoc:
138
+ end
149
139
 
150
- def entry_item_size(number, size)
151
- @entry_items_size[number] = size
152
- end
140
+ module HintTable
141
+ module ClassMethods
142
+ def header_item_size(number, size)
143
+ @header_items_size[number] = size
144
+ end
153
145
 
154
- def get_entry_item_size(number)
155
- @entry_items_size[number]
156
- end
146
+ def get_header_item_size(number)
147
+ @header_items_size[number]
148
+ end
157
149
 
158
- def nb_header_items
159
- @header_items_size.size
160
- end
150
+ def entry_item_size(number, size)
151
+ @entry_items_size[number] = size
152
+ end
161
153
 
162
- def nb_entry_items
163
- @entry_items_size.size
164
- end
165
- end
154
+ def get_entry_item_size(number)
155
+ @entry_items_size[number]
156
+ end
166
157
 
167
- def self.included(receiver)
168
- receiver.instance_variable_set(:@header_items_size, {})
169
- receiver.instance_variable_set(:@entry_items_size, {})
170
- receiver.extend(ClassMethods)
171
- end
158
+ def nb_header_items
159
+ @header_items_size.size
160
+ end
172
161
 
173
- attr_accessor :header_items
174
- attr_accessor :entries
162
+ def nb_entry_items
163
+ @entry_items_size.size
164
+ end
165
+ end
175
166
 
176
- def initialize
177
- @header_items = {}
178
- @entries = []
179
- end
167
+ def self.included(receiver)
168
+ receiver.instance_variable_set(:@header_items_size, {})
169
+ receiver.instance_variable_set(:@entry_items_size, {})
170
+ receiver.extend(ClassMethods)
171
+ end
180
172
 
181
- def to_s
182
- data = ""
173
+ attr_accessor :header_items
174
+ attr_accessor :entries
183
175
 
184
- nitems = self.class.nb_header_items
185
- for no in (1..nitems)
186
- unless @header_items.include?(no)
187
- raise InvalidHintTableError, "Missing item #{no} in header section of #{self.class}"
188
- end
176
+ def initialize
177
+ @header_items = {}
178
+ @entries = []
179
+ end
189
180
 
190
- value = @header_items[no]
191
- item_size = self.class.get_header_item_size(no)
181
+ def to_s
182
+ data = ""
192
183
 
193
- item_size = ((item_size + 7) >> 3) << 3
194
- item_data = value.to_s(2)
195
- item_data = "0" * (item_size - item_data.size) + item_data
184
+ nitems = self.class.nb_header_items
185
+ (1..nitems).each do |no|
186
+ unless @header_items.include?(no)
187
+ raise InvalidHintTableError, "Missing item #{no} in header section of #{self.class}"
188
+ end
196
189
 
197
- data << [ item_data ].pack("B*")
198
- end
190
+ value = @header_items[no]
191
+ item_size = self.class.get_header_item_size(no)
199
192
 
200
- nitems = self.class.nb_entry_items
201
- @entries.each_with_index do |entry, i|
202
- for no in (1..nitems)
203
- unless entry.include?(no)
204
- raise InvalidHintTableError, "Missing item #{no} in entry #{i} of #{self.class}"
205
- end
193
+ item_size = ((item_size + 7) >> 3) << 3
194
+ item_data = value.to_s(2)
195
+ item_data = "0" * (item_size - item_data.size) + item_data
206
196
 
207
- value = entry[no]
208
- item_size = self.class.get_entry_item_size(no)
197
+ data << [item_data].pack("B*")
198
+ end
209
199
 
210
- item_size = ((item_size + 7) >> 3) << 3
211
- item_data = value.to_s(2)
212
- item_data = "0" * (item_size - item_data.size) + item_data
200
+ nitems = self.class.nb_entry_items
201
+ @entries.each_with_index do |entry, i|
202
+ (1..nitems).each do |no|
203
+ unless entry.include?(no)
204
+ raise InvalidHintTableError, "Missing item #{no} in entry #{i} of #{self.class}"
205
+ end
213
206
 
214
- data << [ item_data ].pack("B*")
215
- end
216
- end
207
+ value = entry[no]
208
+ item_size = self.class.get_entry_item_size(no)
217
209
 
218
- data
219
- end
210
+ item_size = ((item_size + 7) >> 3) << 3
211
+ item_data = value.to_s(2)
212
+ item_data = "0" * (item_size - item_data.size) + item_data
220
213
 
221
- class PageOffsetTable
222
- include HintTable
223
-
224
- header_item_size 1, 32
225
- header_item_size 2, 32
226
- header_item_size 3, 16
227
- header_item_size 4, 32
228
- header_item_size 5, 16
229
- header_item_size 6, 32
230
- header_item_size 7, 16
231
- header_item_size 8, 32
232
- header_item_size 9, 16
233
- header_item_size 10, 16
234
- header_item_size 11, 16
235
- header_item_size 12, 16
236
- header_item_size 13, 16
237
-
238
- entry_item_size 1, 16
239
- entry_item_size 2, 16
240
- entry_item_size 3, 16
241
- entry_item_size 4, 16
242
- entry_item_size 5, 16
243
- entry_item_size 6, 16
244
- entry_item_size 7, 16
214
+ data << [item_data].pack("B*")
245
215
  end
216
+ end
246
217
 
247
- class SharedObjectTable
248
- include HintTable
249
-
250
- header_item_size 1, 32
251
- header_item_size 2, 32
252
- header_item_size 3, 32
253
- header_item_size 4, 32
254
- header_item_size 5, 16
255
- header_item_size 6, 32
256
- header_item_size 7, 16
257
-
258
- entry_item_size 1, 16
259
- entry_item_size 2, 1
260
- entry_item_size 3, 128
261
- entry_item_size 4, 16
262
- end
218
+ data
263
219
  end
264
220
 
265
- class InvalidHintStreamObjectError < InvalidStreamObjectError #:nodoc:
221
+ class PageOffsetTable
222
+ include HintTable
223
+
224
+ header_item_size 1, 32
225
+ header_item_size 2, 32
226
+ header_item_size 3, 16
227
+ header_item_size 4, 32
228
+ header_item_size 5, 16
229
+ header_item_size 6, 32
230
+ header_item_size 7, 16
231
+ header_item_size 8, 32
232
+ header_item_size 9, 16
233
+ header_item_size 10, 16
234
+ header_item_size 11, 16
235
+ header_item_size 12, 16
236
+ header_item_size 13, 16
237
+
238
+ entry_item_size 1, 16
239
+ entry_item_size 2, 16
240
+ entry_item_size 3, 16
241
+ entry_item_size 4, 16
242
+ entry_item_size 5, 16
243
+ entry_item_size 6, 16
244
+ entry_item_size 7, 16
266
245
  end
267
246
 
268
- class HintStream < Stream
269
- attr_accessor :page_offset_table
270
- attr_accessor :shared_objects_table
271
- attr_accessor :thumbnails_table
272
- attr_accessor :outlines_table
273
- attr_accessor :threads_table
274
- attr_accessor :named_destinations_table
275
- attr_accessor :interactive_forms_table
276
- attr_accessor :information_dictionary_table
277
- attr_accessor :logical_structure_table
278
- attr_accessor :page_labels_table
279
- attr_accessor :renditions_table
280
- attr_accessor :embedded_files_table
281
-
282
- field :S, :Type => Integer, :Required => true # Shared objects
283
- field :T, :Type => Integer # Thumbnails
284
- field :O, :Type => Integer # Outlines
285
- field :A, :Type => Integer # Threads
286
- field :E, :Type => Integer # Named destinations
287
- field :V, :Type => Integer # Interactive forms
288
- field :I, :Type => Integer # Information dictionary
289
- field :C, :Type => Integer # Logical structure
290
- field :L, :Type => Integer # Page labels
291
- field :R, :Type => Integer # Renditions
292
- field :B, :Type => Integer # Embedded files
293
-
294
- def pre_build
295
- if @page_offset_table.nil?
296
- raise InvalidHintStreamObjectError, "No page offset hint table"
297
- end
298
-
299
- if @shared_objects_table.nil?
300
- raise InvalidHintStreamObjectError, "No shared objects hint table"
301
- end
302
-
303
- @data = ""
304
- save_table(@page_offset_table)
305
- save_table(@shared_objects_table, :S)
306
- save_table(@thumbnails_table, :T)
307
- save_table(@outlines_table, :O)
308
- save_table(@threads_table, :A)
309
- save_table(@named_destinations_table, :E)
310
- save_table(@interactive_forms_table, :V)
311
- save_table(@information_dictionary_table, :I)
312
- save_table(@logical_structure_table, :C)
313
- save_table(@page_labels_table, :L)
314
- save_table(@renditions_table, :R)
315
- save_table(@embedded_files_table, :B)
316
-
317
- super
318
- end
247
+ class SharedObjectTable
248
+ include HintTable
249
+
250
+ header_item_size 1, 32
251
+ header_item_size 2, 32
252
+ header_item_size 3, 32
253
+ header_item_size 4, 32
254
+ header_item_size 5, 16
255
+ header_item_size 6, 32
256
+ header_item_size 7, 16
257
+
258
+ entry_item_size 1, 16
259
+ entry_item_size 2, 1
260
+ entry_item_size 3, 128
261
+ entry_item_size 4, 16
262
+ end
263
+ end
264
+
265
+ class InvalidHintStreamObjectError < InvalidStreamObjectError # :nodoc:
266
+ end
267
+
268
+ class HintStream < Stream
269
+ attr_accessor :page_offset_table
270
+ attr_accessor :shared_objects_table
271
+ attr_accessor :thumbnails_table
272
+ attr_accessor :outlines_table
273
+ attr_accessor :threads_table
274
+ attr_accessor :named_destinations_table
275
+ attr_accessor :interactive_forms_table
276
+ attr_accessor :information_dictionary_table
277
+ attr_accessor :logical_structure_table
278
+ attr_accessor :page_labels_table
279
+ attr_accessor :renditions_table
280
+ attr_accessor :embedded_files_table
281
+
282
+ field :S, Type: Integer, Required: true # Shared objects
283
+ field :T, Type: Integer # Thumbnails
284
+ field :O, Type: Integer # Outlines
285
+ field :A, Type: Integer # Threads
286
+ field :E, Type: Integer # Named destinations
287
+ field :V, Type: Integer # Interactive forms
288
+ field :I, Type: Integer # Information dictionary
289
+ field :C, Type: Integer # Logical structure
290
+ field :L, Type: Integer # Page labels
291
+ field :R, Type: Integer # Renditions
292
+ field :B, Type: Integer # Embedded files
293
+
294
+ def pre_build
295
+ if @page_offset_table.nil?
296
+ raise InvalidHintStreamObjectError, "No page offset hint table"
297
+ end
298
+
299
+ if @shared_objects_table.nil?
300
+ raise InvalidHintStreamObjectError, "No shared objects hint table"
301
+ end
302
+
303
+ @data = ""
304
+ save_table(@page_offset_table)
305
+ save_table(@shared_objects_table, :S)
306
+ save_table(@thumbnails_table, :T)
307
+ save_table(@outlines_table, :O)
308
+ save_table(@threads_table, :A)
309
+ save_table(@named_destinations_table, :E)
310
+ save_table(@interactive_forms_table, :V)
311
+ save_table(@information_dictionary_table, :I)
312
+ save_table(@logical_structure_table, :C)
313
+ save_table(@page_labels_table, :L)
314
+ save_table(@renditions_table, :R)
315
+ save_table(@embedded_files_table, :B)
316
+
317
+ super
318
+ end
319
319
 
320
- private
320
+ private
321
321
 
322
- def save_table(table, name = nil)
323
- unless table.nil?
324
- self[name] = @data.size if name
325
- @data << table.to_s
326
- end
327
- end
322
+ def save_table(table, name = nil)
323
+ unless table.nil?
324
+ self[name] = @data.size if name
325
+ @data << table.to_s
326
+ end
328
327
  end
329
-
328
+ end
330
329
  end