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
data/lib/origami/filters.rb
CHANGED
@@ -1,364 +1,358 @@
|
|
1
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
43
|
+
#
|
44
|
+
# Base class for filter Exceptions.
|
45
|
+
#
|
46
|
+
class Error < Origami::Error
|
47
|
+
attr_accessor :input_data, :decoded_data
|
15
48
|
|
16
|
-
|
17
|
-
|
49
|
+
def initialize(message, input_data: nil, decoded_data: nil)
|
50
|
+
super(message)
|
18
51
|
|
19
|
-
=
|
52
|
+
@input_data, @decoded_data = input_data, decoded_data
|
53
|
+
end
|
54
|
+
end
|
20
55
|
|
21
|
-
|
56
|
+
#
|
57
|
+
# Exception class for unsupported filters or unsupported filter parameters.
|
58
|
+
#
|
59
|
+
class NotImplementedError < Error; end
|
22
60
|
|
23
61
|
#
|
24
|
-
#
|
62
|
+
# Exception class for errors occuring during decode operations.
|
25
63
|
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
#
|
117
|
+
# Outputs the stream as a String.
|
48
118
|
#
|
49
|
-
|
50
|
-
|
119
|
+
def to_s
|
120
|
+
@data.dup
|
121
|
+
end
|
51
122
|
|
52
|
-
|
53
|
-
super(message)
|
123
|
+
private
|
54
124
|
|
55
|
-
|
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
|
-
#
|
175
|
+
# Resets the read pointer.
|
61
176
|
#
|
62
|
-
|
177
|
+
def reset
|
178
|
+
@ptr_byte, @ptr_bit = 0, 0
|
179
|
+
self
|
180
|
+
end
|
63
181
|
|
64
182
|
#
|
65
|
-
#
|
183
|
+
# Returns true if end of data has been reached.
|
66
184
|
#
|
67
|
-
|
185
|
+
def eod?
|
186
|
+
@ptr_byte >= @data.size
|
187
|
+
end
|
68
188
|
|
69
|
-
|
189
|
+
#
|
190
|
+
# Returns the read pointer position in bits.
|
191
|
+
#
|
192
|
+
def pos
|
193
|
+
(@ptr_byte << 3) + @ptr_bit
|
194
|
+
end
|
70
195
|
|
71
|
-
|
72
|
-
|
196
|
+
#
|
197
|
+
# Returns the data size in bits.
|
198
|
+
#
|
199
|
+
def size
|
200
|
+
@data.size << 3
|
201
|
+
end
|
73
202
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
162
|
-
|
209
|
+
pbyte = bits >> 3
|
210
|
+
pbit = bits - (pbyte << 3)
|
211
|
+
@ptr_byte, @ptr_bit = pbyte, pbit
|
212
|
+
end
|
163
213
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
-
|
356
|
-
|
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
|
-
|
360
|
-
|
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
|