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,557 +1,557 @@
1
- =begin
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
+ #
2
20
 
3
- This file is part of Origami, PDF manipulation framework for Ruby
4
- Copyright (C) 2016 Guillaume Delugré.
21
+ module Origami
22
+ class PDF
23
+ #
24
+ # Tries to strip any xrefs information off the document.
25
+ #
26
+ def remove_xrefs
27
+ @revisions.reverse_each do |rev|
28
+ if rev.xrefstm?
29
+ delete_object(rev.xrefstm.reference)
30
+ end
31
+
32
+ if rev.trailer.XRefStm.is_a?(Integer)
33
+ xrefstm = get_object_by_offset(rev.trailer.XRefStm)
5
34
 
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.
35
+ delete_object(xrefstm.reference) if xrefstm.is_a?(XRefStream)
36
+ end
10
37
 
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.
38
+ rev.xrefstm = rev.xreftable = nil
39
+ end
40
+ end
41
+ end
15
42
 
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/>.
43
+ class InvalidXRefError < Error # :nodoc:
44
+ end
18
45
 
19
- =end
46
+ #
47
+ # Class representing a Cross-reference information.
48
+ #
49
+ class XRef
50
+ FREE = "f"
51
+ USED = "n"
52
+ FIRSTFREE = 65535
20
53
 
21
- module Origami
54
+ @@regexp = /(?<offset>\d{10}) (?<gen>\d{5}) (?<state>n|f)(\r\n| \r| \n)/
22
55
 
23
- class PDF
24
- #
25
- # Tries to strip any xrefs information off the document.
26
- #
27
- def remove_xrefs
28
- @revisions.reverse_each do |rev|
29
- if rev.xrefstm?
30
- delete_object(rev.xrefstm.reference)
31
- end
56
+ attr_accessor :offset, :generation, :state
32
57
 
33
- if rev.trailer.XRefStm.is_a?(Integer)
34
- xrefstm = get_object_by_offset(rev.trailer.XRefStm)
58
+ #
59
+ # Creates a new XRef.
60
+ # _offset_:: The file _offset_ of the referenced Object.
61
+ # _generation_:: The generation number of the referenced Object.
62
+ # _state_:: The state of the referenced Object (FREE or USED).
63
+ #
64
+ def initialize(offset, generation, state)
65
+ @offset, @generation, @state = offset, generation, state
66
+ end
35
67
 
36
- delete_object(xrefstm.reference) if xrefstm.is_a?(XRefStream)
37
- end
68
+ def self.parse(stream) # :nodoc:
69
+ scanner = Parser.init_scanner(stream)
38
70
 
39
- rev.xrefstm = rev.xreftable = nil
40
- end
41
- end
71
+ if scanner.scan(@@regexp).nil?
72
+ raise InvalidXRefError, "Invalid XRef format"
73
+ end
74
+
75
+ offset = scanner['offset'].to_i
76
+ generation = scanner['gen'].to_i
77
+ state = scanner['state']
78
+
79
+ XRef.new(offset, generation, state)
42
80
  end
43
81
 
44
- class InvalidXRefError < Error #:nodoc:
82
+ #
83
+ # Returns true if the associated object is used.
84
+ #
85
+ def used?
86
+ @state == USED
45
87
  end
46
88
 
47
89
  #
48
- # Class representing a Cross-reference information.
90
+ # Returns true if the associated object is freed.
49
91
  #
50
- class XRef
92
+ def free?
93
+ @state == FREE
94
+ end
51
95
 
52
- FREE = "f"
53
- USED = "n"
54
- FIRSTFREE = 65535
96
+ #
97
+ # Marks an XRef as freed.
98
+ #
99
+ def free!
100
+ @state = FREE
101
+ end
55
102
 
56
- @@regexp = /(?<offset>\d{10}) (?<gen>\d{5}) (?<state>n|f)(\r\n| \r| \n)/
103
+ #
104
+ # Outputs self into PDF code.
105
+ #
106
+ def to_s(eol: $/)
107
+ off = @offset.to_s.rjust(10, '0')
108
+ gen = @generation.to_s.rjust(5, '0')
57
109
 
58
- attr_accessor :offset, :generation, :state
110
+ "#{off} #{gen} #{@state}" + eol.rjust(2, ' ')
111
+ end
59
112
 
60
- #
61
- # Creates a new XRef.
62
- # _offset_:: The file _offset_ of the referenced Object.
63
- # _generation_:: The generation number of the referenced Object.
64
- # _state_:: The state of the referenced Object (FREE or USED).
65
- #
66
- def initialize(offset, generation, state)
67
- @offset, @generation, @state = offset, generation, state
68
- end
113
+ def to_xrefstm_data(type_w, field1_w, field2_w)
114
+ type_w <<= 3
115
+ field1_w <<= 3
116
+ field2_w <<= 3
69
117
 
70
- def self.parse(stream) #:nodoc:
71
- scanner = Parser.init_scanner(stream)
118
+ type = ((@state == FREE) ? "\000" : "\001").unpack1("B#{type_w}")
72
119
 
73
- if scanner.scan(@@regexp).nil?
74
- raise InvalidXRefError, "Invalid XRef format"
75
- end
120
+ offset = @offset.to_s(2).rjust(field1_w, '0')
121
+ generation = @generation.to_s(2).rjust(field2_w, '0')
76
122
 
77
- offset = scanner['offset'].to_i
78
- generation = scanner['gen'].to_i
79
- state = scanner['state']
123
+ [type, offset, generation].pack("B#{type_w}B#{field1_w}B#{field2_w}")
124
+ end
80
125
 
81
- XRef.new(offset, generation, state)
82
- end
126
+ class InvalidXRefSubsectionError < Error # :nodoc:
127
+ end
128
+
129
+ #
130
+ # Class representing a cross-reference subsection.
131
+ # A subsection contains a continute set of XRef.
132
+ #
133
+ class Subsection
134
+ include Enumerable
83
135
 
84
- #
85
- # Returns true if the associated object is used.
86
- #
87
- def used?
88
- @state == USED
136
+ @@regexp = Regexp.new("(?<start>\\d+) (?<size>\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
137
+
138
+ attr_reader :range
139
+
140
+ #
141
+ # Creates a new XRef subsection.
142
+ # _start_:: The number of the first object referenced in the subsection.
143
+ # _entries_:: An array of XRef.
144
+ #
145
+ def initialize(start, entries = [])
146
+ @entries = entries.dup
147
+ @range = Range.new(start, start + entries.size - 1)
148
+ end
149
+
150
+ def self.parse(stream) # :nodoc:
151
+ scanner = Parser.init_scanner(stream)
152
+
153
+ if scanner.scan(@@regexp).nil?
154
+ raise InvalidXRefSubsectionError, "Bad subsection format"
89
155
  end
90
156
 
91
- #
92
- # Returns true if the associated object is freed.
93
- #
94
- def free?
95
- @state == FREE
157
+ start = scanner['start'].to_i
158
+ size = scanner['size'].to_i
159
+
160
+ xrefs = []
161
+ size.times do
162
+ xrefs << XRef.parse(scanner)
96
163
  end
97
164
 
98
- #
99
- # Marks an XRef as freed.
100
- #
101
- def free!
102
- @state = FREE
165
+ XRef::Subsection.new(start, xrefs)
166
+ end
167
+
168
+ #
169
+ # Returns whether this subsection contains information about a particular object.
170
+ # _no_:: The Object number.
171
+ #
172
+ def has_object?(no)
173
+ @range.include?(no)
174
+ end
175
+
176
+ #
177
+ # Returns XRef associated with a given object.
178
+ # _no_:: The Object number.
179
+ #
180
+ def [](no)
181
+ @entries[no - @range.begin]
182
+ end
183
+
184
+ #
185
+ # Processes each XRef in the subsection.
186
+ #
187
+ def each(&b)
188
+ @entries.each(&b)
189
+ end
190
+
191
+ #
192
+ # Processes each XRef in the subsection, passing the XRef and the object number to the block.
193
+ #
194
+ def each_with_number
195
+ return enum_for(__method__) { size } unless block_given?
196
+
197
+ counter = @range.to_enum
198
+ @entries.each do |entry|
199
+ yield(entry, counter.next)
200
+ end
201
+ end
202
+
203
+ #
204
+ # The number of entries in the subsection.
205
+ #
206
+ def size
207
+ @entries.size
208
+ end
209
+
210
+ #
211
+ # Outputs self into PDF code.
212
+ #
213
+ def to_s(eol: $/)
214
+ section = "#{@range.begin} #{@range.end - @range.begin + 1}" + eol
215
+ @entries.each do |xref|
216
+ section << xref.to_s(eol: eol)
103
217
  end
104
218
 
105
- #
106
- # Outputs self into PDF code.
107
- #
108
- def to_s(eol: $/)
109
- off = @offset.to_s.rjust(10, '0')
110
- gen = @generation.to_s.rjust(5, '0')
219
+ section
220
+ end
221
+ end
111
222
 
112
- "#{off} #{gen} #{@state}" + eol.rjust(2, ' ')
113
- end
223
+ class InvalidXRefSectionError < Error # :nodoc:
224
+ end
225
+
226
+ #
227
+ # Class representing a Cross-reference table.
228
+ # A section contains a set of XRef::Subsection.
229
+ #
230
+ class Section
231
+ include Enumerable
114
232
 
115
- def to_xrefstm_data(type_w, field1_w, field2_w)
116
- type_w <<= 3
117
- field1_w <<= 3
118
- field2_w <<= 3
233
+ TOKEN = "xref"
119
234
 
120
- type = ((@state == FREE) ? "\000" : "\001").unpack("B#{type_w}")[0]
235
+ @@regexp_open = Regexp.new(WHITESPACES + TOKEN + WHITESPACES + "(\\r?\\n|\\r\\n?)")
236
+ @@regexp_sub = Regexp.new("(\\d+) (\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
121
237
 
122
- offset = @offset.to_s(2).rjust(field1_w, '0')
123
- generation = @generation.to_s(2).rjust(field2_w, '0')
238
+ #
239
+ # Creates a new XRef section.
240
+ # _subsections_:: An array of XRefSubsection.
241
+ #
242
+ def initialize(subsections = [])
243
+ @subsections = subsections
244
+ end
124
245
 
125
- [ type , offset, generation ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
246
+ def self.parse(stream) # :nodoc:
247
+ scanner = Parser.init_scanner(stream)
248
+
249
+ if scanner.skip(@@regexp_open).nil?
250
+ raise InvalidXRefSectionError, "No xref token found"
126
251
  end
127
252
 
128
- class InvalidXRefSubsectionError < Error #:nodoc:
253
+ subsections = []
254
+ while scanner.match?(@@regexp_sub)
255
+ subsections << XRef::Subsection.parse(scanner)
129
256
  end
130
257
 
131
- #
132
- # Class representing a cross-reference subsection.
133
- # A subsection contains a continute set of XRef.
134
- #
135
- class Subsection
136
- include Enumerable
137
-
138
- @@regexp = Regexp.new("(?<start>\\d+) (?<size>\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
139
-
140
- attr_reader :range
141
-
142
- #
143
- # Creates a new XRef subsection.
144
- # _start_:: The number of the first object referenced in the subsection.
145
- # _entries_:: An array of XRef.
146
- #
147
- def initialize(start, entries = [])
148
- @entries = entries.dup
149
- @range = Range.new(start, start + entries.size - 1)
150
- end
151
-
152
- def self.parse(stream) #:nodoc:
153
- scanner = Parser.init_scanner(stream)
154
-
155
- if scanner.scan(@@regexp).nil?
156
- raise InvalidXRefSubsectionError, "Bad subsection format"
157
- end
158
-
159
- start = scanner['start'].to_i
160
- size = scanner['size'].to_i
161
-
162
- xrefs = []
163
- size.times do
164
- xrefs << XRef.parse(scanner)
165
- end
166
-
167
- XRef::Subsection.new(start, xrefs)
168
- end
169
-
170
- #
171
- # Returns whether this subsection contains information about a particular object.
172
- # _no_:: The Object number.
173
- #
174
- def has_object?(no)
175
- @range.include?(no)
176
- end
177
-
178
- #
179
- # Returns XRef associated with a given object.
180
- # _no_:: The Object number.
181
- #
182
- def [](no)
183
- @entries[no - @range.begin]
184
- end
185
-
186
- #
187
- # Processes each XRef in the subsection.
188
- #
189
- def each(&b)
190
- @entries.each(&b)
191
- end
192
-
193
- #
194
- # Processes each XRef in the subsection, passing the XRef and the object number to the block.
195
- #
196
- def each_with_number
197
- return enum_for(__method__) { self.size } unless block_given?
198
-
199
- counter = @range.to_enum
200
- @entries.each do |entry|
201
- yield(entry, counter.next)
202
- end
203
- end
204
-
205
- #
206
- # The number of entries in the subsection.
207
- #
208
- def size
209
- @entries.size
210
- end
211
-
212
- #
213
- # Outputs self into PDF code.
214
- #
215
- def to_s(eol: $/)
216
- section = "#{@range.begin} #{@range.end - @range.begin + 1}" + eol
217
- @entries.each do |xref|
218
- section << xref.to_s(eol: eol)
219
- end
220
-
221
- section
222
- end
258
+ XRef::Section.new(subsections)
259
+ end
260
+
261
+ #
262
+ # Appends a new subsection.
263
+ # _subsection_:: A XRefSubsection.
264
+ #
265
+ def <<(subsection)
266
+ @subsections << subsection
267
+ end
268
+
269
+ #
270
+ # Returns a XRef associated with a given object.
271
+ # _no_:: The Object number.
272
+ #
273
+ def [](no)
274
+ @subsections.each do |s|
275
+ return s[no] if s.has_object?(no)
223
276
  end
224
277
 
225
- class InvalidXRefSectionError < Error #:nodoc:
278
+ nil
279
+ end
280
+ alias_method :find, :[]
281
+
282
+ #
283
+ # Processes each XRef in each Subsection.
284
+ #
285
+ def each(&b)
286
+ return enum_for(__method__) { size } unless block_given?
287
+
288
+ @subsections.each do |subsection|
289
+ subsection.each(&b)
226
290
  end
291
+ end
227
292
 
228
- #
229
- # Class representing a Cross-reference table.
230
- # A section contains a set of XRef::Subsection.
231
- #
232
- class Section
233
- include Enumerable
234
-
235
- TOKEN = "xref"
236
-
237
- @@regexp_open = Regexp.new(WHITESPACES + TOKEN + WHITESPACES + "(\\r?\\n|\\r\\n?)")
238
- @@regexp_sub = Regexp.new("(\\d+) (\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
239
-
240
- #
241
- # Creates a new XRef section.
242
- # _subsections_:: An array of XRefSubsection.
243
- #
244
- def initialize(subsections = [])
245
- @subsections = subsections
246
- end
247
-
248
- def self.parse(stream) #:nodoc:
249
- scanner = Parser.init_scanner(stream)
250
-
251
- if scanner.skip(@@regexp_open).nil?
252
- raise InvalidXRefSectionError, "No xref token found"
253
- end
254
-
255
- subsections = []
256
- while scanner.match?(@@regexp_sub) do
257
- subsections << XRef::Subsection.parse(scanner)
258
- end
259
-
260
- XRef::Section.new(subsections)
261
- end
262
-
263
- #
264
- # Appends a new subsection.
265
- # _subsection_:: A XRefSubsection.
266
- #
267
- def <<(subsection)
268
- @subsections << subsection
269
- end
270
-
271
- #
272
- # Returns a XRef associated with a given object.
273
- # _no_:: The Object number.
274
- #
275
- def [](no)
276
- @subsections.each do |s|
277
- return s[no] if s.has_object?(no)
278
- end
279
-
280
- nil
281
- end
282
- alias find []
283
-
284
- #
285
- # Processes each XRef in each Subsection.
286
- #
287
- def each(&b)
288
- return enum_for(__method__) { self.size } unless block_given?
289
-
290
- @subsections.each do |subsection|
291
- subsection.each(&b)
292
- end
293
- end
294
-
295
- #
296
- # Processes each XRef in each Subsection, passing the XRef and the object number.
297
- #
298
- def each_with_number(&b)
299
- return enum_for(__method__) { self.size } unless block_given?
300
-
301
- @subsections.each do |subsection|
302
- subsection.each_with_number(&b)
303
- end
304
- end
305
-
306
- #
307
- # Processes each Subsection in this table.
308
- #
309
- def each_subsection(&b)
310
- @subsections.each(&b)
311
- end
312
-
313
- #
314
- # Returns an Array of Subsection.
315
- #
316
- def subsections
317
- @subsections
318
- end
319
-
320
- #
321
- # Clear all the entries.
322
- #
323
- def clear
324
- @subsections.clear
325
- end
326
-
327
- #
328
- # The number of XRef entries in the Section.
329
- #
330
- def size
331
- @subsections.reduce(0) { |total, subsection| total + subsection.size }
332
- end
333
-
334
- #
335
- # Outputs self into PDF code.
336
- #
337
- def to_s(eol: $/)
338
- "xref" << eol << @subsections.map{|sub| sub.to_s(eol: eol)}.join
339
- end
293
+ #
294
+ # Processes each XRef in each Subsection, passing the XRef and the object number.
295
+ #
296
+ def each_with_number(&b)
297
+ return enum_for(__method__) { size } unless block_given?
298
+
299
+ @subsections.each do |subsection|
300
+ subsection.each_with_number(&b)
340
301
  end
302
+ end
303
+
304
+ #
305
+ # Processes each Subsection in this table.
306
+ #
307
+ def each_subsection(&b)
308
+ @subsections.each(&b)
309
+ end
310
+
311
+ #
312
+ # Returns an Array of Subsection.
313
+ #
314
+ attr_reader :subsections
315
+
316
+ #
317
+ # Clear all the entries.
318
+ #
319
+ def clear
320
+ @subsections.clear
321
+ end
322
+
323
+ #
324
+ # The number of XRef entries in the Section.
325
+ #
326
+ def size
327
+ @subsections.reduce(0) { |total, subsection| total + subsection.size }
328
+ end
329
+
330
+ #
331
+ # Outputs self into PDF code.
332
+ #
333
+ def to_s(eol: $/)
334
+ result = +"xref"
335
+ result << eol << @subsections.map { |sub| sub.to_s(eol: eol) }.join
336
+ result
337
+ end
341
338
  end
339
+ end
342
340
 
343
- #
344
- # An xref poiting to an Object embedded in an ObjectStream.
345
- #
346
- class XRefToCompressedObject
347
- attr_accessor :objstmno, :index
341
+ #
342
+ # An xref poiting to an Object embedded in an ObjectStream.
343
+ #
344
+ class XRefToCompressedObject
345
+ attr_accessor :objstmno, :index
348
346
 
349
- def initialize(objstmno, index)
350
- @objstmno = objstmno
351
- @index = index
352
- end
347
+ def initialize(objstmno, index)
348
+ @objstmno = objstmno
349
+ @index = index
350
+ end
353
351
 
354
- def to_xrefstm_data(type_w, field1_w, field2_w)
355
- type_w <<= 3
356
- field1_w <<= 3
357
- field2_w <<= 3
352
+ def to_xrefstm_data(type_w, field1_w, field2_w)
353
+ type_w <<= 3
354
+ field1_w <<= 3
355
+ field2_w <<= 3
358
356
 
359
- type = "\002".unpack("B#{type_w}")[0]
360
- objstmno = @objstmno.to_s(2).rjust(field1_w, '0')
361
- index = @index.to_s(2).rjust(field2_w, '0')
357
+ type = "\002".unpack1("B#{type_w}")
358
+ objstmno = @objstmno.to_s(2).rjust(field1_w, '0')
359
+ index = @index.to_s(2).rjust(field2_w, '0')
362
360
 
363
- [ type , objstmno, index ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
364
- end
361
+ [type, objstmno, index].pack("B#{type_w}B#{field1_w}B#{field2_w}")
362
+ end
363
+
364
+ def used?
365
+ true
366
+ end
365
367
 
366
- def used?; true end
367
- def free?; false end
368
+ def free?
369
+ false
368
370
  end
371
+ end
369
372
 
370
- class InvalidXRefStreamObjectError < InvalidStreamObjectError ; end
373
+ class InvalidXRefStreamObjectError < InvalidStreamObjectError; end
374
+
375
+ #
376
+ # Class representing a XRef Stream.
377
+ #
378
+ class XRefStream < Stream
379
+ include Enumerable
380
+ include StandardObject
381
+
382
+ XREF_FREE = 0
383
+ XREF_USED = 1
384
+ XREF_COMPRESSED = 2
371
385
 
372
386
  #
373
- # Class representing a XRef Stream.
387
+ # Xref fields
374
388
  #
375
- class XRefStream < Stream
376
- include Enumerable
377
- include StandardObject
389
+ field :Type, Type: Name, Default: :XRef, Required: true, Version: "1.5"
390
+ field :Size, Type: Integer, Required: true
391
+ field :Index, Type: Array.of(Integer, Integer)
392
+ field :Prev, Type: Integer
393
+ field :W, Type: Array.of(Integer, length: 3), Required: true
378
394
 
379
- XREF_FREE = 0
380
- XREF_USED = 1
381
- XREF_COMPRESSED = 2
395
+ #
396
+ # Trailer fields
397
+ #
398
+ field :Root, Type: Catalog, Required: true
399
+ field :Encrypt, Type: Encryption::Standard::Dictionary
400
+ field :Info, Type: Metadata
401
+ field :ID, Type: Array.of(String, length: 2)
382
402
 
383
- #
384
- # Xref fields
385
- #
386
- field :Type, :Type => Name, :Default => :XRef, :Required => true, :Version => "1.5"
387
- field :Size, :Type => Integer, :Required => true
388
- field :Index, :Type => Array.of(Integer, Integer)
389
- field :Prev, :Type => Integer
390
- field :W, :Type => Array.of(Integer, length: 3), :Required => true
403
+ def initialize(data = "", dictionary = {})
404
+ super
391
405
 
392
- #
393
- # Trailer fields
394
- #
395
- field :Root, :Type => Catalog, :Required => true
396
- field :Encrypt, :Type => Encryption::Standard::Dictionary
397
- field :Info, :Type => Metadata
398
- field :ID, :Type => Array.of(String, length: 2)
406
+ @xrefs = nil
407
+ end
399
408
 
400
- def initialize(data = "", dictionary = {})
401
- super(data, dictionary)
409
+ def entries
410
+ load! if @xrefs.nil?
402
411
 
403
- @xrefs = nil
404
- end
412
+ @xrefs
413
+ end
405
414
 
406
- def entries
407
- load! if @xrefs.nil?
415
+ #
416
+ # Returns XRef entries present in this stream.
417
+ #
418
+ def pre_build # :nodoc:
419
+ load! if @xrefs.nil?
408
420
 
409
- @xrefs
410
- end
421
+ self.W = [1, 2, 2] unless key?(:W)
422
+ self.Size = @xrefs.length + 1
411
423
 
412
- #
413
- # Returns XRef entries present in this stream.
414
- #
415
- def pre_build #:nodoc:
416
- load! if @xrefs.nil?
424
+ save!
417
425
 
418
- self.W = [ 1, 2, 2 ] unless self.key?(:W)
419
- self.Size = @xrefs.length + 1
426
+ super
427
+ end
420
428
 
421
- save!
429
+ #
430
+ # Adds an XRef to this Stream.
431
+ #
432
+ def <<(xref)
433
+ load! if @xrefs.nil?
422
434
 
423
- super
424
- end
435
+ @xrefs << xref
436
+ end
425
437
 
426
- #
427
- # Adds an XRef to this Stream.
428
- #
429
- def <<(xref)
430
- load! if @xrefs.nil?
438
+ #
439
+ # Iterates over each XRef present in the stream.
440
+ #
441
+ def each(&b)
442
+ load! if @xrefs.nil?
431
443
 
432
- @xrefs << xref
433
- end
444
+ @xrefs.each(&b)
445
+ end
446
+
447
+ #
448
+ # Iterates over each XRef present in the stream, passing the XRef and its object number.
449
+ #
450
+ def each_with_number
451
+ return enum_for(__method__) unless block_given?
434
452
 
435
- #
436
- # Iterates over each XRef present in the stream.
437
- #
438
- def each(&b)
439
- load! if @xrefs.nil?
453
+ load! if @xrefs.nil?
440
454
 
441
- @xrefs.each(&b)
442
- end
455
+ ranges = object_ranges
456
+ xrefs = @xrefs.to_enum
443
457
 
444
- #
445
- # Iterates over each XRef present in the stream, passing the XRef and its object number.
446
- #
447
- def each_with_number
448
- return enum_for(__method__) unless block_given?
449
-
450
- load! if @xrefs.nil?
451
-
452
- ranges = object_ranges
453
- xrefs = @xrefs.to_enum
454
-
455
- ranges.each do |range|
456
- range.each do |no|
457
- begin
458
- yield(xrefs.next, no)
459
- rescue StopIteration
460
- raise InvalidXRefStreamObjectError, "Range is bigger than number of entries"
461
- end
462
- end
463
- end
458
+ ranges.each do |range|
459
+ range.each do |no|
460
+ yield(xrefs.next, no)
461
+ rescue StopIteration
462
+ raise InvalidXRefStreamObjectError, "Range is bigger than number of entries"
464
463
  end
464
+ end
465
+ end
465
466
 
466
- #
467
- # Returns an XRef matching this object number.
468
- #
469
- def find(no)
470
- load! if @xrefs.nil?
471
-
472
- ranges = object_ranges
467
+ #
468
+ # Returns an XRef matching this object number.
469
+ #
470
+ def find(no)
471
+ load! if @xrefs.nil?
473
472
 
474
- index = 0
475
- ranges.each do |range|
476
- return @xrefs[index + no - range.begin] if range.cover?(no)
473
+ ranges = object_ranges
477
474
 
478
- index += range.size
479
- end
475
+ index = 0
476
+ ranges.each do |range|
477
+ return @xrefs[index + no - range.begin] if range.cover?(no)
480
478
 
481
- nil
482
- end
479
+ index += range.size
480
+ end
483
481
 
484
- def clear
485
- self.data = ''
486
- @xrefs = []
487
- self.Index = []
488
- end
482
+ nil
483
+ end
489
484
 
490
- private
485
+ def clear
486
+ self.data = ''
487
+ @xrefs = []
488
+ self.Index = []
489
+ end
491
490
 
492
- def object_ranges
493
- load! if @xrefs.nil?
491
+ private
494
492
 
495
- if self.key?(:Index)
496
- ranges = self.Index
497
- unless ranges.is_a?(Array) and ranges.length.even? and ranges.all?{|i| i.is_a?(Integer)}
498
- raise InvalidXRefStreamObjectError, "Index must be an even Array of integers"
499
- end
493
+ def object_ranges
494
+ load! if @xrefs.nil?
500
495
 
501
- ranges.each_slice(2).map { |start, length| Range.new(start.to_i, start.to_i + length.to_i - 1) }
502
- else
503
- [ 0...@xrefs.size ]
504
- end
496
+ if key?(:Index)
497
+ ranges = self.Index
498
+ unless ranges.is_a?(Array) && ranges.length.even? && ranges.all? { |i| i.is_a?(Integer) }
499
+ raise InvalidXRefStreamObjectError, "Index must be an even Array of integers"
505
500
  end
506
501
 
507
- def load! #:nodoc:
508
- if @xrefs.nil? and self.key?(:W)
509
- decode!
510
-
511
- type_w, field1_w, field2_w = field_widths
512
-
513
- entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
514
- size = @data.size / (type_w + field1_w + field2_w)
515
-
516
- xentries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
517
-
518
- @xrefs = []
519
- xentries.each_slice(3) do |type, field1, field2|
520
- case type
521
- when XREF_FREE
522
- @xrefs << XRef.new(field1, field2, XRef::FREE)
523
- when XREF_USED
524
- @xrefs << XRef.new(field1, field2, XRef::USED)
525
- when XREF_COMPRESSED
526
- @xrefs << XRefToCompressedObject.new(field1, field2)
527
- end
528
- end
529
- else
530
- @xrefs = []
531
- end
532
- end
502
+ ranges.each_slice(2).map { |start, length| Range.new(start.to_i, start.to_i + length.to_i - 1) }
503
+ else
504
+ [0...@xrefs.size]
505
+ end
506
+ end
533
507
 
534
- def save! #:nodoc:
535
- self.data = ""
508
+ def load! # :nodoc:
509
+ if @xrefs.nil? && key?(:W)
510
+ decode!
536
511
 
537
- type_w, field1_w, field2_w = self.W
538
- @xrefs.each do |xref| @data << xref.to_xrefstm_data(type_w, field1_w, field2_w) end
512
+ type_w, field1_w, field2_w = field_widths
539
513
 
540
- encode!
514
+ entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
515
+ size = @data.size / (type_w + field1_w + field2_w)
516
+
517
+ xentries = @data.unpack(entrymask * size).map! { |field| field.to_i(2) }
518
+
519
+ @xrefs = []
520
+ xentries.each_slice(3) do |type, field1, field2|
521
+ case type
522
+ when XREF_FREE
523
+ @xrefs << XRef.new(field1, field2, XRef::FREE)
524
+ when XREF_USED
525
+ @xrefs << XRef.new(field1, field2, XRef::USED)
526
+ when XREF_COMPRESSED
527
+ @xrefs << XRefToCompressedObject.new(field1, field2)
528
+ end
541
529
  end
530
+ else
531
+ @xrefs = []
532
+ end
533
+ end
542
534
 
543
- #
544
- # Check and return the internal field widths.
545
- #
546
- def field_widths
547
- widths = self.W
535
+ def save! # :nodoc:
536
+ self.data = +""
548
537
 
549
- unless widths.is_a?(Array) and widths.length == 3 and widths.all? {|w| w.is_a?(Integer) and w >= 0 }
550
- raise InvalidXRefStreamObjectError, "Invalid W field: #{widths}"
551
- end
538
+ type_w, field1_w, field2_w = self.W
539
+ @xrefs.each do |xref| @data << xref.to_xrefstm_data(type_w, field1_w, field2_w) end
552
540
 
553
- widths
554
- end
541
+ encode!
555
542
  end
556
543
 
544
+ #
545
+ # Check and return the internal field widths.
546
+ #
547
+ def field_widths
548
+ widths = self.W
549
+
550
+ unless widths.is_a?(Array) && (widths.length == 3) && widths.all? { |w| w.is_a?(Integer) && (w >= 0) }
551
+ raise InvalidXRefStreamObjectError, "Invalid W field: #{widths}"
552
+ end
553
+
554
+ widths
555
+ end
556
+ end
557
557
  end