hexapdf 0.14.3 → 0.14.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c43d8e9e117db1717ddfee73a54e4384743b8aa35863ab5bd19ffe57b8ce5674
4
- data.tar.gz: 1020c8a3de8fcdf201500c1c0d22dfb99ed27daebac7baac92748f8127efc992
3
+ metadata.gz: 958692ab2c53f74fe599c0ba8c9c046aa41b38d2bf840a47dec8f0e258fd86e0
4
+ data.tar.gz: b41d46ccb39d36d351cc143ba0afc145e785307b2a7ae90bc0f32d1ab76949af
5
5
  SHA512:
6
- metadata.gz: e19eea4e88077afb7e8532fa6fe9ab2a03ffc5588749b72277462a971ebcec877ee72868d0ab698744117d46566be98e65c10225649d3bd1b4cd6e64e9625767
7
- data.tar.gz: 6626a9feba0af0b46f293c1069a0d53b458a0dc29d08b82253f14f9bb98a878b914042faccc433b73f2f0e35d4da47c58a1bdebd2f3dee2fefb24c076a4e6bb3
6
+ metadata.gz: c16e231aeeb12b55daf75a28a8e3918f6807127257655f42d1f3433c76cb25f0ea42daafc8dd20bd37099f9ef5f6f2a6a3e3b2468acf000c041452a32908e1ee
7
+ data.tar.gz: a9a1fff7c7ff699c2b48333d89fae1aa67cd7ce61003845f76e4855cfc2f2ad5969ae668359091cd3fa225ea9a8b99fb9883e28b07fe6fcd985c7f83b842969d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ ## 0.14.4 - 2021-02-27
2
+
3
+ ### Added
4
+
5
+ * Support for the Crypt filters
6
+
7
+ ### Changed
8
+
9
+ * [HexaPDF::MalformedPDFError] to make the `pos` argument optional
10
+
11
+ ### Fixed
12
+
13
+ * Handling of invalid floating point numbers NaN, Inf and -Inf when serializing
14
+ * Processing of invalid PDF files containing NaN and Inf instead of numbers
15
+ * Bug in Type1 font AFM parser that occured if the file doesn't end with a new
16
+ line character
17
+ * Cross-reference table reconstruction to handle the case of an entry specifying
18
+ a non-existent indirect object
19
+ * Cross-reference table reconstruction to handle trailers specified by cross-
20
+ reference streams
21
+ * Cross-reference table reconstruction to use the set security handle for
22
+ decrypting indirect objects
23
+ * Parsing of cross-reference streams where data is missing
24
+
25
+
1
26
  ## 0.14.3 - 2021-02-16
2
27
 
3
28
  ### Fixed
@@ -393,7 +393,7 @@ module HexaPDF
393
393
  DCTDecode: 'HexaPDF::Filter::PassThrough',
394
394
  DCT: 'HexaPDF::Filter::PassThrough',
395
395
  JPXDecode: 'HexaPDF::Filter::PassThrough',
396
- Crypt: nil,
396
+ Crypt: 'HexaPDF::Filter::Crypt',
397
397
  Encryption: 'HexaPDF::Filter::Encryption',
398
398
  },
399
399
  'font.map' => {},
@@ -268,7 +268,7 @@ module HexaPDF
268
268
  str.replace(string_algorithm.decrypt(key, str))
269
269
  end
270
270
 
271
- if obj.kind_of?(HexaPDF::Stream)
271
+ if obj.kind_of?(HexaPDF::Stream) && obj.raw_stream.filter[0] != :Crypt
272
272
  unless string_algorithm == stream_algorithm
273
273
  key = object_key(obj.oid, obj.gen, stream_algorithm)
274
274
  end
@@ -300,7 +300,12 @@ module HexaPDF
300
300
  obj.raw_stream.key == key && obj.raw_stream.algorithm == stream_algorithm
301
301
  obj.raw_stream.undecrypted_fiber
302
302
  else
303
- stream_algorithm.encryption_fiber(key, result)
303
+ filter = obj[:Filter]
304
+ if filter == :Crypt || (filter.kind_of?(PDFArray) && filter[0] == :Crypt)
305
+ result
306
+ else
307
+ stream_algorithm.encryption_fiber(key, result)
308
+ end
304
309
  end
305
310
  end
306
311
 
data/lib/hexapdf/error.rb CHANGED
@@ -47,14 +47,14 @@ module HexaPDF
47
47
 
48
48
  # Creates a new malformed PDF error object for the given exception message.
49
49
  #
50
- # The byte position where the error occured has to be given via the +pos+ argument.
51
- def initialize(message, pos:)
50
+ # The byte position where the error occured can be given via the +pos+ argument.
51
+ def initialize(message, pos: nil)
52
52
  super(message)
53
53
  @pos = pos
54
54
  end
55
55
 
56
56
  def message # :nodoc:
57
- "PDF malformed around position #{pos}: #{super}"
57
+ "PDF malformed#{pos ? "around position #{pos}" : ''}: #{super}"
58
58
  end
59
59
 
60
60
  end
@@ -95,6 +95,7 @@ module HexaPDF
95
95
  autoload(:Predictor, 'hexapdf/filter/predictor')
96
96
 
97
97
  autoload(:Encryption, 'hexapdf/filter/encryption')
98
+ autoload(:Crypt, 'hexapdf/filter/crypt')
98
99
 
99
100
  autoload(:PassThrough, 'hexapdf/filter/pass_through')
100
101
 
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/error'
38
+
39
+ module HexaPDF
40
+ module Filter
41
+
42
+ # This filter module implements the Crypt filter. The only supported part is using the Identity
43
+ # filter.
44
+ module Crypt
45
+
46
+ # See HexaPDF::Filter
47
+ def self.decoder(source, options)
48
+ if !options || !options.key?(:Name) || options[:Name] == :Identity
49
+ source
50
+ else
51
+ raise FilterError, "Handling of Crypt filters besides Identity is not implemented"
52
+ end
53
+ end
54
+
55
+ singleton_class.send(:alias_method, :encoder, :decoder)
56
+
57
+ end
58
+
59
+ end
60
+ end
@@ -207,7 +207,8 @@ module HexaPDF
207
207
 
208
208
  # Returns the rest of the line, with whitespace stripped.
209
209
  def parse_string
210
- line = @line.strip!
210
+ @line.strip!
211
+ line = @line
211
212
  @line = ''
212
213
  line
213
214
  end
@@ -56,10 +56,12 @@ module HexaPDF
56
56
  # PDF references are resolved using the associated Document object.
57
57
  def initialize(io, document)
58
58
  @io = io
59
- @tokenizer = Tokenizer.new(io)
59
+ on_correctable_error = document.config['parser.on_correctable_error'].curry[document]
60
+ @tokenizer = Tokenizer.new(io, on_correctable_error: on_correctable_error)
60
61
  @document = document
61
62
  @object_stream_data = {}
62
63
  @reconstructed_revision = nil
64
+ @in_reconstruct_revision = false
63
65
  retrieve_pdf_header_offset_and_version
64
66
  end
65
67
 
@@ -94,7 +96,8 @@ module HexaPDF
94
96
 
95
97
  @document.wrap(obj, oid: oid, gen: gen, stream: stream)
96
98
  rescue HexaPDF::MalformedPDFError
97
- reconstructed_revision.object(xref_entry)
99
+ reconstructed_revision.object(xref_entry) ||
100
+ @document.wrap(nil, oid: xref_entry.oid, gen: xref_entry.gen)
98
101
  end
99
102
 
100
103
  # Parses the indirect object at the specified offset.
@@ -389,6 +392,9 @@ module HexaPDF
389
392
  # If the file contains multiple cross-reference sections, all objects will be put into a single
390
393
  # cross-reference table, later objects overwriting prior ones.
391
394
  def reconstruct_revision
395
+ return if @in_reconstruct_revision
396
+ @in_reconstruct_revision = true
397
+
392
398
  raise unless @document.config['parser.try_xref_reconstruction']
393
399
  msg = "#{$!} - trying cross-reference table reconstruction"
394
400
  @document.config['parser.on_correctable_error'].call(@document, msg, @tokenizer.pos)
@@ -424,16 +430,22 @@ module HexaPDF
424
430
  end
425
431
  end
426
432
 
427
- trailer&.delete(:Prev) # no need for this and may wreak havoc
428
433
  if !trailer || trailer.empty?
429
- raise_malformed("Could not reconstruct malformed PDF because trailer was not found", pos: 0)
434
+ _, trailer = load_revision(startxref_offset) rescue nil
435
+ unless trailer
436
+ @in_reconstruct_revision = false
437
+ raise_malformed("Could not reconstruct malformed PDF because trailer was not found", pos: 0)
438
+ end
430
439
  end
440
+ trailer&.delete(:Prev) # no need for this and may wreak havoc
431
441
 
432
442
  loader = lambda do |xref_entry|
433
443
  obj, oid, gen, stream = parse_indirect_object(xref_entry.pos)
434
- @document.wrap(obj, oid: oid, gen: gen, stream: stream)
444
+ obj = @document.wrap(obj, oid: oid, gen: gen, stream: stream)
445
+ @document.security_handler ? @document.security_handler.decrypt(obj) : obj
435
446
  end
436
447
 
448
+ @in_reconstruct_revision = false
437
449
  Revision.new(@document.wrap(trailer, type: :XXTrailer), xref_section: xref,
438
450
  loader: loader)
439
451
  end
@@ -191,7 +191,13 @@ module HexaPDF
191
191
  #
192
192
  # See: PDF1.7 s7.3.3
193
193
  def serialize_float(obj)
194
- -0.0001 < obj && obj < 0.0001 && obj != 0 ? sprintf("%.6f", obj) : obj.round(6).to_s
194
+ if -0.0001 < obj && obj < 0.0001 && obj != 0
195
+ sprintf("%.6f", obj)
196
+ elsif obj.finite?
197
+ obj.round(6).to_s
198
+ else
199
+ raise HexaPDF::Error, "Can't serialize special floating point number #{obj}"
200
+ end
195
201
  end
196
202
 
197
203
  # The regexp matches all characters that need to be escaped and the substs hash contains the
@@ -73,11 +73,15 @@ module HexaPDF
73
73
  # The IO object from the tokens are read.
74
74
  attr_reader :io
75
75
 
76
- # Creates a new tokenizer.
77
- def initialize(io)
76
+ # Creates a new tokenizer for the given IO stream.
77
+ #
78
+ # If +on_correctable_error+ is set to an object responding to +call(msg, pos)+, errors for
79
+ # correctable situations are only raised if the return value of calling the object is +true+.
80
+ def initialize(io, on_correctable_error: nil)
78
81
  @io = io
79
82
  @ss = StringScanner.new(''.b)
80
83
  @original_pos = -1
84
+ @on_correctable_error = on_correctable_error || proc { false }
81
85
  self.pos = 0
82
86
  end
83
87
 
@@ -180,7 +184,8 @@ module HexaPDF
180
184
  end
181
185
  else
182
186
  unless allow_keyword
183
- raise HexaPDF::MalformedPDFError.new("Invalid object, got token #{token}", pos: pos)
187
+ maybe_raise("Invalid object, got token #{token}", force: token !~ /^-?(nan|inf)$/i)
188
+ token = 0
184
189
  end
185
190
  end
186
191
  end
@@ -428,6 +433,20 @@ module HexaPDF
428
433
  true
429
434
  end
430
435
 
436
+ # Calls the @on_correctable_error callable object with the given message and the current
437
+ # position. If the returned value is +true+, raises a HexaPDF::MalformedPDFError. Otherwise the
438
+ # error is corrected (by the caller) and tokenization continues.
439
+ #
440
+ # If the option +force+ is used, the callable object is not called and the error is raised
441
+ # immediately.
442
+ def maybe_raise(msg, force: false)
443
+ if force || @on_correctable_error.call(msg, pos)
444
+ error = HexaPDF::MalformedPDFError.new(msg, pos: pos)
445
+ error.set_backtrace(caller(1))
446
+ raise error
447
+ end
448
+ end
449
+
431
450
  end
432
451
 
433
452
  end
@@ -135,6 +135,13 @@ module HexaPDF
135
135
  w1 = w[1]
136
136
  w2 = w[2]
137
137
 
138
+ needed_bytes = (w0 + w1 + w2) * index.each_slice(2).sum(&:last)
139
+
140
+ if needed_bytes > data.size
141
+ raise HexaPDF::MalformedPDFError, "Cross-reference stream is missing data " \
142
+ "(#{needed_bytes} bytes needed, got #{data.size})"
143
+ end
144
+
138
145
  index.each_slice(2) do |first_oid, number_of_entries|
139
146
  first_oid.upto(first_oid + number_of_entries - 1) do |oid|
140
147
  # Default for first field: type 1
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.14.3'
40
+ VERSION = '0.14.4'
41
41
 
42
42
  end
@@ -297,6 +297,13 @@ describe HexaPDF::Encryption::SecurityHandler do
297
297
  assert_equal(@encrypted, @handler.decrypt(@obj)[:Key])
298
298
  end
299
299
 
300
+ it "defers handling encryption to a Crypt filter is specified" do
301
+ data = HexaPDF::StreamData.new(proc { 'mydata' }, filter: :Crypt)
302
+ obj = @document.wrap({}, oid: 1, stream: data)
303
+ @handler.decrypt(obj)
304
+ assert_equal('mydata', obj.stream)
305
+ end
306
+
300
307
  it "doesn't decrypt XRef streams" do
301
308
  @obj[:Type] = :XRef
302
309
  assert_equal(@encrypted, @handler.decrypt(@obj)[:Key])
@@ -343,6 +350,14 @@ describe HexaPDF::Encryption::SecurityHandler do
343
350
  assert_equal('string', @handler.encrypt_stream(@stream).resume)
344
351
  end
345
352
 
353
+ it "defers encrypting to a Crypt filter if specified" do
354
+ @stream.set_filter(:Crypt)
355
+ assert_equal('string', @handler.encrypt_stream(@stream).resume)
356
+
357
+ @stream.set_filter([:Crypt])
358
+ assert_equal('string', @handler.encrypt_stream(@stream).resume)
359
+ end
360
+
346
361
  it "doesn't encrypt the /Contents key of signature dictionaries" do
347
362
  @obj[:Type] = :Sig
348
363
  @obj[:Contents] = "test"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/filter/crypt'
5
+
6
+ describe HexaPDF::Filter::Crypt do
7
+ before do
8
+ @obj = HexaPDF::Filter::Crypt
9
+ @source = Fiber.new { "hallo" }
10
+ end
11
+
12
+ it "works with the Identity filter" do
13
+ assert_equal(@source, @obj.decoder(@source, nil))
14
+ assert_equal(@source, @obj.encoder(@source, {})) # sic: 'encoder'
15
+ assert_equal(@source, @obj.decoder(@source, {Name: :Identity}))
16
+ end
17
+
18
+ it "fails if crypt filter name is not Identity" do
19
+ assert_raises(HexaPDF::FilterError) { @obj.decoder(@source, {Name: :Other}) }
20
+ end
21
+ end
@@ -39,6 +39,11 @@ describe HexaPDF::Font::Type1::AFMParser do
39
39
  end
40
40
  end
41
41
 
42
+ it "parses until EOF if no end token is found" do
43
+ io = StringIO.new("StartFontMetrics 4.1\nFontName Test")
44
+ assert_equal('Test', HexaPDF::Font::Type1::AFMParser.parse(io).font_name)
45
+ end
46
+
42
47
  it "extracts kerning and ligature information" do
43
48
  metrics = FONT_TIMES.metrics
44
49
  glyph = metrics.character_metrics[:f]
@@ -531,11 +531,25 @@ describe HexaPDF::Parser do
531
531
  assert_equal(6, @parser.load_object(@xref).value)
532
532
  end
533
533
 
534
+ it "uses a security handler for decrypting indirect objects if necessary" do
535
+ handler = Minitest::Mock.new
536
+ handler.expect(:decrypt, HexaPDF::Object.new(:result, oid: 1), [HexaPDF::Object])
537
+ @document.instance_variable_set(:@security_handler, handler)
538
+ create_parser("1 0 obj\n6\nendobj\ntrailer\n<</Size 1>>")
539
+ assert_equal(:result, @parser.load_object(@xref).value)
540
+ assert(handler.verify)
541
+ end
542
+
534
543
  it "ignores parts where the starting line is split across lines" do
535
544
  create_parser("1 0 obj\n5\nendobj\n1 0\nobj\n6\nendobj\ntrailer\n<</Size 1>>")
536
545
  assert_equal(5, @parser.load_object(@xref).value)
537
546
  end
538
547
 
548
+ it "handles the case when the specified object had an xref entry but is not found" do
549
+ create_parser("3 0 obj\n5\nendobj\ntrailer\n<</Size 1>>")
550
+ assert(@parser.load_object(@xref).null?)
551
+ end
552
+
539
553
  it "handles cases where the line contains an invalid string that exceeds the read buffer" do
540
554
  create_parser("(1" << "(abc" * 32188 << "\n1 0 obj\n6\nendobj\ntrailer\n<</Size 1>>")
541
555
  assert_equal(6, @parser.load_object(@xref).value)
@@ -568,6 +582,16 @@ describe HexaPDF::Parser do
568
582
  assert_equal({Size: 1}, @parser.reconstructed_revision.trailer.value)
569
583
  end
570
584
 
585
+ it "tries the trailer specified at the startxref position if no other is found" do
586
+ create_parser("1 0 obj\n5\nendobj\nquack xref trailer <</Size 1/Prev 5>>\nstartxref\n22\n%%EOF")
587
+ assert_equal({Size: 1}, @parser.reconstructed_revision.trailer.value)
588
+ end
589
+
590
+ it "fails if no trailer is found and the trailer specified at the startxref position is not valid" do
591
+ create_parser("1 0 obj\n5\nendobj\nquack trailer <</Size 1>>\nstartxref\n22\n%%EOF")
592
+ assert_raises(HexaPDF::MalformedPDFError) { @parser.reconstructed_revision.trailer }
593
+ end
594
+
571
595
  it "fails if no valid trailer is found" do
572
596
  create_parser("1 0 obj\n5\nendobj")
573
597
  assert_raises(HexaPDF::MalformedPDFError) { @parser.load_object(@xref) }
@@ -58,6 +58,9 @@ describe HexaPDF::Serializer do
58
58
  assert_serialized("0.000005", 0.000005)
59
59
  assert_serialized("-0.000005", -0.000005)
60
60
  assert_serialized("0.0", 0.0)
61
+ assert_raises(HexaPDF::Error) { @serializer.serialize(0.0 / 0) }
62
+ assert_raises(HexaPDF::Error) { @serializer.serialize(1.0 / 0) }
63
+ assert_raises(HexaPDF::Error) { @serializer.serialize(-1.0 / 0) }
61
64
  end
62
65
 
63
66
  it "serializes numerics" do
@@ -55,4 +55,26 @@ describe HexaPDF::Tokenizer do
55
55
  assert_equal(HexaPDF::Tokenizer::NO_MORE_TOKENS, @tokenizer.next_integer_or_keyword)
56
56
  end
57
57
 
58
+ describe "can correct some problems" do
59
+ describe "invalid inf/-inf/nan/-nan tokens" do
60
+ it "turns them into zeros" do
61
+ count = 0
62
+ on_correctable_error = lambda do |msg, pos|
63
+ count += 1
64
+ assert_match(/Invalid object, got token/, msg)
65
+ assert_equal(8, pos) if count == 2
66
+ false
67
+ end
68
+ tokenizer = HexaPDF::Tokenizer.new(StringIO.new("inf -Inf NaN -nan"),
69
+ on_correctable_error: on_correctable_error)
70
+ assert_equal([0, 0, 0, 0], 4.times.map { tokenizer.next_object })
71
+ assert_equal(4, count)
72
+ end
73
+
74
+ it "raises an error if configured so" do
75
+ tokenizer = HexaPDF::Tokenizer.new(StringIO.new("inf"), on_correctable_error: proc { true })
76
+ assert_raises(HexaPDF::MalformedPDFError) { tokenizer.next_object }
77
+ end
78
+ end
79
+ end
58
80
  end
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.14.3)>>
43
+ <</Producer(HexaPDF version 0.14.4)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.14.3)>>
75
+ <</Producer(HexaPDF version 0.14.4)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
@@ -71,6 +71,13 @@ describe HexaPDF::Type::XRefStream do
71
71
  assert(section[10, 0].in_use?)
72
72
  assert_equal(250, section[10, 0].pos)
73
73
  end
74
+
75
+ it "fails if there is not enough data available" do
76
+ @obj[:Index] = [1, 2, 10, 4]
77
+ @obj[:W] = [1, 2, 1]
78
+ @obj.stream = "abcd"
79
+ assert_raises(HexaPDF::MalformedPDFError) { @obj.xref_section }
80
+ end
74
81
  end
75
82
 
76
83
  describe "trailer" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.3
4
+ version: 0.14.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-16 00:00:00.000000000 Z
11
+ date: 2021-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -267,6 +267,7 @@ files:
267
267
  - lib/hexapdf/filter.rb
268
268
  - lib/hexapdf/filter/ascii85_decode.rb
269
269
  - lib/hexapdf/filter/ascii_hex_decode.rb
270
+ - lib/hexapdf/filter/crypt.rb
270
271
  - lib/hexapdf/filter/encryption.rb
271
272
  - lib/hexapdf/filter/flate_decode.rb
272
273
  - lib/hexapdf/filter/lzw_decode.rb
@@ -507,6 +508,7 @@ files:
507
508
  - test/hexapdf/filter/common.rb
508
509
  - test/hexapdf/filter/test_ascii85_decode.rb
509
510
  - test/hexapdf/filter/test_ascii_hex_decode.rb
511
+ - test/hexapdf/filter/test_crypt.rb
510
512
  - test/hexapdf/filter/test_encryption.rb
511
513
  - test/hexapdf/filter/test_flate_decode.rb
512
514
  - test/hexapdf/filter/test_lzw_decode.rb