origami 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/bin/gui/config.rb +2 -1
  4. data/bin/gui/file.rb +118 -240
  5. data/bin/gui/gtkhex.rb +5 -5
  6. data/bin/gui/hexview.rb +20 -16
  7. data/bin/gui/imgview.rb +1 -1
  8. data/bin/gui/menu.rb +138 -158
  9. data/bin/gui/properties.rb +46 -48
  10. data/bin/gui/signing.rb +183 -214
  11. data/bin/gui/textview.rb +1 -1
  12. data/bin/gui/treeview.rb +13 -7
  13. data/bin/gui/walker.rb +102 -71
  14. data/bin/gui/xrefs.rb +1 -1
  15. data/bin/pdf2ruby +3 -3
  16. data/bin/pdfcop +18 -11
  17. data/bin/pdfextract +14 -5
  18. data/bin/pdfmetadata +3 -3
  19. data/bin/shell/console.rb +8 -8
  20. data/bin/shell/hexdump.rb +4 -4
  21. data/examples/attachments/nested_document.rb +1 -1
  22. data/examples/javascript/hello_world.rb +3 -3
  23. data/lib/origami.rb +0 -1
  24. data/lib/origami/acroform.rb +3 -3
  25. data/lib/origami/array.rb +1 -3
  26. data/lib/origami/boolean.rb +1 -3
  27. data/lib/origami/catalog.rb +3 -9
  28. data/lib/origami/destinations.rb +2 -2
  29. data/lib/origami/dictionary.rb +15 -29
  30. data/lib/origami/encryption.rb +334 -692
  31. data/lib/origami/extensions/fdf.rb +3 -2
  32. data/lib/origami/extensions/ppklite.rb +5 -9
  33. data/lib/origami/filespec.rb +2 -2
  34. data/lib/origami/filters.rb +54 -36
  35. data/lib/origami/filters/ascii.rb +67 -49
  36. data/lib/origami/filters/ccitt.rb +4 -236
  37. data/lib/origami/filters/ccitt/tables.rb +267 -0
  38. data/lib/origami/filters/crypt.rb +1 -1
  39. data/lib/origami/filters/dct.rb +0 -1
  40. data/lib/origami/filters/flate.rb +3 -43
  41. data/lib/origami/filters/lzw.rb +62 -99
  42. data/lib/origami/filters/predictors.rb +135 -105
  43. data/lib/origami/filters/runlength.rb +34 -22
  44. data/lib/origami/graphics.rb +2 -2
  45. data/lib/origami/graphics/colors.rb +89 -63
  46. data/lib/origami/graphics/path.rb +14 -14
  47. data/lib/origami/graphics/patterns.rb +31 -33
  48. data/lib/origami/graphics/render.rb +0 -1
  49. data/lib/origami/graphics/state.rb +9 -9
  50. data/lib/origami/graphics/text.rb +17 -17
  51. data/lib/origami/graphics/xobject.rb +102 -92
  52. data/lib/origami/javascript.rb +91 -68
  53. data/lib/origami/linearization.rb +22 -20
  54. data/lib/origami/metadata.rb +1 -1
  55. data/lib/origami/name.rb +1 -3
  56. data/lib/origami/null.rb +1 -3
  57. data/lib/origami/numeric.rb +3 -13
  58. data/lib/origami/object.rb +100 -72
  59. data/lib/origami/page.rb +24 -28
  60. data/lib/origami/parser.rb +34 -51
  61. data/lib/origami/parsers/fdf.rb +2 -2
  62. data/lib/origami/parsers/pdf.rb +41 -18
  63. data/lib/origami/parsers/pdf/lazy.rb +83 -46
  64. data/lib/origami/parsers/pdf/linear.rb +19 -10
  65. data/lib/origami/parsers/ppklite.rb +1 -1
  66. data/lib/origami/pdf.rb +150 -206
  67. data/lib/origami/reference.rb +4 -6
  68. data/lib/origami/signature.rb +76 -48
  69. data/lib/origami/stream.rb +69 -63
  70. data/lib/origami/string.rb +2 -19
  71. data/lib/origami/trailer.rb +25 -22
  72. data/lib/origami/version.rb +1 -1
  73. data/lib/origami/xfa.rb +6 -4
  74. data/lib/origami/xreftable.rb +29 -29
  75. data/test/test_annotations.rb +16 -38
  76. data/test/test_pdf_attachment.rb +1 -1
  77. data/test/test_pdf_parse.rb +1 -1
  78. data/test/test_xrefs.rb +2 -2
  79. metadata +4 -4
  80. data/lib/origami/export.rb +0 -247
@@ -0,0 +1,267 @@
1
+ =begin
2
+
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ =end
20
+
21
+ module Origami
22
+
23
+ module Filter
24
+
25
+ class CCITTFax
26
+
27
+ def self.codeword(str) #:nodoc:
28
+ [ str.to_i(2), str.length ]
29
+ end
30
+
31
+ WHITE_TERMINAL_ENCODE_TABLE =
32
+ {
33
+ 0 => '00110101',
34
+ 1 => '000111',
35
+ 2 => '0111',
36
+ 3 => '1000',
37
+ 4 => '1011',
38
+ 5 => '1100',
39
+ 6 => '1110',
40
+ 7 => '1111',
41
+ 8 => '10011',
42
+ 9 => '10100',
43
+ 10 => '00111',
44
+ 11 => '01000',
45
+ 12 => '001000',
46
+ 13 => '000011',
47
+ 14 => '110100',
48
+ 15 => '110101',
49
+ 16 => '101010',
50
+ 17 => '101011',
51
+ 18 => '0100111',
52
+ 19 => '0001100',
53
+ 20 => '0001000',
54
+ 21 => '0010111',
55
+ 22 => '0000011',
56
+ 23 => '0000100',
57
+ 24 => '0101000',
58
+ 25 => '0101011',
59
+ 26 => '0010011',
60
+ 27 => '0100100',
61
+ 28 => '0011000',
62
+ 29 => '00000010',
63
+ 30 => '00000011',
64
+ 31 => '00011010',
65
+ 32 => '00011011',
66
+ 33 => '00010010',
67
+ 34 => '00010011',
68
+ 35 => '00010100',
69
+ 36 => '00010101',
70
+ 37 => '00010110',
71
+ 38 => '00010111',
72
+ 39 => '00101000',
73
+ 40 => '00101001',
74
+ 41 => '00101010',
75
+ 42 => '00101011',
76
+ 43 => '00101100',
77
+ 44 => '00101101',
78
+ 45 => '00000100',
79
+ 46 => '00000101',
80
+ 47 => '00001010',
81
+ 48 => '00001011',
82
+ 49 => '01010010',
83
+ 50 => '01010011',
84
+ 51 => '01010100',
85
+ 52 => '01010101',
86
+ 53 => '00100100',
87
+ 54 => '00100101',
88
+ 55 => '01011000',
89
+ 56 => '01011001',
90
+ 57 => '01011010',
91
+ 58 => '01011011',
92
+ 59 => '01001010',
93
+ 60 => '01001011',
94
+ 61 => '00110010',
95
+ 62 => '00110011',
96
+ 63 => '00110100'
97
+ }.map {|length, bits| [length, codeword(bits)]}.to_h
98
+
99
+ WHITE_TERMINAL_DECODE_TABLE = WHITE_TERMINAL_ENCODE_TABLE.invert
100
+
101
+ BLACK_TERMINAL_ENCODE_TABLE =
102
+ {
103
+ 0 => '0000110111',
104
+ 1 => '010',
105
+ 2 => '11',
106
+ 3 => '10',
107
+ 4 => '011',
108
+ 5 => '0011',
109
+ 6 => '0010',
110
+ 7 => '00011',
111
+ 8 => '000101',
112
+ 9 => '000100',
113
+ 10 => '0000100',
114
+ 11 => '0000101',
115
+ 12 => '0000111',
116
+ 13 => '00000100',
117
+ 14 => '00000111',
118
+ 15 => '000011000',
119
+ 16 => '0000010111',
120
+ 17 => '0000011000',
121
+ 18 => '0000001000',
122
+ 19 => '00001100111',
123
+ 20 => '00001101000',
124
+ 21 => '00001101100',
125
+ 22 => '00000110111',
126
+ 23 => '00000101000',
127
+ 24 => '00000010111',
128
+ 25 => '00000011000',
129
+ 26 => '000011001010',
130
+ 27 => '000011001011',
131
+ 28 => '000011001100',
132
+ 29 => '000011001101',
133
+ 30 => '000001101000',
134
+ 31 => '000001101001',
135
+ 32 => '000001101010',
136
+ 33 => '000001101011',
137
+ 34 => '000011010010',
138
+ 35 => '000011010011',
139
+ 36 => '000011010100',
140
+ 37 => '000011010101',
141
+ 38 => '000011010110',
142
+ 39 => '000011010111',
143
+ 40 => '000001101100',
144
+ 41 => '000001101101',
145
+ 42 => '000011011010',
146
+ 43 => '000011011011',
147
+ 44 => '000001010100',
148
+ 45 => '000001010101',
149
+ 46 => '000001010110',
150
+ 47 => '000001010111',
151
+ 48 => '000001100100',
152
+ 49 => '000001100101',
153
+ 50 => '000001010010',
154
+ 51 => '000001010011',
155
+ 52 => '000000100100',
156
+ 53 => '000000110111',
157
+ 54 => '000000111000',
158
+ 55 => '000000100111',
159
+ 56 => '000000101000',
160
+ 57 => '000001011000',
161
+ 58 => '000001011001',
162
+ 59 => '000000101011',
163
+ 60 => '000000101100',
164
+ 61 => '000001011010',
165
+ 62 => '000001100110',
166
+ 63 => '000001100111'
167
+ }.map {|length, bits| [length, codeword(bits)]}.to_h
168
+
169
+ BLACK_TERMINAL_DECODE_TABLE = BLACK_TERMINAL_ENCODE_TABLE.invert
170
+
171
+ WHITE_CONFIGURATION_ENCODE_TABLE =
172
+ {
173
+ 64 => '11011',
174
+ 128 => '10010',
175
+ 192 => '010111',
176
+ 256 => '0110111',
177
+ 320 => '00110110',
178
+ 384 => '00110111',
179
+ 448 => '01100100',
180
+ 512 => '01100101',
181
+ 576 => '01101000',
182
+ 640 => '01100111',
183
+ 704 => '011001100',
184
+ 768 => '011001101',
185
+ 832 => '011010010',
186
+ 896 => '011010011',
187
+ 960 => '011010100',
188
+ 1024 => '011010101',
189
+ 1088 => '011010110',
190
+ 1152 => '011010111',
191
+ 1216 => '011011000',
192
+ 1280 => '011011001',
193
+ 1344 => '011011010',
194
+ 1408 => '011011011',
195
+ 1472 => '010011000',
196
+ 1536 => '010011001',
197
+ 1600 => '010011010',
198
+ 1664 => '011000',
199
+ 1728 => '010011011',
200
+
201
+ 1792 => '00000001000',
202
+ 1856 => '00000001100',
203
+ 1920 => '00000001001',
204
+ 1984 => '000000010010',
205
+ 2048 => '000000010011',
206
+ 2112 => '000000010100',
207
+ 2176 => '000000010101',
208
+ 2240 => '000000010110',
209
+ 2340 => '000000010111',
210
+ 2368 => '000000011100',
211
+ 2432 => '000000011101',
212
+ 2496 => '000000011110',
213
+ 2560 => '000000011111'
214
+ }.map {|length, bits| [length, codeword(bits)]}.to_h
215
+
216
+ WHITE_CONFIGURATION_DECODE_TABLE = WHITE_CONFIGURATION_ENCODE_TABLE.invert
217
+
218
+ BLACK_CONFIGURATION_ENCODE_TABLE =
219
+ {
220
+ 64 => '0000001111',
221
+ 128 => '000011001000',
222
+ 192 => '000011001001',
223
+ 256 => '000001011011',
224
+ 320 => '000000110011',
225
+ 384 => '000000110100',
226
+ 448 => '000000110101',
227
+ 512 => '0000001101100',
228
+ 576 => '0000001101101',
229
+ 640 => '0000001001010',
230
+ 704 => '0000001001011',
231
+ 768 => '0000001001100',
232
+ 832 => '0000001001101',
233
+ 896 => '0000001110010',
234
+ 960 => '0000001110011',
235
+ 1024 => '0000001110100',
236
+ 1088 => '0000001110101',
237
+ 1152 => '0000001110110',
238
+ 1216 => '0000001110111',
239
+ 1280 => '0000001010010',
240
+ 1344 => '0000001010011',
241
+ 1408 => '0000001010100',
242
+ 1472 => '0000001010101',
243
+ 1536 => '0000001011010',
244
+ 1600 => '0000001011011',
245
+ 1664 => '0000001100100',
246
+ 1728 => '0000001100101',
247
+
248
+ 1792 => '00000001000',
249
+ 1856 => '00000001100',
250
+ 1920 => '00000001001',
251
+ 1984 => '000000010010',
252
+ 2048 => '000000010011',
253
+ 2112 => '000000010100',
254
+ 2176 => '000000010101',
255
+ 2240 => '000000010110',
256
+ 2340 => '000000010111',
257
+ 2368 => '000000011100',
258
+ 2432 => '000000011101',
259
+ 2496 => '000000011110',
260
+ 2560 => '000000011111'
261
+ }.map {|length, bits| [length, codeword(bits)]}.to_h
262
+
263
+ BLACK_CONFIGURATION_DECODE_TABLE = BLACK_CONFIGURATION_ENCODE_TABLE.invert
264
+ end
265
+
266
+ end
267
+ end
@@ -30,7 +30,7 @@ module Origami
30
30
  class DecodeParms < Dictionary
31
31
  include StandardObject
32
32
 
33
- field :Type, :Type => Name, :Default => :Crypt
33
+ field :Type, :Type => Name, :Default => :CryptFilterDecodeParms
34
34
  field :Name, :Type => Name, :Default => :Identity
35
35
  end
36
36
  end
@@ -52,4 +52,3 @@ module Origami
52
52
 
53
53
  end
54
54
  end
55
-
@@ -32,44 +32,16 @@ module Origami
32
32
  #
33
33
  class Flate
34
34
  include Filter
35
+ include Predictor
35
36
 
36
37
  EOD = 257 #:nodoc:
37
38
 
38
- class DecodeParms < Dictionary
39
- include StandardObject
40
-
41
- field :Predictor, :Type => Integer, :Default => 1
42
- field :Colors, :Type => Integer, :Default => 1
43
- field :BitsPerComponent, :Type => Integer, :Default => 8
44
- field :Columns, :Type => Integer, :Default => 1
45
- end
46
-
47
- #
48
- # Create a new Flate Filter.
49
- # _parameters_:: A hash of filter options (ignored).
50
- #
51
- def initialize(parameters = {})
52
- super(DecodeParms.new(parameters))
53
- end
54
-
55
39
  #
56
40
  # Encodes data using zlib/Deflate compression method.
57
41
  # _stream_:: The data to encode.
58
42
  #
59
43
  def encode(stream)
60
- if @params.Predictor.is_a?(Integer)
61
- colors = @params.Colors.is_a?(Integer) ? @params.Colors.to_i : 1
62
- bpc = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
63
- columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1
64
-
65
- stream = Predictor.do_pre_prediction(stream,
66
- predictor: @params.Predictor.to_i,
67
- colors: colors,
68
- bpc: bpc,
69
- columns: columns)
70
- end
71
-
72
- Zlib::Deflate.deflate(stream, Zlib::BEST_COMPRESSION)
44
+ Zlib::Deflate.deflate(pre_prediction(stream), Zlib::BEST_COMPRESSION)
73
45
  end
74
46
 
75
47
  #
@@ -88,19 +60,7 @@ module Origami
88
60
  end
89
61
  end
90
62
 
91
- if @params.Predictor.is_a?(Integer)
92
- colors = @params.Colors.is_a?(Integer) ? @params.Colors.to_i : 1
93
- bpc = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
94
- columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1
95
-
96
- uncompressed = Predictor.do_post_prediction(uncompressed,
97
- predictor: @params.Predictor.to_i,
98
- colors: colors,
99
- bpc: bpc,
100
- columns: columns)
101
- end
102
-
103
- uncompressed
63
+ post_prediction(uncompressed)
104
64
  end
105
65
  end
106
66
  Fl = Flate
@@ -32,52 +32,24 @@ module Origami
32
32
  #
33
33
  class LZW
34
34
  include Filter
35
-
36
- class DecodeParms < Dictionary
37
- include StandardObject
38
-
39
- field :Predictor, :Type => Integer, :Default => 1
40
- field :Colors, :Type => Integer, :Default => 1
41
- field :BitsPerComponent, :Type => Integer, :Default => 8
42
- field :Columns, :Type => Integer, :Default => 1
43
- field :EarlyChange, :Type => Integer, :Default => 1
44
- end
35
+ include Predictor
45
36
 
46
37
  EOD = 257 #:nodoc:
47
38
  CLEARTABLE = 256 #:nodoc:
48
39
 
49
- #
50
- # Creates a new LZW Filter.
51
- # _parameters_:: A hash of filter options (ignored).
52
- #
53
- def initialize(parameters = {})
54
- super(DecodeParms.new(parameters))
55
- end
56
-
57
40
  #
58
41
  # Encodes given data using LZW compression method.
59
42
  # _stream_:: The data to encode.
60
43
  #
61
44
  def encode(string)
62
- if @params.Predictor.is_a?(Integer)
63
- colors = @params.Colors.is_a?(Integer) ? @params.Colors.to_i : 1
64
- bpc = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
65
- columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1
66
-
67
- string = Predictor.do_pre_prediction(string,
68
- predictor: @params.Predictor.to_i,
69
- colors: colors,
70
- bpc: bpc,
71
- columns: columns)
72
- end
45
+ input = pre_prediction(string)
73
46
 
74
- codesize = 9
47
+ table, codesize = reset_state
75
48
  result = Utils::BitWriter.new
76
49
  result.write(CLEARTABLE, codesize)
77
- table = clear({})
78
50
 
79
51
  s = ''
80
- string.each_byte do |byte|
52
+ input.each_byte do |byte|
81
53
  char = byte.chr
82
54
 
83
55
  case table.size
@@ -86,8 +58,7 @@ module Origami
86
58
  when 2048 then codesize = 12
87
59
  when 4096
88
60
  result.write(CLEARTABLE, codesize)
89
- codesize = 9
90
- clear table
61
+ table, codesize = reset_state
91
62
  redo
92
63
  end
93
64
 
@@ -114,85 +85,76 @@ module Origami
114
85
  def decode(string)
115
86
  result = "".b
116
87
  bstring = Utils::BitReader.new(string)
117
- codesize = 9
118
- table = clear(Hash.new)
119
- prevbyte = nil
88
+ table, codesize, prevbyte = reset_state
120
89
 
121
90
  until bstring.eod? do
122
91
  byte = bstring.read(codesize)
123
-
124
- case table.size
125
- when 510 then codesize = 10
126
- when 1022 then codesize = 11
127
- when 2046 then codesize = 12
128
- when 4095
129
- if byte != CLEARTABLE
130
- raise InvalidLZWDataError.new(
131
- "LZW table is full and no clear flag was set (codeword #{byte.to_s(2).rjust(codesize,'0')} at bit #{bstring.pos - codesize}/#{bstring.size})",
132
- input_data: string,
133
- decoded_data: result
134
- )
135
- end
136
- end
92
+ break if byte == EOD
137
93
 
138
94
  if byte == CLEARTABLE
139
- codesize = 9
140
- clear table
141
- prevbyte = nil
95
+ table, codesize, prevbyte = reset_state
142
96
  redo
143
- elsif byte == EOD
144
- break
145
- else
146
- if prevbyte.nil?
147
- raise InvalidLZWDataError.new(
148
- "No entry for codeword #{byte.to_s(2).rjust(codesize,'0')}.",
149
- input_data: string,
150
- decoded_data: result
151
- ) unless table.value?(byte)
152
-
153
- prevbyte = byte
154
- result << table.key(byte)
155
- redo
156
- else
157
- raise InvalidLZWDataError.new(
158
- "No entry for codeword #{prevbyte.to_s(2).rjust(codesize,'0')}.",
159
- input_data: string,
160
- decoded_data: result
161
- ) unless table.value?(prevbyte)
162
-
163
- if table.value?(byte)
164
- entry = table.key(byte)
165
- else
166
- entry = table.key(prevbyte)
167
- entry += entry[0,1]
168
- end
169
-
170
- result << entry
171
- table[table.key(prevbyte) + entry[0,1]] = table.size
172
- prevbyte = byte
173
- end
174
97
  end
175
- end
176
98
 
177
- if @params.Predictor.is_a?(Integer)
178
- colors = @params.Colors.is_a?(Integer) ? @params.Colors.to_i : 1
179
- bpc = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
180
- columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1
99
+ begin
100
+ codesize = decode_codeword_size(table)
101
+ result << decode_byte(table, prevbyte, byte, codesize)
102
+ rescue InvalidLZWDataError => error
103
+ error.message.concat " (bit pos #{bstring.pos - codesize})"
104
+ error.input_data = string
105
+ error.decoded_data = result
106
+ raise(error)
107
+ end
181
108
 
182
- result = Predictor.do_post_prediction(result,
183
- predictor: @params.Predictor.to_i,
184
- colors: colors,
185
- bpc: bpc,
186
- columns: columns)
109
+ prevbyte = byte
187
110
  end
188
111
 
189
- result
112
+ post_prediction(result)
190
113
  end
191
114
 
192
115
  private
193
116
 
194
- def clear(table) #:nodoc:
195
- table.clear
117
+ def decode_codeword_size(table)
118
+ case table.size
119
+ when 258...510 then 9
120
+ when 510...1022 then 10
121
+ when 1022...2046 then 11
122
+ when 2046...4095 then 12
123
+ when 4095
124
+ raise InvalidLZWDataError, "LZW table is full and no clear flag was set"
125
+ end
126
+ end
127
+
128
+ def decode_byte(table, previous_byte, byte, codesize) #:nodoc:
129
+
130
+ # Ensure the codeword can be decoded in the current state.
131
+ check_codeword(table, previous_byte, byte, codesize)
132
+
133
+ if previous_byte.nil?
134
+ table.key(byte)
135
+ else
136
+ if table.value?(byte)
137
+ entry = table.key(byte)
138
+ else
139
+ entry = table.key(previous_byte)
140
+ entry += entry[0, 1]
141
+ end
142
+
143
+ table[table.key(previous_byte) + entry[0,1]] = table.size
144
+
145
+ entry
146
+ end
147
+ end
148
+
149
+ def check_codeword(table, previous_byte, byte, codesize) #:nodoc:
150
+ if (previous_byte.nil? and not table.value?(byte)) or (previous_byte and not table.value?(previous_byte))
151
+ codeword = previous_byte || byte
152
+ raise InvalidLZWDataError, "No entry for codeword #{codeword.to_s(2).rjust(codesize, '0')}"
153
+ end
154
+ end
155
+
156
+ def reset_state #:nodoc:
157
+ table = {}
196
158
  256.times do |i|
197
159
  table[i.chr] = i
198
160
  end
@@ -200,7 +162,8 @@ module Origami
200
162
  table[CLEARTABLE] = CLEARTABLE
201
163
  table[EOD] = EOD
202
164
 
203
- table
165
+ # Codeword table, codeword size, previous_byte
166
+ [table, 9, nil]
204
167
  end
205
168
  end
206
169