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,364 +1,358 @@
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é.
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.
21
+ module Origami
22
+ #
23
+ # Filters are algorithms used to encode data into a PDF Stream.
24
+ #
25
+ module Filter
26
+ autoload :ASCIIHex, "origami/filters/ascii"
27
+ autoload :AHx, "origami/filters/ascii"
28
+ autoload :ASCII85, "origami/filters/ascii"
29
+ autoload :A85, "origami/filters/ascii"
30
+ autoload :CCITTFax, "origami/filters/ccitt"
31
+ autoload :CCF, "origami/filters/ccitt"
32
+ autoload :Crypt, "origami/filters/crypt"
33
+ autoload :DCT, "origami/filters/dct"
34
+ autoload :Flate, "origami/filters/flate"
35
+ autoload :Fl, "origami/filters/flate"
36
+ autoload :JBIG2, "origami/filters/jbig2"
37
+ autoload :JPX, "origami/filters/jpx"
38
+ autoload :LZW, "origami/filters/lzw"
39
+ autoload :RunLength, "origami/filters/runlength"
40
+ autoload :RL, "origami/filters/runlength"
41
+ autoload :Predictor, "origami/filters/predictors"
10
42
 
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.
43
+ #
44
+ # Base class for filter Exceptions.
45
+ #
46
+ class Error < Origami::Error
47
+ attr_accessor :input_data, :decoded_data
15
48
 
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/>.
49
+ def initialize(message, input_data: nil, decoded_data: nil)
50
+ super(message)
18
51
 
19
- =end
52
+ @input_data, @decoded_data = input_data, decoded_data
53
+ end
54
+ end
20
55
 
21
- module Origami
56
+ #
57
+ # Exception class for unsupported filters or unsupported filter parameters.
58
+ #
59
+ class NotImplementedError < Error; end
22
60
 
23
61
  #
24
- # Filters are algorithms used to encode data into a PDF Stream.
62
+ # Exception class for errors occuring during decode operations.
25
63
  #
26
- module Filter
27
-
28
- autoload :ASCIIHex, "origami/filters/ascii"
29
- autoload :AHx, "origami/filters/ascii"
30
- autoload :ASCII85, "origami/filters/ascii"
31
- autoload :A85, "origami/filters/ascii"
32
- autoload :CCITTFax, "origami/filters/ccitt"
33
- autoload :CCF, "origami/filters/ccitt"
34
- autoload :Crypt, "origami/filters/crypt"
35
- autoload :DCT, "origami/filters/dct"
36
- autoload :Flate, "origami/filters/flate"
37
- autoload :Fl, "origami/filters/flate"
38
- autoload :JBIG2, "origami/filters/jbig2"
39
- autoload :JPX, "origami/filters/jpx"
40
- autoload :LZW, "origami/filters/lzw"
41
- autoload :RunLength, "origami/filters/runlength"
42
- autoload :RL, "origami/filters/runlength"
43
- autoload :Predictor, "origami/filters/predictors"
64
+ class DecodeError < Error; end
65
+
66
+ module Utils
67
+ class BitWriterError < Error # :nodoc:
68
+ end
69
+
70
+ #
71
+ # Class used to forge a String from a stream of bits.
72
+ # Internally used by some filters.
73
+ #
74
+ class BitWriter
75
+ def initialize
76
+ @data = ''.b
77
+ @last_byte = nil
78
+ @ptr_bit = 0
79
+ end
80
+
81
+ #
82
+ # Writes _data_ represented as Fixnum to a _length_ number of bits.
83
+ #
84
+ def write(data, length)
85
+ return BitWriterError, "Invalid data length" unless (length > 0) && (length >= data.bit_length)
86
+
87
+ # optimization for aligned byte writing
88
+ if (length == 8) && @last_byte.nil? && (@ptr_bit == 0)
89
+ @data << data.chr
90
+ return self
91
+ end
92
+
93
+ write_bits(data, length)
94
+
95
+ self
96
+ end
97
+
98
+ #
99
+ # Returns the data size in bits.
100
+ #
101
+ def size
102
+ (@data.size << 3) + @ptr_bit
103
+ end
104
+
105
+ #
106
+ # Finalizes the stream.
107
+ #
108
+ def final
109
+ @data << @last_byte.chr if @last_byte
110
+ @last_byte = nil
111
+ @p = 0
44
112
 
113
+ self
114
+ end
45
115
 
46
116
  #
47
- # Base class for filter Exceptions.
117
+ # Outputs the stream as a String.
48
118
  #
49
- class Error < Origami::Error
50
- attr_accessor :input_data, :decoded_data
119
+ def to_s
120
+ @data.dup
121
+ end
51
122
 
52
- def initialize(message, input_data: nil, decoded_data: nil)
53
- super(message)
123
+ private
54
124
 
55
- @input_data, @decoded_data = input_data, decoded_data
125
+ #
126
+ # Write the bits into the internal data.
127
+ #
128
+ def write_bits(data, length)
129
+ while length > 0
130
+ if length >= 8 - @ptr_bit
131
+ length -= 8 - @ptr_bit
132
+ @last_byte ||= 0
133
+ @last_byte |= (data >> length) & ((1 << (8 - @ptr_bit)) - 1)
134
+
135
+ data &= (1 << length) - 1
136
+ @data << @last_byte.chr
137
+ @last_byte = nil
138
+ @ptr_bit = 0
139
+ else
140
+ @last_byte ||= 0
141
+ @last_byte |= (data & ((1 << length) - 1)) << (8 - @ptr_bit - length)
142
+ @ptr_bit += length
143
+
144
+ if @ptr_bit == 8
145
+ @data << @last_byte.chr
146
+ @last_byte = nil
147
+ @ptr_bit = 0
148
+ end
149
+
150
+ length = 0
56
151
  end
152
+ end
153
+ end
154
+ end
155
+
156
+ class BitReaderError < Error # :nodoc:
157
+ end
158
+
159
+ #
160
+ # Class used to read a String as a stream of bits.
161
+ # Internally used by some filters.
162
+ #
163
+ class BitReader
164
+ BRUIJIN_TABLE = ::Array.new(32)
165
+ BRUIJIN_TABLE.size.times do |i|
166
+ BRUIJIN_TABLE[((0x77cb531 * (1 << i)) >> 27) & 31] = i
167
+ end
168
+
169
+ def initialize(data)
170
+ @data = data
171
+ reset
57
172
  end
58
173
 
59
174
  #
60
- # Exception class for unsupported filters or unsupported filter parameters.
175
+ # Resets the read pointer.
61
176
  #
62
- class NotImplementedError < Error; end
177
+ def reset
178
+ @ptr_byte, @ptr_bit = 0, 0
179
+ self
180
+ end
63
181
 
64
182
  #
65
- # Exception class for errors occuring during decode operations.
183
+ # Returns true if end of data has been reached.
66
184
  #
67
- class DecodeError < Error; end
185
+ def eod?
186
+ @ptr_byte >= @data.size
187
+ end
68
188
 
69
- module Utils
189
+ #
190
+ # Returns the read pointer position in bits.
191
+ #
192
+ def pos
193
+ (@ptr_byte << 3) + @ptr_bit
194
+ end
70
195
 
71
- class BitWriterError < Error #:nodoc:
72
- end
196
+ #
197
+ # Returns the data size in bits.
198
+ #
199
+ def size
200
+ @data.size << 3
201
+ end
73
202
 
74
- #
75
- # Class used to forge a String from a stream of bits.
76
- # Internally used by some filters.
77
- #
78
- class BitWriter
79
- def initialize
80
- @data = ''.b
81
- @last_byte = nil
82
- @ptr_bit = 0
83
- end
84
-
85
- #
86
- # Writes _data_ represented as Fixnum to a _length_ number of bits.
87
- #
88
- def write(data, length)
89
- return BitWriterError, "Invalid data length" unless length > 0 and length >= data.bit_length
90
-
91
- # optimization for aligned byte writing
92
- if length == 8 and @last_byte.nil? and @ptr_bit == 0
93
- @data << data.chr
94
- return self
95
- end
96
-
97
- write_bits(data, length)
98
-
99
- self
100
- end
101
-
102
- #
103
- # Returns the data size in bits.
104
- #
105
- def size
106
- (@data.size << 3) + @ptr_bit
107
- end
108
-
109
- #
110
- # Finalizes the stream.
111
- #
112
- def final
113
- @data << @last_byte.chr if @last_byte
114
- @last_byte = nil
115
- @p = 0
116
-
117
- self
118
- end
119
-
120
- #
121
- # Outputs the stream as a String.
122
- #
123
- def to_s
124
- @data.dup
125
- end
126
-
127
- private
128
-
129
- #
130
- # Write the bits into the internal data.
131
- #
132
- def write_bits(data, length)
133
-
134
- while length > 0
135
- if length >= 8 - @ptr_bit
136
- length -= 8 - @ptr_bit
137
- @last_byte ||= 0
138
- @last_byte |= (data >> length) & ((1 << (8 - @ptr_bit)) - 1)
139
-
140
- data &= (1 << length) - 1
141
- @data << @last_byte.chr
142
- @last_byte = nil
143
- @ptr_bit = 0
144
- else
145
- @last_byte ||= 0
146
- @last_byte |= (data & ((1 << length) - 1)) << (8 - @ptr_bit - length)
147
- @ptr_bit += length
148
-
149
- if @ptr_bit == 8
150
- @data << @last_byte.chr
151
- @last_byte = nil
152
- @ptr_bit = 0
153
- end
154
-
155
- length = 0
156
- end
157
- end
158
- end
159
- end
203
+ #
204
+ # Sets the read pointer position in bits.
205
+ #
206
+ def pos=(bits)
207
+ raise BitReaderError, "Pointer position out of data" if bits > size
160
208
 
161
- class BitReaderError < Error #:nodoc:
162
- end
209
+ pbyte = bits >> 3
210
+ pbit = bits - (pbyte << 3)
211
+ @ptr_byte, @ptr_bit = pbyte, pbit
212
+ end
163
213
 
164
- #
165
- # Class used to read a String as a stream of bits.
166
- # Internally used by some filters.
167
- #
168
- class BitReader
169
- BRUIJIN_TABLE = ::Array.new(32)
170
- BRUIJIN_TABLE.size.times do |i|
171
- BRUIJIN_TABLE[((0x77cb531 * (1 << i)) >> 27) & 31] = i
172
- end
173
-
174
- def initialize(data)
175
- @data = data
176
- reset
177
- end
178
-
179
- #
180
- # Resets the read pointer.
181
- #
182
- def reset
183
- @ptr_byte, @ptr_bit = 0, 0
184
- self
185
- end
186
-
187
- #
188
- # Returns true if end of data has been reached.
189
- #
190
- def eod?
191
- @ptr_byte >= @data.size
192
- end
193
-
194
- #
195
- # Returns the read pointer position in bits.
196
- #
197
- def pos
198
- (@ptr_byte << 3) + @ptr_bit
199
- end
200
-
201
- #
202
- # Returns the data size in bits.
203
- #
204
- def size
205
- @data.size << 3
206
- end
207
-
208
- #
209
- # Sets the read pointer position in bits.
210
- #
211
- def pos=(bits)
212
- raise BitReaderError, "Pointer position out of data" if bits > self.size
213
-
214
- pbyte = bits >> 3
215
- pbit = bits - (pbyte << 3)
216
- @ptr_byte, @ptr_bit = pbyte, pbit
217
- end
218
-
219
- #
220
- # Reads _length_ bits as a Fixnum and advances read pointer.
221
- #
222
- def read(length)
223
- n = self.peek(length)
224
- self.pos += length
225
-
226
- n
227
- end
228
-
229
- #
230
- # Reads _length_ bits as a Fixnum. Does not advance read pointer.
231
- #
232
- def peek(length)
233
- return BitReaderError, "Invalid read length" unless length > 0
234
- return BitReaderError, "Insufficient data" if self.pos + length > self.size
235
-
236
- n = 0
237
- ptr_byte, ptr_bit = @ptr_byte, @ptr_bit
238
-
239
- while length > 0
240
- byte = @data[ptr_byte].ord
241
-
242
- if length > 8 - ptr_bit
243
- length -= 8 - ptr_bit
244
- n |= ( byte & ((1 << (8 - ptr_bit)) - 1) ) << length
245
-
246
- ptr_byte += 1
247
- ptr_bit = 0
248
- else
249
- n |= (byte >> (8 - ptr_bit - length)) & ((1 << length) - 1)
250
- length = 0
251
- end
252
- end
253
-
254
- n
255
- end
256
-
257
- #
258
- # Used for bit scanning.
259
- # Counts leading zeros. Does not advance read pointer.
260
- #
261
- def clz
262
- count = 0
263
- if @ptr_bit != 0
264
- bits = peek(8 - @ptr_bit)
265
- count = clz32(bits << (32 - (8 - @ptr_bit)))
266
-
267
- return count if count < (8 - @ptr_bit)
268
- end
269
-
270
- delta = 0
271
- while @data.size > @ptr_byte + delta * 4
272
- word = @data[@ptr_byte + delta * 4, 4] # next 32 bits
273
- z = clz32((word << (4 - word.size)).unpack("N")[0])
274
-
275
- count += z
276
- delta += 1
277
-
278
- return count if z < 32 - ((4 - word.size) << 3)
279
- end
280
-
281
- count
282
- end
283
-
284
- #
285
- # Used for bit scanning.
286
- # Count leading ones. Does not advance read pointer.
287
- #
288
- def clo
289
- count = 0
290
- if @ptr_bit != 0
291
- bits = peek(8 - @ptr_bit)
292
- count = clz32(~(bits << (32 - (8 - @ptr_bit))) & 0xff)
293
-
294
- return count if count < (8 - @ptr_bit)
295
- end
296
-
297
- delta = 0
298
- while @data.size > @ptr_byte + delta * 4
299
- word = @data[@ptr_byte + delta * 4, 4] # next 32 bits
300
- z = clz32(~((word << (4 - word.size)).unpack("N")[0]) & 0xffff_ffff)
301
-
302
- count += z
303
- delta += 1
304
-
305
- return count if z < 32 - ((4 - word.size) << 3)
306
- end
307
-
308
- count
309
- end
310
-
311
- private
312
-
313
- def bitswap8(i) #:nodoc
314
- ((i * 0x0202020202) & 0x010884422010) % 1023
315
- end
316
-
317
- def bitswap32(i) #:nodoc:
318
- (bitswap8((i >> 0) & 0xff) << 24) |
319
- (bitswap8((i >> 8) & 0xff) << 16) |
320
- (bitswap8((i >> 16) & 0xff) << 8) |
321
- (bitswap8((i >> 24) & 0xff) << 0)
322
- end
323
-
324
- def ctz32(i) #:nodoc:
325
- if i == 0 then 32
326
- else
327
- BRUIJIN_TABLE[(((i & -i) * 0x77cb531) >> 27) & 31]
328
- end
329
- end
330
-
331
- def clz32(i) #:nodoc:
332
- ctz32 bitswap32 i
333
- end
334
- end
214
+ #
215
+ # Reads _length_ bits as a Fixnum and advances read pointer.
216
+ #
217
+ def read(length)
218
+ n = peek(length)
219
+ self.pos += length
220
+
221
+ n
335
222
  end
336
223
 
337
- module ClassMethods
338
- #
339
- # Decodes the given data.
340
- # _stream_:: The data to decode.
341
- #
342
- def decode(stream, params = {})
343
- self.new(params).decode(stream)
344
- end
224
+ #
225
+ # Reads _length_ bits as a Fixnum. Does not advance read pointer.
226
+ #
227
+ def peek(length)
228
+ return BitReaderError, "Invalid read length" unless length > 0
229
+ return BitReaderError, "Insufficient data" if self.pos + length > size
230
+
231
+ n = 0
232
+ ptr_byte, ptr_bit = @ptr_byte, @ptr_bit
233
+
234
+ while length > 0
235
+ byte = @data[ptr_byte].ord
345
236
 
346
- #
347
- # Encodes the given data.
348
- # _stream_:: The data to encode.
349
- #
350
- def encode(stream, params = {})
351
- self.new(params).encode(stream)
237
+ if length > 8 - ptr_bit
238
+ length -= 8 - ptr_bit
239
+ n |= (byte & ((1 << (8 - ptr_bit)) - 1)) << length
240
+
241
+ ptr_byte += 1
242
+ ptr_bit = 0
243
+ else
244
+ n |= (byte >> (8 - ptr_bit - length)) & ((1 << length) - 1)
245
+ length = 0
352
246
  end
247
+ end
248
+
249
+ n
353
250
  end
354
251
 
355
- def initialize(parameters = {})
356
- @params = parameters
252
+ #
253
+ # Used for bit scanning.
254
+ # Counts leading zeros. Does not advance read pointer.
255
+ #
256
+ def clz
257
+ count = 0
258
+ if @ptr_bit != 0
259
+ bits = peek(8 - @ptr_bit)
260
+ count = clz32(bits << (32 - (8 - @ptr_bit)))
261
+
262
+ return count if count < (8 - @ptr_bit)
263
+ end
264
+
265
+ delta = 0
266
+ while @data.size > @ptr_byte + delta * 4
267
+ word = @data[@ptr_byte + delta * 4, 4] # next 32 bits
268
+ z = clz32((word << (4 - word.size)).unpack1("N"))
269
+
270
+ count += z
271
+ delta += 1
272
+
273
+ return count if z < 32 - ((4 - word.size) << 3)
274
+ end
275
+
276
+ count
357
277
  end
358
278
 
359
- def self.included(receiver)
360
- receiver.extend(ClassMethods)
279
+ #
280
+ # Used for bit scanning.
281
+ # Count leading ones. Does not advance read pointer.
282
+ #
283
+ def clo
284
+ count = 0
285
+ if @ptr_bit != 0
286
+ bits = peek(8 - @ptr_bit)
287
+ count = clz32(~(bits << (32 - (8 - @ptr_bit))) & 0xff)
288
+
289
+ return count if count < (8 - @ptr_bit)
290
+ end
291
+
292
+ delta = 0
293
+ while @data.size > @ptr_byte + delta * 4
294
+ word = @data[@ptr_byte + delta * 4, 4] # next 32 bits
295
+ z = clz32(~(word << (4 - word.size)).unpack1("N") & 0xffff_ffff)
296
+
297
+ count += z
298
+ delta += 1
299
+
300
+ return count if z < 32 - ((4 - word.size) << 3)
301
+ end
302
+
303
+ count
304
+ end
305
+
306
+ private
307
+
308
+ def bitswap8(i) # :nodoc
309
+ ((i * 0x0202020202) & 0x010884422010) % 1023
310
+ end
311
+
312
+ def bitswap32(i) # :nodoc:
313
+ (bitswap8((i >> 0) & 0xff) << 24) |
314
+ (bitswap8((i >> 8) & 0xff) << 16) |
315
+ (bitswap8((i >> 16) & 0xff) << 8) |
316
+ (bitswap8((i >> 24) & 0xff) << 0)
317
+ end
318
+
319
+ def ctz32(i) # :nodoc:
320
+ if i == 0 then 32
321
+ else
322
+ BRUIJIN_TABLE[(((i & -i) * 0x77cb531) >> 27) & 31]
323
+ end
324
+ end
325
+
326
+ def clz32(i) # :nodoc:
327
+ ctz32 bitswap32 i
361
328
  end
329
+ end
362
330
  end
363
331
 
332
+ module ClassMethods
333
+ #
334
+ # Decodes the given data.
335
+ # _stream_:: The data to decode.
336
+ #
337
+ def decode(stream, params = {})
338
+ new(params).decode(stream)
339
+ end
340
+
341
+ #
342
+ # Encodes the given data.
343
+ # _stream_:: The data to encode.
344
+ #
345
+ def encode(stream, params = {})
346
+ new(params).encode(stream)
347
+ end
348
+ end
349
+
350
+ def initialize(parameters = {})
351
+ @params = parameters
352
+ end
353
+
354
+ def self.included(receiver)
355
+ receiver.extend(ClassMethods)
356
+ end
357
+ end
364
358
  end