hexapdf 0.17.1 → 0.17.2
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 +1024 -0
- data/LICENSE +29 -0
- data/README.md +129 -0
- data/Rakefile +109 -0
- data/agpl-3.0.txt +661 -0
- data/examples/001-hello_world.rb +16 -0
- data/examples/002-graphics.rb +275 -0
- data/examples/003-arcs.rb +50 -0
- data/examples/004-optimizing.rb +23 -0
- data/examples/005-merging.rb +27 -0
- data/examples/006-standard_pdf_fonts.rb +73 -0
- data/examples/007-truetype.rb +42 -0
- data/examples/008-show_char_bboxes.rb +55 -0
- data/examples/009-text_layouter_alignment.rb +47 -0
- data/examples/010-text_layouter_inline_boxes.rb +64 -0
- data/examples/011-text_layouter_line_wrapping.rb +57 -0
- data/examples/012-text_layouter_styling.rb +122 -0
- data/examples/013-text_layouter_shapes.rb +176 -0
- data/examples/014-text_in_polygon.rb +60 -0
- data/examples/015-boxes.rb +76 -0
- data/examples/016-frame_automatic_box_placement.rb +90 -0
- data/examples/017-frame_text_flow.rb +60 -0
- data/examples/018-composer.rb +44 -0
- data/examples/019-acro_form.rb +88 -0
- data/examples/emoji-smile.png +0 -0
- data/examples/emoji-wink.png +0 -0
- data/examples/machupicchu.jpg +0 -0
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
- data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
- data/test/data/fonts/Ubuntu-Title.ttf +0 -0
- data/test/data/images/cmyk.jpg +0 -0
- data/test/data/images/fillbytes.jpg +0 -0
- data/test/data/images/gray.jpg +0 -0
- data/test/data/images/greyscale-1bit.png +0 -0
- data/test/data/images/greyscale-2bit.png +0 -0
- data/test/data/images/greyscale-4bit.png +0 -0
- data/test/data/images/greyscale-8bit.png +0 -0
- data/test/data/images/greyscale-alpha-8bit.png +0 -0
- data/test/data/images/greyscale-trns-8bit.png +0 -0
- data/test/data/images/greyscale-with-gamma1.0.png +0 -0
- data/test/data/images/greyscale-with-gamma1.5.png +0 -0
- data/test/data/images/indexed-1bit.png +0 -0
- data/test/data/images/indexed-2bit.png +0 -0
- data/test/data/images/indexed-4bit.png +0 -0
- data/test/data/images/indexed-8bit.png +0 -0
- data/test/data/images/indexed-alpha-4bit.png +0 -0
- data/test/data/images/indexed-alpha-8bit.png +0 -0
- data/test/data/images/rgb.jpg +0 -0
- data/test/data/images/truecolour-8bit.png +0 -0
- data/test/data/images/truecolour-alpha-8bit.png +0 -0
- data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
- data/test/data/images/truecolour-srgb-8bit.png +0 -0
- data/test/data/images/ycck.jpg +0 -0
- data/test/data/minimal.pdf +44 -0
- data/test/data/standard-security-handler/README +9 -0
- data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
- data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
- data/test/hexapdf/common_tokenizer_tests.rb +236 -0
- data/test/hexapdf/content/common.rb +39 -0
- data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
- data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
- data/test/hexapdf/content/test_canvas.rb +1279 -0
- data/test/hexapdf/content/test_color_space.rb +176 -0
- data/test/hexapdf/content/test_graphics_state.rb +151 -0
- data/test/hexapdf/content/test_operator.rb +619 -0
- data/test/hexapdf/content/test_parser.rb +99 -0
- data/test/hexapdf/content/test_processor.rb +163 -0
- data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
- data/test/hexapdf/document/test_files.rb +72 -0
- data/test/hexapdf/document/test_fonts.rb +60 -0
- data/test/hexapdf/document/test_images.rb +72 -0
- data/test/hexapdf/document/test_pages.rb +130 -0
- data/test/hexapdf/encryption/common.rb +87 -0
- data/test/hexapdf/encryption/test_aes.rb +129 -0
- data/test/hexapdf/encryption/test_arc4.rb +39 -0
- data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
- data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
- data/test/hexapdf/encryption/test_identity.rb +21 -0
- data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
- data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
- data/test/hexapdf/encryption/test_security_handler.rb +380 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
- data/test/hexapdf/filter/common.rb +53 -0
- data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
- data/test/hexapdf/filter/test_crypt.rb +21 -0
- data/test/hexapdf/filter/test_encryption.rb +24 -0
- data/test/hexapdf/filter/test_flate_decode.rb +44 -0
- data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
- data/test/hexapdf/filter/test_predictor.rb +219 -0
- data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
- data/test/hexapdf/font/cmap/test_parser.rb +102 -0
- data/test/hexapdf/font/cmap/test_writer.rb +66 -0
- data/test/hexapdf/font/encoding/test_base.rb +45 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
- data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
- data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
- data/test/hexapdf/font/test_cmap.rb +104 -0
- data/test/hexapdf/font/test_encoding.rb +27 -0
- data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
- data/test/hexapdf/font/true_type/common.rb +17 -0
- data/test/hexapdf/font/true_type/table/common.rb +27 -0
- data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
- data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
- data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
- data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
- data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
- data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
- data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
- data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
- data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
- data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
- data/test/hexapdf/font/true_type/test_builder.rb +42 -0
- data/test/hexapdf/font/true_type/test_font.rb +116 -0
- data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
- data/test/hexapdf/font/true_type/test_table.rb +48 -0
- data/test/hexapdf/font/type1/common.rb +6 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
- data/test/hexapdf/font/type1/test_font.rb +104 -0
- data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
- data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
- data/test/hexapdf/font_loader/test_from_file.rb +36 -0
- data/test/hexapdf/font_loader/test_standard14.rb +33 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
- data/test/hexapdf/image_loader/test_pdf.rb +47 -0
- data/test/hexapdf/image_loader/test_png.rb +259 -0
- data/test/hexapdf/layout/test_box.rb +154 -0
- data/test/hexapdf/layout/test_frame.rb +350 -0
- data/test/hexapdf/layout/test_image_box.rb +73 -0
- data/test/hexapdf/layout/test_inline_box.rb +71 -0
- data/test/hexapdf/layout/test_line.rb +206 -0
- data/test/hexapdf/layout/test_style.rb +790 -0
- data/test/hexapdf/layout/test_text_box.rb +140 -0
- data/test/hexapdf/layout/test_text_fragment.rb +375 -0
- data/test/hexapdf/layout/test_text_layouter.rb +758 -0
- data/test/hexapdf/layout/test_text_shaper.rb +62 -0
- data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
- data/test/hexapdf/task/test_dereference.rb +51 -0
- data/test/hexapdf/task/test_optimize.rb +162 -0
- data/test/hexapdf/test_composer.rb +258 -0
- data/test/hexapdf/test_configuration.rb +93 -0
- data/test/hexapdf/test_data_dir.rb +32 -0
- data/test/hexapdf/test_dictionary.rb +340 -0
- data/test/hexapdf/test_dictionary_fields.rb +269 -0
- data/test/hexapdf/test_document.rb +641 -0
- data/test/hexapdf/test_filter.rb +100 -0
- data/test/hexapdf/test_importer.rb +106 -0
- data/test/hexapdf/test_object.rb +258 -0
- data/test/hexapdf/test_parser.rb +645 -0
- data/test/hexapdf/test_pdf_array.rb +169 -0
- data/test/hexapdf/test_rectangle.rb +73 -0
- data/test/hexapdf/test_reference.rb +50 -0
- data/test/hexapdf/test_revision.rb +188 -0
- data/test/hexapdf/test_revisions.rb +196 -0
- data/test/hexapdf/test_serializer.rb +195 -0
- data/test/hexapdf/test_stream.rb +274 -0
- data/test/hexapdf/test_tokenizer.rb +80 -0
- data/test/hexapdf/test_type.rb +18 -0
- data/test/hexapdf/test_writer.rb +140 -0
- data/test/hexapdf/test_xref_section.rb +61 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
- data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
- data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
- data/test/hexapdf/type/acro_form/test_field.rb +259 -0
- data/test/hexapdf/type/acro_form/test_form.rb +357 -0
- data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
- data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
- data/test/hexapdf/type/actions/test_launch.rb +24 -0
- data/test/hexapdf/type/actions/test_uri.rb +23 -0
- data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
- data/test/hexapdf/type/annotations/test_text.rb +34 -0
- data/test/hexapdf/type/annotations/test_widget.rb +225 -0
- data/test/hexapdf/type/test_annotation.rb +97 -0
- data/test/hexapdf/type/test_catalog.rb +48 -0
- data/test/hexapdf/type/test_cid_font.rb +61 -0
- data/test/hexapdf/type/test_file_specification.rb +141 -0
- data/test/hexapdf/type/test_font.rb +67 -0
- data/test/hexapdf/type/test_font_descriptor.rb +61 -0
- data/test/hexapdf/type/test_font_simple.rb +176 -0
- data/test/hexapdf/type/test_font_true_type.rb +31 -0
- data/test/hexapdf/type/test_font_type0.rb +120 -0
- data/test/hexapdf/type/test_font_type1.rb +142 -0
- data/test/hexapdf/type/test_font_type3.rb +26 -0
- data/test/hexapdf/type/test_form.rb +120 -0
- data/test/hexapdf/type/test_image.rb +261 -0
- data/test/hexapdf/type/test_info.rb +9 -0
- data/test/hexapdf/type/test_object_stream.rb +117 -0
- data/test/hexapdf/type/test_page.rb +598 -0
- data/test/hexapdf/type/test_page_tree_node.rb +315 -0
- data/test/hexapdf/type/test_resources.rb +209 -0
- data/test/hexapdf/type/test_trailer.rb +116 -0
- data/test/hexapdf/type/test_xref_stream.rb +143 -0
- data/test/hexapdf/utils/test_bit_field.rb +63 -0
- data/test/hexapdf/utils/test_bit_stream.rb +69 -0
- data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
- data/test/hexapdf/utils/test_lru_cache.rb +22 -0
- data/test/hexapdf/utils/test_object_hash.rb +120 -0
- data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
- data/test/test_helper.rb +58 -0
- metadata +263 -3
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/pdf_array'
|
|
5
|
+
require 'hexapdf/reference'
|
|
6
|
+
require 'hexapdf/dictionary'
|
|
7
|
+
|
|
8
|
+
describe HexaPDF::PDFArray do
|
|
9
|
+
def deref(obj)
|
|
10
|
+
if obj.kind_of?(HexaPDF::Reference)
|
|
11
|
+
HexaPDF::Object.new('deref', oid: obj.oid, gen: obj.gen)
|
|
12
|
+
else
|
|
13
|
+
obj
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add(obj)
|
|
18
|
+
HexaPDF::Object.new(obj, oid: 1)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def delete(_obj)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def wrap(obj, type:)
|
|
25
|
+
type.new(obj, document: self)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
before do
|
|
29
|
+
@array = HexaPDF::PDFArray.new([1, HexaPDF::Object.new(:data), HexaPDF::Reference.new(1, 0),
|
|
30
|
+
HexaPDF::Dictionary.new({a: 'b'})], document: self)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "after_data_change" do
|
|
34
|
+
it "uses an empty array if nil is provided" do
|
|
35
|
+
array = HexaPDF::PDFArray.new(nil)
|
|
36
|
+
assert_equal([], array.value)
|
|
37
|
+
end
|
|
38
|
+
it "fails if the value is not an array" do
|
|
39
|
+
assert_raises(ArgumentError) { HexaPDF::PDFArray.new(:Name) }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "[]" do
|
|
44
|
+
it "allows retrieving values by index" do
|
|
45
|
+
assert_equal(1, @array[0])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "allows retrieving values by start/length" do
|
|
49
|
+
assert_equal([1, :data], @array[0, 2])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "allows retrieving values by range" do
|
|
53
|
+
assert_equal([1, :data], @array[0..1])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "fetches the value out of a HexaPDF::Object" do
|
|
57
|
+
assert_equal(:data, @array[1])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "resolves references and stores the resolved object in place of the reference" do
|
|
61
|
+
assert_equal('deref', @array[2])
|
|
62
|
+
assert_kind_of(HexaPDF::Object, @array.value[2])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "[]=" do
|
|
67
|
+
it "directly stores the value if the stored value is no HexaPDF::Object" do
|
|
68
|
+
@array[0] = 2
|
|
69
|
+
assert_equal(2, @array.value[0])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "stores the value in an existing HexaPDF::Object but only if it is not such an object" do
|
|
73
|
+
@array[1] = [4, 5]
|
|
74
|
+
assert_equal([4, 5], @array.value[1].value)
|
|
75
|
+
|
|
76
|
+
@array[1] = temp = HexaPDF::Object.new(:other)
|
|
77
|
+
assert_equal(temp, @array.value[1])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "doesn't store the value inside the existing object for subclasses of HexaPDF::Object" do
|
|
81
|
+
@array[3] = [4, 5]
|
|
82
|
+
assert_equal([4, 5], @array.value[3])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "doesn't store the value inside for HexaPDF::Reference objects" do
|
|
86
|
+
@array[1] = HexaPDF::Reference.new(5, 0)
|
|
87
|
+
assert_kind_of(HexaPDF::Reference, @array.value[1])
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "allows getting multiple values at once" do
|
|
92
|
+
assert_equal([1, :data, @array[3]], @array.values_at(0, 1, 3))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "allows adding values to the end" do
|
|
96
|
+
@array << 5
|
|
97
|
+
assert_equal(5, @array[4])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "allows inserting values like Array#insert" do
|
|
101
|
+
@array.insert(1, :a, :b)
|
|
102
|
+
assert_equal([1, :a, :b, :data], @array[0, 4])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "allows deleting values at a certain index" do
|
|
106
|
+
@array.delete_at(2)
|
|
107
|
+
assert_equal([1, :data, @array[2]], @array[0, 5])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "allows deleting an object" do
|
|
111
|
+
obj = @array.value[1]
|
|
112
|
+
assert_same(obj, @array.delete(obj))
|
|
113
|
+
ref = HexaPDF::Object.new(:test, oid: 1)
|
|
114
|
+
assert_equal(ref, @array.delete(ref))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe "slice!" do
|
|
118
|
+
it "allows deleting a single element" do
|
|
119
|
+
@array.slice!(2)
|
|
120
|
+
assert_equal([1, :data, @array[2]], @array[0, 5])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "allows deleting elements given by start/length" do
|
|
124
|
+
@array.slice!(1, 2)
|
|
125
|
+
assert_equal([1, @array[1]], @array[0, 5])
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "allows deleting elements given a range" do
|
|
129
|
+
@array.slice!(1..2)
|
|
130
|
+
assert_equal([1, @array[1]], @array[0, 5])
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "allows deleting elements that are selected using a block" do
|
|
135
|
+
@array.reject! {|item| item == :data }
|
|
136
|
+
assert_equal([1, "deref", @array[2]], @array[0, 5])
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe "index" do
|
|
140
|
+
it "allows getting the index of an element" do
|
|
141
|
+
assert_equal(2, @array.index("deref"))
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "allows getting the index of the first element for which a block returns true" do
|
|
145
|
+
assert_equal(2, @array.index {|item| item == "deref" })
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "returns the length of the array" do
|
|
150
|
+
assert_equal(4, @array.length)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "allows checking for emptiness" do
|
|
154
|
+
refute(@array.empty?)
|
|
155
|
+
@array.slice!(0, 5)
|
|
156
|
+
assert(@array.empty?)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
describe "each" do
|
|
160
|
+
it "iterates over all elements in the dictionary" do
|
|
161
|
+
data = [1, :data, "deref", @array[3]]
|
|
162
|
+
@array.each {|value| assert_equal(data.shift, value) }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "can be converted to a simple array" do
|
|
167
|
+
assert_equal([1, :data, "deref", @array[3]], @array.to_ary)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/rectangle'
|
|
5
|
+
require 'hexapdf/document'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Rectangle do
|
|
8
|
+
describe "after_data_change" do
|
|
9
|
+
it "fails if the rectangle doesn't contain four numbers" do
|
|
10
|
+
assert_raises(ArgumentError) { HexaPDF::Rectangle.new([1, 2, 3]) }
|
|
11
|
+
assert_raises(ArgumentError) { HexaPDF::Rectangle.new([1, 2, 3, :a]) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "normalizes the array values" do
|
|
15
|
+
rect = HexaPDF::Rectangle.new([0, 1, 2, 3])
|
|
16
|
+
assert_equal([0, 1, 2, 3], rect.value)
|
|
17
|
+
|
|
18
|
+
rect = HexaPDF::Rectangle.new([2, 3, 0, 1])
|
|
19
|
+
assert_equal([0, 1, 2, 3], rect.value)
|
|
20
|
+
|
|
21
|
+
rect = HexaPDF::Rectangle.new([0, 3, 2, 1])
|
|
22
|
+
assert_equal([0, 1, 2, 3], rect.value)
|
|
23
|
+
|
|
24
|
+
rect = HexaPDF::Rectangle.new([2, 1, 0, 3])
|
|
25
|
+
assert_equal([0, 1, 2, 3], rect.value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "returns individual fields of the rectangle" do
|
|
30
|
+
rect = HexaPDF::Rectangle.new([2, 1, 0, 5])
|
|
31
|
+
assert_equal(0, rect.left)
|
|
32
|
+
assert_equal(2, rect.right)
|
|
33
|
+
assert_equal(1, rect.bottom)
|
|
34
|
+
assert_equal(5, rect.top)
|
|
35
|
+
assert_equal(2, rect.width)
|
|
36
|
+
assert_equal(4, rect.height)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "allows setting all fields of the rectangle" do
|
|
40
|
+
rect = HexaPDF::Rectangle.new([2, 1, 0, 5])
|
|
41
|
+
rect.left = 5
|
|
42
|
+
rect.right = 1
|
|
43
|
+
rect.bottom = 2
|
|
44
|
+
rect.top = 3
|
|
45
|
+
assert_equal([5, 2, 1, 3], rect.value)
|
|
46
|
+
|
|
47
|
+
rect.width = 10
|
|
48
|
+
assert_equal(15, rect.right)
|
|
49
|
+
rect.height = 10
|
|
50
|
+
assert_equal(12, rect.top)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "allows comparison to arrays" do
|
|
54
|
+
rect = HexaPDF::Rectangle.new([0, 1, 2, 5])
|
|
55
|
+
assert(rect == [0, 1, 2, 5])
|
|
56
|
+
rect.oid = 5
|
|
57
|
+
refute(rect == [0, 1, 2, 5])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe "validation" do
|
|
61
|
+
it "ensures that it is a correct PDF rectangle" do
|
|
62
|
+
doc = HexaPDF::Document.new
|
|
63
|
+
rect = HexaPDF::Rectangle.new([0, 1, 2, 3], document: doc)
|
|
64
|
+
assert(rect.validate)
|
|
65
|
+
|
|
66
|
+
rect.value.shift
|
|
67
|
+
refute(rect.validate)
|
|
68
|
+
|
|
69
|
+
rect.value.unshift(:A)
|
|
70
|
+
refute(rect.validate)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/reference'
|
|
5
|
+
require 'hexapdf/object'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Reference do
|
|
8
|
+
it "correctly assigns oid and gen on initialization" do
|
|
9
|
+
r = HexaPDF::Reference.new(5, 7)
|
|
10
|
+
assert_equal(5, r.oid)
|
|
11
|
+
assert_equal(7, r.gen)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "raises an error when invalid objects are supplied on initialization" do
|
|
15
|
+
assert_raises(ArgumentError) { HexaPDF::Reference.new('a', 7) }
|
|
16
|
+
assert_raises(ArgumentError) { HexaPDF::Reference.new(5, 'b') }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "is sortable w.r.t to other objects implementing #oid and #gen" do
|
|
20
|
+
obj = Object.new
|
|
21
|
+
obj.define_singleton_method(:oid) { 1 }
|
|
22
|
+
obj.define_singleton_method(:gen) { 0 }
|
|
23
|
+
obj.define_singleton_method(:<=>) {|o| HexaPDF::Reference.new(oid, gen) <=> o }
|
|
24
|
+
assert_equal([obj, HexaPDF::Reference.new(1, 1), HexaPDF::Reference.new(5, 7)],
|
|
25
|
+
[HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(1, 1), obj].sort)
|
|
26
|
+
assert_nil(HexaPDF::Reference.new(1, 0) <=> 5)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "is comparable to objects that have an oid and gen" do
|
|
30
|
+
assert_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(5, 7))
|
|
31
|
+
refute_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(5, 8))
|
|
32
|
+
refute_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Reference.new(4, 7))
|
|
33
|
+
assert_equal(HexaPDF::Reference.new(5, 7), HexaPDF::Object.new(:data, oid: 5, gen: 7))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "behaves correctly as hash key" do
|
|
37
|
+
h = {}
|
|
38
|
+
h[HexaPDF::Reference.new(5, 7)] = true
|
|
39
|
+
assert(h.key?(HexaPDF::Reference.new(5, 7)))
|
|
40
|
+
refute(h.key?(HexaPDF::Reference.new(5, 8)))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "shows the PDF serialization as string representation " do
|
|
44
|
+
assert_equal("5 7 R", HexaPDF::Reference.new(5, 7).to_s)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "shows oid and gen on inspection" do
|
|
48
|
+
assert_match(/\[5, 7\]/, HexaPDF::Reference.new(5, 7).inspect)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/revision'
|
|
5
|
+
require 'hexapdf/object'
|
|
6
|
+
require 'hexapdf/reference'
|
|
7
|
+
require 'hexapdf/xref_section'
|
|
8
|
+
require 'stringio'
|
|
9
|
+
|
|
10
|
+
describe HexaPDF::Revision do
|
|
11
|
+
before do
|
|
12
|
+
@xref_section = HexaPDF::XRefSection.new
|
|
13
|
+
@xref_section.add_in_use_entry(2, 0, 5000)
|
|
14
|
+
@xref_section.add_free_entry(3, 0)
|
|
15
|
+
@obj = HexaPDF::Object.new(:val, oid: 1, gen: 0)
|
|
16
|
+
@ref = HexaPDF::Reference.new(1, 0)
|
|
17
|
+
|
|
18
|
+
@loader = lambda do |entry|
|
|
19
|
+
if entry.type == :free
|
|
20
|
+
HexaPDF::Object.new(nil, oid: entry.oid, gen: entry.gen)
|
|
21
|
+
else
|
|
22
|
+
HexaPDF::Object.new(:Test, oid: entry.oid, gen: entry.gen)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
@rev = HexaPDF::Revision.new({}, xref_section: @xref_section, loader: @loader)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "needs the trailer as first argument on initialization" do
|
|
29
|
+
rev = HexaPDF::Revision.new({})
|
|
30
|
+
assert_equal({}, rev.trailer)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "takes an xref section and/or a parser on initialization" do
|
|
34
|
+
rev = HexaPDF::Revision.new({}, loader: @loader, xref_section: @xref_section)
|
|
35
|
+
assert_equal(:Test, rev.object(2).value)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "returns the next free object number" do
|
|
39
|
+
assert_equal(4, @rev.next_free_oid)
|
|
40
|
+
@obj.oid = 4
|
|
41
|
+
@rev.add(@obj)
|
|
42
|
+
assert_equal(5, @rev.next_free_oid)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "add" do
|
|
46
|
+
it "works correctly" do
|
|
47
|
+
@rev.add(@obj)
|
|
48
|
+
assert(@rev.object?(@ref))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "also returns the supplied object" do
|
|
52
|
+
assert_equal(@obj, @rev.add(@obj))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "fails if the revision already has an object with the same object number" do
|
|
56
|
+
@rev.add(@obj)
|
|
57
|
+
assert_raises(HexaPDF::Error) { @rev.add(@obj) }
|
|
58
|
+
assert_raises(HexaPDF::Error) { @rev.add(HexaPDF::Object.new(:val, oid: 2)) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "fails if the given object has an object number of zero" do
|
|
62
|
+
assert_raises(HexaPDF::Error) { @rev.add(HexaPDF::Object.new(:val)) }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "xref" do
|
|
67
|
+
it "returns the xref structure" do
|
|
68
|
+
assert_equal(@xref_section[2, 0], @rev.xref(HexaPDF::Reference.new(2, 0)))
|
|
69
|
+
assert_equal(@xref_section[2, 0], @rev.xref(2))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "returns nil if no xref entry is found" do
|
|
73
|
+
assert_nil(@rev.xref(@ref))
|
|
74
|
+
assert_nil(@rev.xref(1))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "object" do
|
|
79
|
+
it "returns nil if no object is found" do
|
|
80
|
+
assert_nil(@rev.object(@ref))
|
|
81
|
+
assert_nil(@rev.object(1))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "returns an object that was added before" do
|
|
85
|
+
@rev.add(@obj)
|
|
86
|
+
assert_equal(@obj, @rev.object(@ref))
|
|
87
|
+
assert_equal(@obj, @rev.object(1))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "loads an object that is defined in the cross-reference section" do
|
|
91
|
+
obj = @rev.object(HexaPDF::Reference.new(2, 0))
|
|
92
|
+
assert_equal(:Test, obj.value)
|
|
93
|
+
assert_equal(2, obj.oid)
|
|
94
|
+
assert_equal(0, obj.gen)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "loads an object that is defined in the cross-reference section using the object number" do
|
|
98
|
+
obj = @rev.object(2)
|
|
99
|
+
refute_nil(obj)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "loads free entries in the cross-reference section as special PDF null objects" do
|
|
103
|
+
obj = @rev.object(HexaPDF::Reference.new(3, 0))
|
|
104
|
+
assert_nil(obj.value)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe "update" do
|
|
109
|
+
before do
|
|
110
|
+
@rev.add(@obj)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "updates the object if it has the same data instance" do
|
|
114
|
+
x = HexaPDF::Object.new(@obj.data)
|
|
115
|
+
y = @rev.update(x)
|
|
116
|
+
assert_same(x, y)
|
|
117
|
+
refute_same(x, @obj)
|
|
118
|
+
assert_same(x, @rev.object(@ref))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "doesn't update the object if it refers to a different data instance" do
|
|
122
|
+
x = HexaPDF::Object.new(:value, oid: 5)
|
|
123
|
+
assert_nil(@rev.update(x))
|
|
124
|
+
x.data.oid = 1
|
|
125
|
+
assert_nil(@rev.update(x))
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe "delete" do
|
|
130
|
+
before do
|
|
131
|
+
@rev.add(@obj)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "deletes objects specified by reference" do
|
|
135
|
+
@rev.delete(@ref, mark_as_free: false)
|
|
136
|
+
refute(@rev.object?(@ref))
|
|
137
|
+
assert(@obj.null?)
|
|
138
|
+
assert_raises(HexaPDF::Error) { @obj.document }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "deletes objects specified by object number" do
|
|
142
|
+
@rev.delete(@ref.oid, mark_as_free: false)
|
|
143
|
+
refute(@rev.object?(@ref.oid))
|
|
144
|
+
assert(@obj.null?)
|
|
145
|
+
assert_raises(HexaPDF::Error) { @obj.document }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "marks the object as PDF null object when using mark_as_free=true" do
|
|
149
|
+
refute(@obj.null?)
|
|
150
|
+
@rev.delete(@ref)
|
|
151
|
+
assert(@rev.object(@ref).null?)
|
|
152
|
+
assert(@obj.null?)
|
|
153
|
+
assert_raises(HexaPDF::Error) { @obj.document }
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe "object iteration" do
|
|
158
|
+
it "iterates over all objects via each" do
|
|
159
|
+
@rev.add(@obj)
|
|
160
|
+
obj2 = @rev.object(2)
|
|
161
|
+
obj3 = @rev.object(3)
|
|
162
|
+
assert_equal([@obj, obj2, obj3], @rev.each.to_a)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "iterates only over loaded objects" do
|
|
166
|
+
obj = @rev.object(2)
|
|
167
|
+
assert_equal([obj], @rev.each(only_loaded: true).to_a)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "works without a cross-reference section" do
|
|
172
|
+
rev = HexaPDF::Revision.new({})
|
|
173
|
+
rev.add(@obj)
|
|
174
|
+
assert_equal(@obj, rev.object(@ref))
|
|
175
|
+
assert(rev.object?(@ref))
|
|
176
|
+
assert_equal([@obj], rev.each.to_a)
|
|
177
|
+
rev.delete(@ref, mark_as_free: false)
|
|
178
|
+
refute(rev.object?(@ref))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "can iterate over all modified objects" do
|
|
182
|
+
obj = @rev.object(2)
|
|
183
|
+
assert_equal([], @rev.each_modified_object.to_a)
|
|
184
|
+
obj.value = :Other
|
|
185
|
+
@rev.add(@obj)
|
|
186
|
+
assert_equal([obj, @obj], @rev.each_modified_object.to_a)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/revisions'
|
|
5
|
+
require 'hexapdf/document'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
|
|
8
|
+
describe HexaPDF::Revisions do
|
|
9
|
+
before do
|
|
10
|
+
@io = StringIO.new(<<~EOF)
|
|
11
|
+
%PDF-1.7
|
|
12
|
+
1 0 obj
|
|
13
|
+
10
|
|
14
|
+
endobj
|
|
15
|
+
|
|
16
|
+
2 0 obj
|
|
17
|
+
20
|
|
18
|
+
endobj
|
|
19
|
+
|
|
20
|
+
xref
|
|
21
|
+
0 3
|
|
22
|
+
0000000000 65535 f
|
|
23
|
+
0000000009 00000 n
|
|
24
|
+
0000000028 00000 n
|
|
25
|
+
trailer
|
|
26
|
+
<< /Size 3 >>
|
|
27
|
+
startxref
|
|
28
|
+
47
|
|
29
|
+
%%EOF
|
|
30
|
+
|
|
31
|
+
2 0 obj
|
|
32
|
+
300
|
|
33
|
+
endobj
|
|
34
|
+
|
|
35
|
+
3 0 obj
|
|
36
|
+
<< /Type /XRef /Size 4 /Index [2 1] /W [1 1 1] /Filter /ASCIIHexDecode /Length 6
|
|
37
|
+
>>stream
|
|
38
|
+
019E00
|
|
39
|
+
endstream
|
|
40
|
+
endobj
|
|
41
|
+
|
|
42
|
+
2 0 obj
|
|
43
|
+
200
|
|
44
|
+
endobj
|
|
45
|
+
|
|
46
|
+
xref
|
|
47
|
+
2 2
|
|
48
|
+
0000000301 00000 n
|
|
49
|
+
0000000178 00000 n
|
|
50
|
+
trailer
|
|
51
|
+
<< /Size 4 /Prev 47 >>
|
|
52
|
+
startxref
|
|
53
|
+
321
|
|
54
|
+
%%EOF
|
|
55
|
+
|
|
56
|
+
2 0 obj
|
|
57
|
+
400
|
|
58
|
+
endobj
|
|
59
|
+
|
|
60
|
+
xref
|
|
61
|
+
2 1
|
|
62
|
+
0000000422 00000 n
|
|
63
|
+
trailer
|
|
64
|
+
<< /Size 4 /Prev 321 /XRefStm 178 >>
|
|
65
|
+
startxref
|
|
66
|
+
442
|
|
67
|
+
%%EOF
|
|
68
|
+
EOF
|
|
69
|
+
@doc = HexaPDF::Document.new(io: @io)
|
|
70
|
+
@revisions = @doc.revisions
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "add" do
|
|
74
|
+
it "adds an empty revision as the current revision" do
|
|
75
|
+
rev = @revisions.add
|
|
76
|
+
assert_equal({Size: 4}, rev.trailer.value)
|
|
77
|
+
assert_equal(rev, @revisions.current)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "delete_revision" do
|
|
82
|
+
it "allows deleting a revision by index" do
|
|
83
|
+
rev = @revisions.revision(0)
|
|
84
|
+
@revisions.delete(0)
|
|
85
|
+
refute(@revisions.any? {|r| r == rev })
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "allows deleting a revision by specifying a revision" do
|
|
89
|
+
rev = @revisions.revision(0)
|
|
90
|
+
@revisions.delete(rev)
|
|
91
|
+
refute(@revisions.any? {|r| r == rev })
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "fails when trying to delete the only existing revision" do
|
|
95
|
+
assert_raises(HexaPDF::Error) { @revisions.delete(0) while @revisions.current }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe "merge" do
|
|
100
|
+
it "does nothing when only one revision is specified" do
|
|
101
|
+
@revisions.merge(1..1)
|
|
102
|
+
assert_equal(3, @revisions.each.to_a.size)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "merges the higher into the the lower revision" do
|
|
106
|
+
@revisions.merge
|
|
107
|
+
assert_equal(1, @revisions.each.to_a.size)
|
|
108
|
+
assert_equal([10, 400, @doc.object(3).value], @revisions.current.each.to_a.sort.map(&:value))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "handles objects correctly that are in multiple revisions" do
|
|
112
|
+
@revisions.current.add(@revisions[0].object(1))
|
|
113
|
+
@revisions.merge
|
|
114
|
+
assert_equal(1, @revisions.each.to_a.size)
|
|
115
|
+
assert_equal([10, 400, @doc.object(3).value], @revisions.current.each.to_a.sort.map(&:value))
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "initialize" do
|
|
120
|
+
it "automatically loads all revisions from the underlying IO object" do
|
|
121
|
+
assert_kind_of(HexaPDF::Parser, @revisions.parser)
|
|
122
|
+
assert_equal(20, @revisions.revision(0).object(2).value)
|
|
123
|
+
assert_equal(300, @revisions[1].object(2).value)
|
|
124
|
+
assert_equal(400, @revisions[2].object(2).value)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "handles invalid PDFs that have a loop via the xref /Prev or /XRefStm entries" do
|
|
129
|
+
io = StringIO.new(<<~EOF)
|
|
130
|
+
%PDF-1.7
|
|
131
|
+
1 0 obj
|
|
132
|
+
10
|
|
133
|
+
endobj
|
|
134
|
+
|
|
135
|
+
xref
|
|
136
|
+
0 2
|
|
137
|
+
0000000000 65535 f
|
|
138
|
+
0000000009 00000 n
|
|
139
|
+
trailer
|
|
140
|
+
<< /Size 2 /Prev 148>>
|
|
141
|
+
startxref
|
|
142
|
+
28
|
|
143
|
+
%%EOF
|
|
144
|
+
|
|
145
|
+
2 0 obj
|
|
146
|
+
300
|
|
147
|
+
endobj
|
|
148
|
+
|
|
149
|
+
xref
|
|
150
|
+
2 1
|
|
151
|
+
0000000301 00000 n
|
|
152
|
+
trailer
|
|
153
|
+
<< /Size 3 /Prev 28 /XRefStm 148>>
|
|
154
|
+
startxref
|
|
155
|
+
148
|
|
156
|
+
%%EOF
|
|
157
|
+
EOF
|
|
158
|
+
doc = HexaPDF::Document.new(io: io)
|
|
159
|
+
assert_equal(2, doc.revisions.count)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "uses the reconstructed revision if errors are found when loading from an IO" do
|
|
163
|
+
io = StringIO.new(<<~EOF)
|
|
164
|
+
%PDF-1.7
|
|
165
|
+
1 0 obj
|
|
166
|
+
10
|
|
167
|
+
endobj
|
|
168
|
+
|
|
169
|
+
xref
|
|
170
|
+
0 2
|
|
171
|
+
0000000000 65535 f
|
|
172
|
+
0000000009 00000 n
|
|
173
|
+
trailer
|
|
174
|
+
<< /Size 5 >>
|
|
175
|
+
startxref
|
|
176
|
+
28
|
|
177
|
+
%%EOF
|
|
178
|
+
|
|
179
|
+
2 0 obj
|
|
180
|
+
300
|
|
181
|
+
endobj
|
|
182
|
+
|
|
183
|
+
xref
|
|
184
|
+
2 1
|
|
185
|
+
0000000301 00000 n
|
|
186
|
+
trailer
|
|
187
|
+
<< /Size 3 /Prev 100>>
|
|
188
|
+
startxref
|
|
189
|
+
139
|
|
190
|
+
%%EOF
|
|
191
|
+
EOF
|
|
192
|
+
doc = HexaPDF::Document.new(io: io)
|
|
193
|
+
assert_equal(2, doc.revisions.count)
|
|
194
|
+
assert_same(doc.revisions[0].trailer.value, doc.revisions[1].trailer.value)
|
|
195
|
+
end
|
|
196
|
+
end
|