hexapdf 0.14.3 → 0.14.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/lib/hexapdf/configuration.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +7 -2
- data/lib/hexapdf/error.rb +3 -3
- data/lib/hexapdf/filter.rb +1 -0
- data/lib/hexapdf/filter/crypt.rb +60 -0
- data/lib/hexapdf/font/type1/afm_parser.rb +2 -1
- data/lib/hexapdf/parser.rb +17 -5
- data/lib/hexapdf/serializer.rb +7 -1
- data/lib/hexapdf/tokenizer.rb +22 -3
- data/lib/hexapdf/type/xref_stream.rb +7 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/encryption/test_security_handler.rb +15 -0
- data/test/hexapdf/filter/test_crypt.rb +21 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +5 -0
- data/test/hexapdf/test_parser.rb +24 -0
- data/test/hexapdf/test_serializer.rb +3 -0
- data/test/hexapdf/test_tokenizer.rb +22 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/test_xref_stream.rb +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 958692ab2c53f74fe599c0ba8c9c046aa41b38d2bf840a47dec8f0e258fd86e0
|
4
|
+
data.tar.gz: b41d46ccb39d36d351cc143ba0afc145e785307b2a7ae90bc0f32d1ab76949af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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:
|
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
|
-
|
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
|
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
|
data/lib/hexapdf/filter.rb
CHANGED
@@ -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
|
data/lib/hexapdf/parser.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
data/lib/hexapdf/serializer.rb
CHANGED
@@ -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
|
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
|
data/lib/hexapdf/tokenizer.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
data/lib/hexapdf/version.rb
CHANGED
@@ -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]
|
data/test/hexapdf/test_parser.rb
CHANGED
@@ -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
|
data/test/hexapdf/test_writer.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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-
|
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
|