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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/examples/attachments/attachment.rb +7 -8
- data/examples/attachments/nested_document.rb +6 -5
- data/examples/encryption/encryption.rb +5 -4
- data/examples/events/events.rb +7 -6
- data/examples/flash/flash.rb +10 -9
- data/examples/forms/javascript.rb +14 -13
- data/examples/forms/xfa.rb +67 -66
- data/examples/javascript/hello_world.rb +6 -5
- data/examples/javascript/js_emulation.rb +26 -26
- data/examples/loop/goto.rb +12 -11
- data/examples/loop/named.rb +17 -16
- data/examples/signature/signature.rb +11 -11
- data/examples/uri/javascript.rb +25 -24
- data/examples/uri/open-uri.rb +5 -4
- data/examples/uri/submitform.rb +11 -10
- data/lib/origami/3d.rb +330 -334
- data/lib/origami/acroform.rb +267 -268
- data/lib/origami/actions.rb +266 -278
- data/lib/origami/annotations.rb +659 -670
- data/lib/origami/array.rb +192 -196
- data/lib/origami/boolean.rb +66 -70
- data/lib/origami/catalog.rb +360 -363
- data/lib/origami/collections.rb +132 -133
- data/lib/origami/compound.rb +125 -129
- data/lib/origami/destinations.rb +226 -237
- data/lib/origami/dictionary.rb +155 -154
- data/lib/origami/encryption.rb +967 -923
- data/lib/origami/extensions/fdf.rb +270 -275
- data/lib/origami/extensions/ppklite.rb +323 -328
- data/lib/origami/filespec.rb +170 -173
- data/lib/origami/filters/ascii.rb +162 -167
- data/lib/origami/filters/ccitt/tables.rb +248 -252
- data/lib/origami/filters/ccitt.rb +309 -312
- data/lib/origami/filters/crypt.rb +31 -34
- data/lib/origami/filters/dct.rb +47 -50
- data/lib/origami/filters/flate.rb +57 -60
- data/lib/origami/filters/jbig2.rb +50 -53
- data/lib/origami/filters/jpx.rb +40 -43
- data/lib/origami/filters/lzw.rb +151 -155
- data/lib/origami/filters/predictors.rb +250 -255
- data/lib/origami/filters/runlength.rb +111 -115
- data/lib/origami/filters.rb +319 -325
- data/lib/origami/font.rb +173 -177
- data/lib/origami/functions.rb +62 -66
- data/lib/origami/graphics/colors.rb +203 -208
- data/lib/origami/graphics/instruction.rb +79 -81
- data/lib/origami/graphics/path.rb +141 -144
- data/lib/origami/graphics/patterns.rb +156 -160
- data/lib/origami/graphics/render.rb +51 -47
- data/lib/origami/graphics/state.rb +144 -142
- data/lib/origami/graphics/text.rb +185 -188
- data/lib/origami/graphics/xobject.rb +818 -804
- data/lib/origami/graphics.rb +25 -26
- data/lib/origami/header.rb +63 -65
- data/lib/origami/javascript.rb +718 -651
- data/lib/origami/linearization.rb +284 -285
- data/lib/origami/metadata.rb +156 -135
- data/lib/origami/name.rb +98 -100
- data/lib/origami/null.rb +49 -51
- data/lib/origami/numeric.rb +133 -135
- data/lib/origami/obfuscation.rb +180 -182
- data/lib/origami/object.rb +634 -631
- data/lib/origami/optionalcontent.rb +147 -149
- data/lib/origami/outline.rb +46 -48
- data/lib/origami/outputintents.rb +76 -77
- data/lib/origami/page.rb +637 -596
- data/lib/origami/parser.rb +214 -221
- data/lib/origami/parsers/fdf.rb +44 -45
- data/lib/origami/parsers/pdf/lazy.rb +147 -154
- data/lib/origami/parsers/pdf/linear.rb +104 -109
- data/lib/origami/parsers/pdf.rb +109 -107
- data/lib/origami/parsers/ppklite.rb +44 -46
- data/lib/origami/pdf.rb +886 -896
- data/lib/origami/reference.rb +116 -120
- data/lib/origami/signature.rb +617 -625
- data/lib/origami/stream.rb +560 -558
- data/lib/origami/string.rb +366 -368
- data/lib/origami/template/patterns.rb +50 -52
- data/lib/origami/template/widgets.rb +111 -114
- data/lib/origami/trailer.rb +153 -157
- data/lib/origami/tree.rb +55 -57
- data/lib/origami/version.rb +19 -19
- data/lib/origami/webcapture.rb +87 -90
- data/lib/origami/xfa/config.rb +409 -414
- data/lib/origami/xfa/connectionset.rb +113 -117
- data/lib/origami/xfa/datasets.rb +38 -42
- data/lib/origami/xfa/localeset.rb +33 -37
- data/lib/origami/xfa/package.rb +49 -52
- data/lib/origami/xfa/pdf.rb +54 -59
- data/lib/origami/xfa/signature.rb +33 -37
- data/lib/origami/xfa/sourceset.rb +34 -38
- data/lib/origami/xfa/stylesheet.rb +35 -39
- data/lib/origami/xfa/template.rb +1630 -1634
- data/lib/origami/xfa/xdc.rb +33 -37
- data/lib/origami/xfa/xfa.rb +132 -123
- data/lib/origami/xfa/xfdf.rb +34 -38
- data/lib/origami/xfa/xmpmeta.rb +34 -38
- data/lib/origami/xfa.rb +50 -53
- data/lib/origami/xreftable.rb +462 -462
- data/lib/origami.rb +37 -38
- data/test/test_actions.rb +22 -20
- data/test/test_annotations.rb +54 -52
- data/test/test_forms.rb +23 -21
- data/test/test_native_types.rb +82 -78
- data/test/test_object_tree.rb +25 -24
- data/test/test_pages.rb +43 -41
- data/test/test_pdf.rb +2 -0
- data/test/test_pdf_attachment.rb +23 -21
- data/test/test_pdf_create.rb +16 -15
- data/test/test_pdf_encrypt.rb +69 -66
- data/test/test_pdf_parse.rb +131 -129
- data/test/test_pdf_parse_lazy.rb +53 -53
- data/test/test_pdf_sign.rb +67 -67
- data/test/test_streams.rb +145 -143
- data/test/test_xrefs.rb +46 -45
- metadata +64 -8
@@ -1,330 +1,329 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
80
|
+
#
|
81
|
+
# Remove all xrefs.
|
82
|
+
# Fix: Should be merged instead.
|
83
|
+
#
|
84
|
+
remove_xrefs
|
98
85
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
107
|
-
next unless offset.is_a?(Integer)
|
92
|
+
remove_revision(0)
|
108
93
|
|
109
|
-
|
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
|
-
#
|
100
|
+
# Strip the document from Hint streams given a linearization dictionary.
|
117
101
|
#
|
118
|
-
|
119
|
-
|
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
|
-
|
138
|
-
|
106
|
+
hints.each_slice(2) do |offset, _length|
|
107
|
+
next unless offset.is_a?(Integer)
|
139
108
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
147
|
-
|
148
|
-
end
|
137
|
+
class InvalidHintTableError < Error # :nodoc:
|
138
|
+
end
|
149
139
|
|
150
|
-
|
151
|
-
|
152
|
-
|
140
|
+
module HintTable
|
141
|
+
module ClassMethods
|
142
|
+
def header_item_size(number, size)
|
143
|
+
@header_items_size[number] = size
|
144
|
+
end
|
153
145
|
|
154
|
-
|
155
|
-
|
156
|
-
|
146
|
+
def get_header_item_size(number)
|
147
|
+
@header_items_size[number]
|
148
|
+
end
|
157
149
|
|
158
|
-
|
159
|
-
|
160
|
-
|
150
|
+
def entry_item_size(number, size)
|
151
|
+
@entry_items_size[number] = size
|
152
|
+
end
|
161
153
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
154
|
+
def get_entry_item_size(number)
|
155
|
+
@entry_items_size[number]
|
156
|
+
end
|
166
157
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
receiver.extend(ClassMethods)
|
171
|
-
end
|
158
|
+
def nb_header_items
|
159
|
+
@header_items_size.size
|
160
|
+
end
|
172
161
|
|
173
|
-
|
174
|
-
|
162
|
+
def nb_entry_items
|
163
|
+
@entry_items_size.size
|
164
|
+
end
|
165
|
+
end
|
175
166
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
-
|
182
|
-
|
173
|
+
attr_accessor :header_items
|
174
|
+
attr_accessor :entries
|
183
175
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
end
|
176
|
+
def initialize
|
177
|
+
@header_items = {}
|
178
|
+
@entries = []
|
179
|
+
end
|
189
180
|
|
190
|
-
|
191
|
-
|
181
|
+
def to_s
|
182
|
+
data = ""
|
192
183
|
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
-
|
198
|
-
|
190
|
+
value = @header_items[no]
|
191
|
+
item_size = self.class.get_header_item_size(no)
|
199
192
|
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
208
|
-
|
197
|
+
data << [item_data].pack("B*")
|
198
|
+
end
|
209
199
|
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
215
|
-
|
216
|
-
end
|
207
|
+
value = entry[no]
|
208
|
+
item_size = self.class.get_entry_item_size(no)
|
217
209
|
|
218
|
-
|
219
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
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
|
-
|
320
|
+
private
|
321
321
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
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
|