origamindee 3.0.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 +7 -0
- data/CHANGELOG.md +89 -0
- data/COPYING.LESSER +165 -0
- data/README.md +131 -0
- data/bin/config/pdfcop.conf.yml +236 -0
- data/bin/pdf2pdfa +87 -0
- data/bin/pdf2ruby +333 -0
- data/bin/pdfcop +476 -0
- data/bin/pdfdecompress +97 -0
- data/bin/pdfdecrypt +91 -0
- data/bin/pdfencrypt +113 -0
- data/bin/pdfexplode +223 -0
- data/bin/pdfextract +277 -0
- data/bin/pdfmetadata +143 -0
- data/bin/pdfsh +12 -0
- data/bin/shell/console.rb +128 -0
- data/bin/shell/hexdump.rb +59 -0
- data/bin/shell/irbrc +69 -0
- data/examples/README.md +34 -0
- data/examples/attachments/attachment.rb +38 -0
- data/examples/attachments/nested_document.rb +51 -0
- data/examples/encryption/encryption.rb +28 -0
- data/examples/events/events.rb +72 -0
- data/examples/flash/flash.rb +37 -0
- data/examples/flash/helloworld.swf +0 -0
- data/examples/forms/javascript.rb +54 -0
- data/examples/forms/xfa.rb +115 -0
- data/examples/javascript/hello_world.rb +22 -0
- data/examples/javascript/js_emulation.rb +54 -0
- data/examples/loop/goto.rb +32 -0
- data/examples/loop/named.rb +33 -0
- data/examples/signature/signature.rb +65 -0
- data/examples/uri/javascript.rb +56 -0
- data/examples/uri/open-uri.rb +21 -0
- data/examples/uri/submitform.rb +47 -0
- data/lib/origami/3d.rb +364 -0
- data/lib/origami/acroform.rb +321 -0
- data/lib/origami/actions.rb +318 -0
- data/lib/origami/annotations.rb +711 -0
- data/lib/origami/array.rb +242 -0
- data/lib/origami/boolean.rb +90 -0
- data/lib/origami/catalog.rb +418 -0
- data/lib/origami/collections.rb +144 -0
- data/lib/origami/compound.rb +161 -0
- data/lib/origami/destinations.rb +252 -0
- data/lib/origami/dictionary.rb +192 -0
- data/lib/origami/encryption.rb +1084 -0
- data/lib/origami/extensions/fdf.rb +347 -0
- data/lib/origami/extensions/ppklite.rb +422 -0
- data/lib/origami/filespec.rb +197 -0
- data/lib/origami/filters/ascii.rb +211 -0
- data/lib/origami/filters/ccitt/tables.rb +267 -0
- data/lib/origami/filters/ccitt.rb +357 -0
- data/lib/origami/filters/crypt.rb +38 -0
- data/lib/origami/filters/dct.rb +54 -0
- data/lib/origami/filters/flate.rb +69 -0
- data/lib/origami/filters/jbig2.rb +57 -0
- data/lib/origami/filters/jpx.rb +47 -0
- data/lib/origami/filters/lzw.rb +170 -0
- data/lib/origami/filters/predictors.rb +292 -0
- data/lib/origami/filters/runlength.rb +129 -0
- data/lib/origami/filters.rb +364 -0
- data/lib/origami/font.rb +196 -0
- data/lib/origami/functions.rb +79 -0
- data/lib/origami/graphics/colors.rb +230 -0
- data/lib/origami/graphics/instruction.rb +98 -0
- data/lib/origami/graphics/path.rb +182 -0
- data/lib/origami/graphics/patterns.rb +174 -0
- data/lib/origami/graphics/render.rb +62 -0
- data/lib/origami/graphics/state.rb +149 -0
- data/lib/origami/graphics/text.rb +225 -0
- data/lib/origami/graphics/xobject.rb +918 -0
- data/lib/origami/graphics.rb +38 -0
- data/lib/origami/header.rb +75 -0
- data/lib/origami/javascript.rb +713 -0
- data/lib/origami/linearization.rb +330 -0
- data/lib/origami/metadata.rb +172 -0
- data/lib/origami/name.rb +135 -0
- data/lib/origami/null.rb +65 -0
- data/lib/origami/numeric.rb +181 -0
- data/lib/origami/obfuscation.rb +245 -0
- data/lib/origami/object.rb +760 -0
- data/lib/origami/optionalcontent.rb +183 -0
- data/lib/origami/outline.rb +54 -0
- data/lib/origami/outputintents.rb +85 -0
- data/lib/origami/page.rb +722 -0
- data/lib/origami/parser.rb +269 -0
- data/lib/origami/parsers/fdf.rb +56 -0
- data/lib/origami/parsers/pdf/lazy.rb +176 -0
- data/lib/origami/parsers/pdf/linear.rb +122 -0
- data/lib/origami/parsers/pdf.rb +118 -0
- data/lib/origami/parsers/ppklite.rb +57 -0
- data/lib/origami/pdf.rb +1108 -0
- data/lib/origami/reference.rb +134 -0
- data/lib/origami/signature.rb +702 -0
- data/lib/origami/stream.rb +705 -0
- data/lib/origami/string.rb +444 -0
- data/lib/origami/template/patterns.rb +56 -0
- data/lib/origami/template/widgets.rb +151 -0
- data/lib/origami/trailer.rb +190 -0
- data/lib/origami/tree.rb +62 -0
- data/lib/origami/version.rb +23 -0
- data/lib/origami/webcapture.rb +100 -0
- data/lib/origami/xfa/config.rb +453 -0
- data/lib/origami/xfa/connectionset.rb +146 -0
- data/lib/origami/xfa/datasets.rb +49 -0
- data/lib/origami/xfa/localeset.rb +42 -0
- data/lib/origami/xfa/package.rb +59 -0
- data/lib/origami/xfa/pdf.rb +73 -0
- data/lib/origami/xfa/signature.rb +42 -0
- data/lib/origami/xfa/sourceset.rb +43 -0
- data/lib/origami/xfa/stylesheet.rb +44 -0
- data/lib/origami/xfa/template.rb +1691 -0
- data/lib/origami/xfa/xdc.rb +42 -0
- data/lib/origami/xfa/xfa.rb +146 -0
- data/lib/origami/xfa/xfdf.rb +43 -0
- data/lib/origami/xfa/xmpmeta.rb +43 -0
- data/lib/origami/xfa.rb +62 -0
- data/lib/origami/xreftable.rb +557 -0
- data/lib/origami.rb +47 -0
- data/test/dataset/calc.pdf +85 -0
- data/test/dataset/crypto.pdf +36 -0
- data/test/dataset/empty.pdf +49 -0
- data/test/test_actions.rb +27 -0
- data/test/test_annotations.rb +68 -0
- data/test/test_forms.rb +30 -0
- data/test/test_native_types.rb +83 -0
- data/test/test_object_tree.rb +33 -0
- data/test/test_pages.rb +60 -0
- data/test/test_pdf.rb +20 -0
- data/test/test_pdf_attachment.rb +34 -0
- data/test/test_pdf_create.rb +24 -0
- data/test/test_pdf_encrypt.rb +102 -0
- data/test/test_pdf_parse.rb +134 -0
- data/test/test_pdf_parse_lazy.rb +69 -0
- data/test/test_pdf_sign.rb +97 -0
- data/test/test_streams.rb +184 -0
- data/test/test_xrefs.rb +67 -0
- metadata +280 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
class TestPDFParser < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@files =
|
6
|
+
%w{
|
7
|
+
dataset/empty.pdf
|
8
|
+
dataset/calc.pdf
|
9
|
+
dataset/crypto.pdf
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_parse_pdf
|
14
|
+
@files.each do |file|
|
15
|
+
pdf = PDF.read(File.join(__dir__, file), ignore_errors: false, verbosity: Parser::VERBOSE_QUIET)
|
16
|
+
|
17
|
+
assert_instance_of PDF, pdf
|
18
|
+
|
19
|
+
pdf.each_object do |object|
|
20
|
+
assert_kind_of Origami::Object, object
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_parse_dictionary
|
26
|
+
dict = Dictionary.parse("<</Ref 2 0 R/N null/Pi 3.14 /D <<>>>>")
|
27
|
+
|
28
|
+
assert_instance_of Dictionary, dict
|
29
|
+
assert_instance_of Dictionary, dict[:D]
|
30
|
+
assert_instance_of Null, dict[:N]
|
31
|
+
assert_instance_of Reference, dict[:Ref]
|
32
|
+
assert_equal dict.size, 4
|
33
|
+
assert_raises(InvalidReferenceError) { dict[:Ref].solve }
|
34
|
+
assert dict[:Pi] == 3.14
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_parse_array
|
38
|
+
array = Origami::Array.parse("[/Test (abc) .2 \n 799 [<<>>]]")
|
39
|
+
|
40
|
+
assert array.all?{|e| e.is_a?(Origami::Object)}
|
41
|
+
assert_equal array.length, 5
|
42
|
+
assert_raises(InvalidArrayObjectError) { Origami::Array.parse("[1 ") }
|
43
|
+
assert_raises(InvalidArrayObjectError) { Origami::Array.parse("") }
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_parse_string
|
47
|
+
str = LiteralString.parse("(\\122\\125by\\n)")
|
48
|
+
assert_instance_of LiteralString, str
|
49
|
+
assert_equal str.value, "RUby\n"
|
50
|
+
|
51
|
+
assert_raises(InvalidLiteralStringObjectError) { LiteralString.parse("") }
|
52
|
+
assert_raises(InvalidLiteralStringObjectError) { LiteralString.parse("(test") }
|
53
|
+
assert_equal "((O))", LiteralString.parse("(((O)))").value
|
54
|
+
assert_equal LiteralString.parse("(ABC\\\nDEF\\\r\nGHI)").value, "ABCDEFGHI"
|
55
|
+
assert_equal LiteralString.parse('(\r\n\b\t\f\\(\\)\\x\\\\)').value, "\r\n\b\t\f()x\\"
|
56
|
+
assert_equal LiteralString.parse('(\r\n\b\t\f\\\\\\(\\))').to_s, '(\r\n\b\t\f\\\\\\(\\))'
|
57
|
+
|
58
|
+
str = HexaString.parse("<52 55 62 79 0A>")
|
59
|
+
assert_instance_of HexaString, str
|
60
|
+
assert_equal str.value, "RUby\n"
|
61
|
+
|
62
|
+
assert_equal HexaString.parse("<4>").value, 0x40.chr
|
63
|
+
|
64
|
+
assert_raises(InvalidHexaStringObjectError) { HexaString.parse("") }
|
65
|
+
assert_raises(InvalidHexaStringObjectError) { HexaString.parse("<12") }
|
66
|
+
assert_raises(InvalidHexaStringObjectError) { HexaString.parse("<12X>") }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_parse_bool
|
70
|
+
b_true = Boolean.parse("true")
|
71
|
+
b_false = Boolean.parse("false")
|
72
|
+
|
73
|
+
assert_instance_of Boolean, b_true
|
74
|
+
assert_instance_of Boolean, b_false
|
75
|
+
|
76
|
+
assert b_false.false?
|
77
|
+
refute b_true.false?
|
78
|
+
|
79
|
+
assert_raises(InvalidBooleanObjectError) { Boolean.parse("") }
|
80
|
+
assert_raises(InvalidBooleanObjectError) { Boolean.parse("tru") }
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_parse_real
|
84
|
+
real = Real.parse("-3.141592653")
|
85
|
+
assert_instance_of Real, real
|
86
|
+
assert_equal real, -3.141592653
|
87
|
+
|
88
|
+
real = Real.parse("+.00200")
|
89
|
+
assert_instance_of Real, real
|
90
|
+
assert_equal real, 0.002
|
91
|
+
|
92
|
+
assert_raises(InvalidRealObjectError) { Real.parse("") }
|
93
|
+
assert_raises(InvalidRealObjectError) { Real.parse(".") }
|
94
|
+
assert_raises(InvalidRealObjectError) { Real.parse("+0x1") }
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_parse_int
|
98
|
+
int = Origami::Integer.parse("02000000000000")
|
99
|
+
assert_instance_of Origami::Integer, int
|
100
|
+
assert_equal int, 2000000000000
|
101
|
+
|
102
|
+
int = Origami::Integer.parse("-98")
|
103
|
+
assert_instance_of Origami::Integer, int
|
104
|
+
assert_equal int, -98
|
105
|
+
|
106
|
+
assert_raises(Origami::InvalidIntegerObjectError) { Origami::Integer.parse("") }
|
107
|
+
assert_raises(Origami::InvalidIntegerObjectError) { Origami::Integer.parse("+-1") }
|
108
|
+
assert_raises(Origami::InvalidIntegerObjectError) { Origami::Integer.parse("ABC") }
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_parse_name
|
112
|
+
name = Name.parse("/#52#55#62#79#0A")
|
113
|
+
assert_instance_of Name, name
|
114
|
+
assert_equal name.value, :"RUby\n"
|
115
|
+
|
116
|
+
name = Name.parse("/")
|
117
|
+
assert_instance_of Name, name
|
118
|
+
assert_equal :"", name.value
|
119
|
+
|
120
|
+
assert_raises(Origami::InvalidNameObjectError) { Name.parse("") }
|
121
|
+
assert_raises(Origami::InvalidNameObjectError) { Name.parse("test") }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_parse_reference
|
125
|
+
ref = Reference.parse("199 1 R")
|
126
|
+
assert_instance_of Reference, ref
|
127
|
+
|
128
|
+
assert_equal [199, 1], ref.to_a
|
129
|
+
assert_raises(InvalidReferenceError) { ref.solve }
|
130
|
+
assert_raises(InvalidReferenceError) { Reference.parse("-2 0 R") }
|
131
|
+
assert_raises(InvalidReferenceError) { Reference.parse("0 R") }
|
132
|
+
assert_raises(InvalidReferenceError) { Reference.parse("") }
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class TestPDFLazyParser < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@files =
|
8
|
+
%w{
|
9
|
+
dataset/empty.pdf
|
10
|
+
dataset/calc.pdf
|
11
|
+
dataset/crypto.pdf
|
12
|
+
}
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_parse_pdf_lazy
|
17
|
+
@files.each do |file|
|
18
|
+
pdf = PDF.read(File.join(__dir__, file),
|
19
|
+
ignore_errors: false,
|
20
|
+
lazy: true,
|
21
|
+
verbosity: Parser::VERBOSE_QUIET)
|
22
|
+
|
23
|
+
assert_instance_of PDF, pdf
|
24
|
+
|
25
|
+
pdf.each_object do |object|
|
26
|
+
assert_kind_of Origami::Object, object
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_instance_of Catalog, pdf.Catalog
|
30
|
+
|
31
|
+
pdf.each_page do |page|
|
32
|
+
assert_kind_of Page, page
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_save_pdf_lazy
|
38
|
+
@files.each do |file|
|
39
|
+
pdf = PDF.read(File.join(__dir__, file),
|
40
|
+
ignore_errors: false,
|
41
|
+
lazy: true,
|
42
|
+
verbosity: Parser::VERBOSE_QUIET)
|
43
|
+
|
44
|
+
pdf.save(StringIO.new)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_random_access
|
49
|
+
io = StringIO.new
|
50
|
+
stream = Stream.new("abc")
|
51
|
+
|
52
|
+
PDF.create(io) do |pdf|
|
53
|
+
pdf.insert(stream)
|
54
|
+
end
|
55
|
+
|
56
|
+
io = io.reopen(io.string, 'r')
|
57
|
+
|
58
|
+
pdf = PDF.read(io, ignore_errors: false,
|
59
|
+
lazy: true,
|
60
|
+
verbosity: Parser::VERBOSE_QUIET)
|
61
|
+
|
62
|
+
non_existent = pdf[42]
|
63
|
+
existent = pdf[stream.reference]
|
64
|
+
|
65
|
+
assert_nil non_existent
|
66
|
+
assert_instance_of Stream, existent
|
67
|
+
assert_equal stream.data, existent.data
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'stringio'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
class TestSign < Minitest::Test
|
6
|
+
|
7
|
+
def create_self_signed_ca_certificate(key_size, expires)
|
8
|
+
key = OpenSSL::PKey::RSA.new key_size
|
9
|
+
|
10
|
+
name = OpenSSL::X509::Name.parse 'CN=origami/DC=example'
|
11
|
+
|
12
|
+
cert = OpenSSL::X509::Certificate.new
|
13
|
+
cert.version = 2
|
14
|
+
cert.serial = 0
|
15
|
+
cert.not_before = Time.now
|
16
|
+
cert.not_after = Time.now + expires
|
17
|
+
|
18
|
+
cert.public_key = key.public_key
|
19
|
+
cert.subject = name
|
20
|
+
|
21
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
22
|
+
extension_factory.issuer_certificate = cert
|
23
|
+
extension_factory.subject_certificate = cert
|
24
|
+
|
25
|
+
cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)
|
26
|
+
cert.add_extension extension_factory.create_extension('keyUsage', 'digitalSignature,keyCertSign')
|
27
|
+
cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
|
28
|
+
|
29
|
+
cert.issuer = name
|
30
|
+
cert.sign key, OpenSSL::Digest::SHA256.new
|
31
|
+
|
32
|
+
[ cert, key ]
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@cert, @key = create_self_signed_ca_certificate(1024, 3600)
|
37
|
+
@other_cert, @other_key = create_self_signed_ca_certificate(1024, 3600)
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_document_with_annotation
|
41
|
+
document = PDF.read(File.join(__dir__, "dataset/calc.pdf"),
|
42
|
+
ignore_errors: false, verbosity: Parser::VERBOSE_QUIET)
|
43
|
+
|
44
|
+
annotation = Annotation::Widget::Signature.new.set_indirect(true)
|
45
|
+
annotation.Rect = Rectangle[llx: 89.0, lly: 386.0, urx: 190.0, ury: 353.0]
|
46
|
+
|
47
|
+
document.append_page do |page|
|
48
|
+
page.add_annotation(annotation)
|
49
|
+
end
|
50
|
+
|
51
|
+
[ document, annotation ]
|
52
|
+
end
|
53
|
+
|
54
|
+
def sign_document_with_method(method)
|
55
|
+
document, annotation = setup_document_with_annotation
|
56
|
+
|
57
|
+
document.sign(@cert, @key,
|
58
|
+
method: method,
|
59
|
+
annotation: annotation,
|
60
|
+
issuer: "Guillaume Delugré",
|
61
|
+
location: "France",
|
62
|
+
contact: "origami@localhost",
|
63
|
+
reason: "Example"
|
64
|
+
)
|
65
|
+
|
66
|
+
assert document.frozen?
|
67
|
+
assert document.signed?
|
68
|
+
|
69
|
+
output = StringIO.new
|
70
|
+
document.save(output)
|
71
|
+
|
72
|
+
document = PDF.read(output.reopen(output.string,'r'), verbosity: Parser::VERBOSE_QUIET)
|
73
|
+
|
74
|
+
refute document.verify
|
75
|
+
assert document.verify(allow_self_signed: true)
|
76
|
+
assert document.verify(trusted_certs: [@cert])
|
77
|
+
refute document.verify(trusted_certs: [@other_cert])
|
78
|
+
|
79
|
+
result = document.verify do |ctx|
|
80
|
+
ctx.error == OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT and ctx.current_cert.to_pem == @cert.to_pem
|
81
|
+
end
|
82
|
+
|
83
|
+
assert result
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_sign_pkcs7_sha1
|
87
|
+
sign_document_with_method(Signature::PKCS7_SHA1)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_sign_pkcs7_detached
|
91
|
+
sign_document_with_method(Signature::PKCS7_DETACHED)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_sign_x509_sha1
|
95
|
+
sign_document_with_method(Signature::PKCS1_RSA_SHA1)
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class TestStreams < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@target = PDF.new
|
7
|
+
@output = StringIO.new
|
8
|
+
@data = "0123456789" * 1024
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_predictors
|
12
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
13
|
+
stm.set_predictor(Filter::Predictor::TIFF)
|
14
|
+
raw = stm.encoded_data
|
15
|
+
stm.data = nil
|
16
|
+
stm.encoded_data = raw
|
17
|
+
|
18
|
+
assert_equal @data, stm.data
|
19
|
+
|
20
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
21
|
+
stm.set_predictor(Filter::Predictor::PNG_SUB)
|
22
|
+
raw = stm.encoded_data
|
23
|
+
stm.data = nil
|
24
|
+
stm.encoded_data = raw
|
25
|
+
|
26
|
+
assert_equal @data, stm.data
|
27
|
+
|
28
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
29
|
+
stm.set_predictor(Filter::Predictor::PNG_UP)
|
30
|
+
raw = stm.encoded_data
|
31
|
+
stm.data = nil
|
32
|
+
stm.encoded_data = raw
|
33
|
+
|
34
|
+
assert_equal stm.data, @data
|
35
|
+
|
36
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
37
|
+
stm.set_predictor(Filter::Predictor::PNG_AVERAGE)
|
38
|
+
raw = stm.encoded_data
|
39
|
+
stm.data = nil
|
40
|
+
stm.encoded_data = raw
|
41
|
+
|
42
|
+
assert_equal stm.data, @data
|
43
|
+
|
44
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
45
|
+
stm.set_predictor(Filter::Predictor::PNG_PAETH)
|
46
|
+
raw = stm.encoded_data
|
47
|
+
stm.data = nil
|
48
|
+
stm.encoded_data = raw
|
49
|
+
|
50
|
+
assert_equal stm.data, @data
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_filter_flate
|
54
|
+
stm = Stream.new(@data, :Filter => :FlateDecode)
|
55
|
+
raw = stm.encoded_data
|
56
|
+
stm.data = nil
|
57
|
+
stm.encoded_data = raw
|
58
|
+
|
59
|
+
assert_equal stm.data, @data
|
60
|
+
|
61
|
+
assert_equal Filter::Flate.decode(Filter::Flate.encode("")), ""
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_filter_asciihex
|
65
|
+
stm = Stream.new(@data, :Filter => :ASCIIHexDecode)
|
66
|
+
raw = stm.encoded_data
|
67
|
+
stm.data = nil
|
68
|
+
stm.encoded_data = raw
|
69
|
+
|
70
|
+
assert_equal stm.data, @data
|
71
|
+
|
72
|
+
assert_raises(Filter::InvalidASCIIHexStringError) do
|
73
|
+
Filter::ASCIIHex.decode("123456789ABCDEFGHIJKL")
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_equal Filter::ASCIIHex.decode(Filter::ASCIIHex.encode("")), ""
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_filter_ascii85
|
80
|
+
stm = Stream.new(@data, :Filter => :ASCII85Decode)
|
81
|
+
raw = stm.encoded_data
|
82
|
+
stm.data = nil
|
83
|
+
stm.encoded_data = raw
|
84
|
+
|
85
|
+
assert_equal stm.data, @data
|
86
|
+
|
87
|
+
assert_raises(Filter::InvalidASCII85StringError) do
|
88
|
+
Filter::ASCII85.decode("ABCD\x01")
|
89
|
+
end
|
90
|
+
|
91
|
+
assert_equal Filter::ASCII85.decode(Filter::ASCII85.encode("")), ""
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_filter_rle
|
95
|
+
stm = Stream.new(@data, :Filter => :RunLengthDecode)
|
96
|
+
raw = stm.encoded_data
|
97
|
+
stm.data = nil
|
98
|
+
stm.encoded_data = raw
|
99
|
+
|
100
|
+
assert_equal stm.data, @data
|
101
|
+
|
102
|
+
assert_raises(Filter::InvalidRunLengthDataError) do
|
103
|
+
Filter::RunLength.decode("\x7f")
|
104
|
+
end
|
105
|
+
|
106
|
+
assert_equal Filter::RunLength.decode(Filter::RunLength.encode("")), ""
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_filter_lzw
|
110
|
+
stm = Stream.new(@data, :Filter => :LZWDecode)
|
111
|
+
raw = stm.encoded_data
|
112
|
+
stm.data = nil
|
113
|
+
stm.encoded_data = raw
|
114
|
+
|
115
|
+
assert_equal stm.data, @data
|
116
|
+
|
117
|
+
assert_raises(Filter::InvalidLZWDataError) do
|
118
|
+
Filter::LZW.decode("abcd")
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_equal Filter::LZW.decode(Filter::LZW.encode("")), ""
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_filter_ccittfax
|
125
|
+
stm = Stream.new(@data[0, 216], :Filter => :CCITTFaxDecode)
|
126
|
+
|
127
|
+
raw = stm.encoded_data
|
128
|
+
stm.data = nil
|
129
|
+
stm.encoded_data = raw
|
130
|
+
|
131
|
+
assert_equal stm.data, @data[0, 216]
|
132
|
+
|
133
|
+
assert_raises(Filter::InvalidCCITTFaxDataError) do
|
134
|
+
Filter::CCITTFax.decode("abcd")
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal Filter::CCITTFax.decode(Filter::CCITTFax.encode("")), ""
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_stream
|
141
|
+
chain = %i[FlateDecode LZWDecode ASCIIHexDecode]
|
142
|
+
|
143
|
+
stm = Stream.new(@data, Filter: chain)
|
144
|
+
@target << stm
|
145
|
+
@target.save(@output)
|
146
|
+
|
147
|
+
assert stm.Length == stm.encoded_data.length
|
148
|
+
assert_equal stm.filters, chain
|
149
|
+
assert_equal stm.data, @data
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_object_stream
|
153
|
+
objstm = ObjectStream.new
|
154
|
+
objstm.Filter = %i[FlateDecode ASCIIHexDecode RunLengthDecode]
|
155
|
+
|
156
|
+
@target << objstm
|
157
|
+
|
158
|
+
assert_raises(InvalidObjectError) do
|
159
|
+
objstm.insert Stream.new
|
160
|
+
end
|
161
|
+
|
162
|
+
3.times do
|
163
|
+
objstm.insert HexaString.new(@data)
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_equal objstm.objects.size, 3
|
167
|
+
|
168
|
+
objstm.each_object do |object|
|
169
|
+
assert_instance_of HexaString, object
|
170
|
+
assert_equal object.parent, objstm
|
171
|
+
assert objstm.include?(object.no)
|
172
|
+
assert_equal objstm.extract(object.no), object
|
173
|
+
assert_equal objstm.extract_by_index(objstm.index(object.no)), object
|
174
|
+
end
|
175
|
+
|
176
|
+
objstm.delete(objstm.objects.first.no)
|
177
|
+
assert_equal objstm.objects.size, 2
|
178
|
+
|
179
|
+
@target.save(@output)
|
180
|
+
|
181
|
+
assert_instance_of Origami::Integer, objstm.N
|
182
|
+
assert_equal objstm.N, objstm.objects.size
|
183
|
+
end
|
184
|
+
end
|
data/test/test_xrefs.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'stringio'
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
class TestXrefs < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@target = PDF.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_xreftable
|
12
|
+
output = StringIO.new
|
13
|
+
|
14
|
+
@target.save(output)
|
15
|
+
output.reopen(output.string, 'r')
|
16
|
+
|
17
|
+
pdf = PDF.read(output, verbosity: Parser::VERBOSE_QUIET, ignore_errors: false)
|
18
|
+
|
19
|
+
xreftable = pdf.revisions.last.xreftable
|
20
|
+
assert_instance_of XRef::Section, xreftable
|
21
|
+
|
22
|
+
pdf.root_objects.each do |object|
|
23
|
+
xref = xreftable.find(object.no)
|
24
|
+
|
25
|
+
assert_instance_of XRef, xref
|
26
|
+
assert xref.used?
|
27
|
+
|
28
|
+
assert_equal xref.offset, object.file_offset
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_xrefstream
|
33
|
+
output = StringIO.new
|
34
|
+
objstm = ObjectStream.new
|
35
|
+
objstm.Filter = :FlateDecode
|
36
|
+
|
37
|
+
@target.insert objstm
|
38
|
+
|
39
|
+
3.times do
|
40
|
+
objstm.insert Null.new
|
41
|
+
end
|
42
|
+
|
43
|
+
@target.save(output)
|
44
|
+
output = output.reopen(output.string, 'r')
|
45
|
+
|
46
|
+
pdf = PDF.read(output, verbosity: Parser::VERBOSE_QUIET, ignore_errors: false)
|
47
|
+
xrefstm = pdf.revisions.last.xrefstm
|
48
|
+
|
49
|
+
assert_instance_of XRefStream, xrefstm
|
50
|
+
assert xrefstm.entries.all?{ |xref| xref.is_a?(XRef) or xref.is_a?(XRefToCompressedObject) }
|
51
|
+
|
52
|
+
pdf.each_object(compressed: true) do |object|
|
53
|
+
xref = xrefstm.find(object.no)
|
54
|
+
|
55
|
+
if object.parent.is_a?(ObjectStream)
|
56
|
+
assert_instance_of XRefToCompressedObject, xref
|
57
|
+
assert_equal xref.objstmno, object.parent.no
|
58
|
+
assert_equal xref.index, object.parent.index(object.no)
|
59
|
+
else
|
60
|
+
assert_instance_of XRef, xref
|
61
|
+
assert_equal xref.offset, object.file_offset
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_instance_of Catalog, xrefstm.Root
|
66
|
+
end
|
67
|
+
end
|