hexapdf 0.6.0 → 0.7.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 +5 -5
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTERS +1 -1
- data/LICENSE +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/hexapdf +1 -1
- data/examples/text_layouter_styling.rb +1 -2
- data/lib/hexapdf.rb +2 -2
- data/lib/hexapdf/cli.rb +3 -3
- data/lib/hexapdf/cli/batch.rb +5 -5
- data/lib/hexapdf/cli/command.rb +15 -17
- data/lib/hexapdf/cli/files.rb +3 -3
- data/lib/hexapdf/cli/images.rb +3 -4
- data/lib/hexapdf/cli/info.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +6 -6
- data/lib/hexapdf/cli/merge.rb +6 -6
- data/lib/hexapdf/cli/modify.rb +4 -4
- data/lib/hexapdf/cli/optimize.rb +3 -3
- data/lib/hexapdf/configuration.rb +4 -5
- data/lib/hexapdf/content.rb +2 -2
- data/lib/hexapdf/content/canvas.rb +35 -36
- data/lib/hexapdf/content/color_space.rb +9 -14
- data/lib/hexapdf/content/graphic_object.rb +2 -2
- data/lib/hexapdf/content/graphic_object/arc.rb +3 -3
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +4 -8
- data/lib/hexapdf/content/graphics_state.rb +4 -13
- data/lib/hexapdf/content/operator.rb +33 -35
- data/lib/hexapdf/content/parser.rb +28 -18
- data/lib/hexapdf/content/processor.rb +4 -5
- data/lib/hexapdf/content/transformation_matrix.rb +2 -2
- data/lib/hexapdf/data_dir.rb +2 -2
- data/lib/hexapdf/dictionary.rb +8 -9
- data/lib/hexapdf/dictionary_fields.rb +7 -10
- data/lib/hexapdf/document.rb +18 -18
- data/lib/hexapdf/document/files.rb +12 -10
- data/lib/hexapdf/document/fonts.rb +2 -2
- data/lib/hexapdf/document/images.rb +3 -3
- data/lib/hexapdf/document/pages.rb +4 -4
- data/lib/hexapdf/encryption.rb +2 -2
- data/lib/hexapdf/encryption/aes.rb +2 -2
- data/lib/hexapdf/encryption/arc4.rb +4 -4
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +4 -4
- data/lib/hexapdf/encryption/identity.rb +5 -4
- data/lib/hexapdf/encryption/ruby_aes.rb +147 -139
- data/lib/hexapdf/encryption/ruby_arc4.rb +4 -4
- data/lib/hexapdf/encryption/security_handler.rb +11 -12
- data/lib/hexapdf/encryption/standard_security_handler.rb +6 -9
- data/lib/hexapdf/error.rb +7 -9
- data/lib/hexapdf/filter.rb +2 -3
- data/lib/hexapdf/filter/ascii85_decode.rb +3 -3
- data/lib/hexapdf/filter/ascii_hex_decode.rb +2 -2
- data/lib/hexapdf/filter/dct_decode.rb +2 -2
- data/lib/hexapdf/filter/encryption.rb +2 -2
- data/lib/hexapdf/filter/flate_decode.rb +16 -33
- data/lib/hexapdf/filter/jpx_decode.rb +2 -2
- data/lib/hexapdf/filter/lzw_decode.rb +4 -4
- data/lib/hexapdf/filter/predictor.rb +2 -6
- data/lib/hexapdf/filter/run_length_decode.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +2 -3
- data/lib/hexapdf/font/cmap/parser.rb +11 -11
- data/lib/hexapdf/font/cmap/writer.rb +25 -25
- data/lib/hexapdf/font/encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/base.rb +2 -2
- data/lib/hexapdf/font/encoding/difference_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/glyph_list.rb +6 -6
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +2 -2
- data/lib/hexapdf/font/invalid_glyph.rb +7 -7
- data/lib/hexapdf/font/true_type.rb +2 -2
- data/lib/hexapdf/font/true_type/builder.rb +13 -7
- data/lib/hexapdf/font/true_type/font.rb +2 -3
- data/lib/hexapdf/font/true_type/optimizer.rb +2 -2
- data/lib/hexapdf/font/true_type/subsetter.rb +4 -4
- data/lib/hexapdf/font/true_type/table.rb +3 -5
- data/lib/hexapdf/font/true_type/table/cmap.rb +2 -2
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +9 -16
- data/lib/hexapdf/font/true_type/table/directory.rb +4 -4
- data/lib/hexapdf/font/true_type/table/glyf.rb +2 -2
- data/lib/hexapdf/font/true_type/table/head.rb +3 -2
- data/lib/hexapdf/font/true_type/table/hhea.rb +2 -2
- data/lib/hexapdf/font/true_type/table/hmtx.rb +2 -2
- data/lib/hexapdf/font/true_type/table/kern.rb +3 -3
- data/lib/hexapdf/font/true_type/table/loca.rb +3 -3
- data/lib/hexapdf/font/true_type/table/maxp.rb +2 -2
- data/lib/hexapdf/font/true_type/table/name.rb +3 -5
- data/lib/hexapdf/font/true_type/table/os2.rb +4 -3
- data/lib/hexapdf/font/true_type/table/post.rb +3 -7
- data/lib/hexapdf/font/true_type_wrapper.rb +20 -22
- data/lib/hexapdf/font/type1.rb +2 -2
- data/lib/hexapdf/font/type1/afm_parser.rb +7 -7
- data/lib/hexapdf/font/type1/character_metrics.rb +2 -2
- data/lib/hexapdf/font/type1/font.rb +3 -3
- data/lib/hexapdf/font/type1/font_metrics.rb +2 -4
- data/lib/hexapdf/font/type1/pfb_parser.rb +2 -2
- data/lib/hexapdf/font/type1_wrapper.rb +8 -9
- data/lib/hexapdf/font_loader.rb +2 -2
- data/lib/hexapdf/font_loader/from_configuration.rb +2 -2
- data/lib/hexapdf/font_loader/from_file.rb +2 -2
- data/lib/hexapdf/font_loader/standard14.rb +2 -2
- data/lib/hexapdf/image_loader.rb +2 -2
- data/lib/hexapdf/image_loader/jpeg.rb +6 -4
- data/lib/hexapdf/image_loader/pdf.rb +2 -2
- data/lib/hexapdf/image_loader/png.rb +6 -6
- data/lib/hexapdf/importer.rb +6 -4
- data/lib/hexapdf/layout.rb +2 -2
- data/lib/hexapdf/layout/box.rb +4 -4
- data/lib/hexapdf/layout/inline_box.rb +2 -2
- data/lib/hexapdf/layout/line.rb +6 -6
- data/lib/hexapdf/layout/numeric_refinements.rb +2 -2
- data/lib/hexapdf/layout/style.rb +17 -8
- data/lib/hexapdf/layout/text_fragment.rb +86 -48
- data/lib/hexapdf/layout/text_layouter.rb +40 -21
- data/lib/hexapdf/layout/text_shaper.rb +2 -2
- data/lib/hexapdf/name_tree_node.rb +2 -2
- data/lib/hexapdf/number_tree_node.rb +2 -2
- data/lib/hexapdf/object.rb +6 -8
- data/lib/hexapdf/parser.rb +10 -10
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/reference.rb +2 -2
- data/lib/hexapdf/revision.rb +4 -4
- data/lib/hexapdf/revisions.rb +5 -5
- data/lib/hexapdf/serializer.rb +27 -24
- data/lib/hexapdf/stream.rb +4 -4
- data/lib/hexapdf/task.rb +2 -2
- data/lib/hexapdf/task/dereference.rb +4 -4
- data/lib/hexapdf/task/optimize.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +12 -14
- data/lib/hexapdf/type.rb +2 -2
- data/lib/hexapdf/type/action.rb +3 -3
- data/lib/hexapdf/type/actions.rb +2 -2
- data/lib/hexapdf/type/actions/go_to.rb +2 -2
- data/lib/hexapdf/type/actions/go_to_r.rb +2 -2
- data/lib/hexapdf/type/actions/launch.rb +2 -2
- data/lib/hexapdf/type/actions/uri.rb +3 -3
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations.rb +2 -2
- data/lib/hexapdf/type/annotations/link.rb +2 -2
- data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -2
- data/lib/hexapdf/type/annotations/text.rb +2 -2
- data/lib/hexapdf/type/catalog.rb +4 -4
- data/lib/hexapdf/type/cid_font.rb +4 -5
- data/lib/hexapdf/type/embedded_file.rb +3 -3
- data/lib/hexapdf/type/file_specification.rb +6 -7
- data/lib/hexapdf/type/font.rb +4 -4
- data/lib/hexapdf/type/font_descriptor.rb +3 -4
- data/lib/hexapdf/type/font_simple.rb +12 -16
- data/lib/hexapdf/type/font_true_type.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +5 -5
- data/lib/hexapdf/type/font_type1.rb +4 -4
- data/lib/hexapdf/type/form.rb +3 -3
- data/lib/hexapdf/type/graphics_state_parameter.rb +3 -3
- data/lib/hexapdf/type/image.rb +13 -14
- data/lib/hexapdf/type/info.rb +2 -2
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +5 -5
- data/lib/hexapdf/type/page.rb +9 -10
- data/lib/hexapdf/type/page_tree_node.rb +5 -6
- data/lib/hexapdf/type/resources.rb +11 -11
- data/lib/hexapdf/type/trailer.rb +3 -3
- data/lib/hexapdf/type/viewer_preferences.rb +2 -2
- data/lib/hexapdf/type/xref_stream.rb +8 -4
- data/lib/hexapdf/utils/bit_field.rb +4 -4
- data/lib/hexapdf/utils/bit_stream.rb +4 -4
- data/lib/hexapdf/utils/graphics_helpers.rb +2 -2
- data/lib/hexapdf/utils/lru_cache.rb +2 -2
- data/lib/hexapdf/utils/math_helpers.rb +2 -2
- data/lib/hexapdf/utils/object_hash.rb +3 -3
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +3 -3
- data/lib/hexapdf/utils/sorted_tree_node.rb +12 -11
- data/lib/hexapdf/version.rb +3 -3
- data/lib/hexapdf/writer.rb +8 -8
- data/lib/hexapdf/xref_section.rb +3 -3
- data/test/hexapdf/common_tokenizer_tests.rb +6 -7
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +0 -1
- data/test/hexapdf/content/test_canvas.rb +28 -36
- data/test/hexapdf/content/test_color_space.rb +4 -0
- data/test/hexapdf/content/test_graphics_state.rb +2 -0
- data/test/hexapdf/content/test_operator.rb +6 -7
- data/test/hexapdf/content/test_parser.rb +2 -2
- data/test/hexapdf/content/test_processor.rb +1 -1
- data/test/hexapdf/document/test_files.rb +1 -0
- data/test/hexapdf/document/test_images.rb +1 -1
- data/test/hexapdf/encryption/common.rb +3 -3
- data/test/hexapdf/encryption/test_aes.rb +10 -4
- data/test/hexapdf/encryption/test_identity.rb +1 -1
- data/test/hexapdf/encryption/test_security_handler.rb +13 -17
- data/test/hexapdf/encryption/test_standard_security_handler.rb +12 -12
- data/test/hexapdf/filter/test_ascii85_decode.rb +2 -3
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +6 -1
- data/test/hexapdf/filter/test_flate_decode.rb +2 -2
- data/test/hexapdf/filter/test_lzw_decode.rb +10 -10
- data/test/hexapdf/filter/test_predictor.rb +10 -2
- data/test/hexapdf/filter/test_run_length_decode.rb +1 -1
- data/test/hexapdf/font/cmap/test_parser.rb +40 -40
- data/test/hexapdf/font/cmap/test_writer.rb +29 -29
- data/test/hexapdf/font/test_true_type_wrapper.rb +3 -2
- data/test/hexapdf/font/true_type/common.rb +2 -0
- data/test/hexapdf/font/true_type/table/test_cmap.rb +1 -1
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +5 -4
- data/test/hexapdf/font/true_type/table/test_glyf.rb +2 -2
- data/test/hexapdf/font/true_type/table/test_head.rb +2 -2
- data/test/hexapdf/font/true_type/table/test_name.rb +9 -6
- data/test/hexapdf/font/true_type/test_builder.rb +8 -3
- data/test/hexapdf/font/true_type/test_optimizer.rb +1 -2
- data/test/hexapdf/font/type1/test_afm_parser.rb +2 -2
- data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
- data/test/hexapdf/image_loader/test_pdf.rb +1 -1
- data/test/hexapdf/image_loader/test_png.rb +3 -3
- data/test/hexapdf/layout/test_inline_box.rb +10 -1
- data/test/hexapdf/layout/test_line.rb +4 -4
- data/test/hexapdf/layout/test_style.rb +19 -7
- data/test/hexapdf/layout/test_text_fragment.rb +73 -27
- data/test/hexapdf/layout/test_text_layouter.rb +84 -68
- data/test/hexapdf/layout/test_text_shaper.rb +4 -6
- data/test/hexapdf/task/test_dereference.rb +2 -2
- data/test/hexapdf/task/test_optimize.rb +16 -7
- data/test/hexapdf/test_configuration.rb +1 -1
- data/test/hexapdf/test_data_dir.rb +2 -2
- data/test/hexapdf/test_dictionary.rb +6 -3
- data/test/hexapdf/test_dictionary_fields.rb +15 -14
- data/test/hexapdf/test_document.rb +47 -48
- data/test/hexapdf/test_filter.rb +30 -26
- data/test/hexapdf/test_importer.rb +14 -0
- data/test/hexapdf/test_object.rb +16 -4
- data/test/hexapdf/test_parser.rb +36 -36
- data/test/hexapdf/test_reference.rb +7 -5
- data/test/hexapdf/test_revision.rb +1 -1
- data/test/hexapdf/test_revisions.rb +90 -90
- data/test/hexapdf/test_serializer.rb +3 -2
- data/test/hexapdf/test_stream.rb +2 -4
- data/test/hexapdf/test_tokenizer.rb +2 -2
- data/test/hexapdf/test_writer.rb +80 -80
- data/test/hexapdf/test_xref_section.rb +1 -1
- data/test/hexapdf/type/annotations/test_link.rb +1 -1
- data/test/hexapdf/type/annotations/test_text.rb +3 -3
- data/test/hexapdf/type/test_font_descriptor.rb +1 -1
- data/test/hexapdf/type/test_font_simple.rb +2 -2
- data/test/hexapdf/type/test_font_type0.rb +0 -1
- data/test/hexapdf/type/test_image.rb +0 -3
- data/test/hexapdf/type/test_object_stream.rb +2 -1
- data/test/hexapdf/type/test_page.rb +5 -1
- data/test/hexapdf/type/test_page_tree_node.rb +4 -4
- data/test/hexapdf/type/test_trailer.rb +1 -1
- data/test/hexapdf/type/test_xref_stream.rb +4 -0
- data/test/hexapdf/utils/test_bit_field.rb +2 -0
- data/test/hexapdf/utils/test_bit_stream.rb +1 -1
- data/test/hexapdf/utils/test_lru_cache.rb +1 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -4
- data/test/test_helper.rb +3 -6
- metadata +3 -3
|
@@ -45,8 +45,8 @@ describe HexaPDF::Content::Parser do
|
|
|
45
45
|
assert_equal([[:inline_image, [{CS: :RGB}, @image_data]],
|
|
46
46
|
[:restore_graphics_state],
|
|
47
47
|
[:save_graphics_state],
|
|
48
|
-
[:concatenate_matrix, [1308, 0, 0, 1, 485.996, 4531.67]]
|
|
49
|
-
|
|
48
|
+
[:concatenate_matrix, [1308, 0, 0, 1, 485.996, 4531.67]]],
|
|
49
|
+
@processor.recorded_ops)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it "parses a content stream with an inline image with EI in image data at end of stream" do
|
|
@@ -141,7 +141,7 @@ describe HexaPDF::Content::Processor do
|
|
|
141
141
|
lry = @font.bounding_box[3] / 1000.0 * @processor.graphics_state.font_size +
|
|
142
142
|
@processor.graphics_state.text_rise
|
|
143
143
|
arr = ["Hül".encode("Windows-1252"), 20, " le".encode("Windows-1252")]
|
|
144
|
-
width = "Hül le".encode("Windows-1252").codepoints.inject(0) {|s, cp| s + @font.width(cp)}
|
|
144
|
+
width = "Hül le".encode("Windows-1252").codepoints.inject(0) {|s, cp| s + @font.width(cp) }
|
|
145
145
|
width = (width - 20) * @processor.graphics_state.scaled_font_size +
|
|
146
146
|
6 * @processor.graphics_state.scaled_character_spacing +
|
|
147
147
|
@processor.graphics_state.scaled_word_spacing
|
|
@@ -53,6 +53,7 @@ describe HexaPDF::Document::Files do
|
|
|
53
53
|
@doc.add(Type: :Filespec)
|
|
54
54
|
spec1 = @doc.files.add(__FILE__)
|
|
55
55
|
spec2 = @doc.add(Type: :Filespec)
|
|
56
|
+
@doc.pages.add # page without annot
|
|
56
57
|
@doc.pages.add[:Annots] = [
|
|
57
58
|
{Subtype: :FileAttachment, FS: HexaPDF::Reference.new(spec1.oid, spec1.gen)},
|
|
58
59
|
{Subtype: :FileAttachment, FS: spec2},
|
|
@@ -13,7 +13,7 @@ describe HexaPDF::Document::Images do
|
|
|
13
13
|
describe "using a custom image loader" do
|
|
14
14
|
before do
|
|
15
15
|
@loader = Object.new
|
|
16
|
-
@loader.define_singleton_method(:handles?) {|*| true}
|
|
16
|
+
@loader.define_singleton_method(:handles?) {|*| true }
|
|
17
17
|
@loader.define_singleton_method(:load) do |doc, s|
|
|
18
18
|
s = HexaPDF::StreamData.new(s) if s.kind_of?(IO)
|
|
19
19
|
doc.add({Subtype: :Image}, stream: s)
|
|
@@ -30,7 +30,7 @@ module AESEncryptionTests
|
|
|
30
30
|
TEST_VECTOR_FILES.each do |filename|
|
|
31
31
|
name, size, mode = File.basename(filename, '.data.gz').split('-')
|
|
32
32
|
size = size.to_i / 8
|
|
33
|
-
data = Zlib::GzipReader.open(filename
|
|
33
|
+
data = Zlib::GzipReader.open(filename, &:read).force_encoding(Encoding::BINARY)
|
|
34
34
|
data.scan(/(.{#{size}})(.{16})(.{16})(.{16})/m).each_with_index do |(key, iv, plain, cipher), index|
|
|
35
35
|
aes = @algorithm_class.new(key, iv, mode.intern)
|
|
36
36
|
assert_equal(cipher, aes.process(plain),
|
|
@@ -66,8 +66,8 @@ module ARC4EncryptionTests
|
|
|
66
66
|
def setup
|
|
67
67
|
super
|
|
68
68
|
@encrypted = ['BBF316E8D940AF0AD3', '1021BF0420', '45A01F645FC35B383552544B9BF5'].
|
|
69
|
-
map {|c| [c].pack('H*')}
|
|
70
|
-
@plain = ['Plaintext', 'pedia', 'Attack at dawn'].each {|s| s.force_encoding('BINARY')}
|
|
69
|
+
map {|c| [c].pack('H*') }
|
|
70
|
+
@plain = ['Plaintext', 'pedia', 'Attack at dawn'].each {|s| s.force_encoding('BINARY') }
|
|
71
71
|
@keys = ['Key', 'Wiki', 'Secret']
|
|
72
72
|
end
|
|
73
73
|
|
|
@@ -17,13 +17,17 @@ describe HexaPDF::Encryption::AES do
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def process(data)
|
|
20
|
-
raise "invalid data" if data.
|
|
20
|
+
raise "invalid data" if data.empty? || data.length % 16 != 0
|
|
21
21
|
data
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
@padding_data = (0..15).map do |length|
|
|
26
|
-
{
|
|
26
|
+
{
|
|
27
|
+
plain: '5' * length,
|
|
28
|
+
cipher_padding: '5' * length + (16 - length).chr * (16 - length),
|
|
29
|
+
length: 32,
|
|
30
|
+
}
|
|
27
31
|
end
|
|
28
32
|
@padding_data << {plain: '5' * 16, cipher_padding: '5' * 16 + 16.chr * 16, length: 48}
|
|
29
33
|
end
|
|
@@ -73,7 +77,8 @@ describe HexaPDF::Encryption::AES do
|
|
|
73
77
|
|
|
74
78
|
it "returns the decrypted result without padding and with IV removed on decryption_fiber" do
|
|
75
79
|
@padding_data.each do |data|
|
|
76
|
-
result = @algorithm_class.decryption_fiber('some key' * 2,
|
|
80
|
+
result = @algorithm_class.decryption_fiber('some key' * 2,
|
|
81
|
+
Fiber.new { 'iv' * 8 + data[:cipher_padding] })
|
|
77
82
|
result = TestHelper.collector(result)
|
|
78
83
|
assert_equal(data[:plain], result)
|
|
79
84
|
end
|
|
@@ -106,7 +111,8 @@ describe HexaPDF::Encryption::AES do
|
|
|
106
111
|
it "fails on decryption if not enough bytes are provided" do
|
|
107
112
|
[4, 20, 40].each do |length|
|
|
108
113
|
assert_raises(HexaPDF::EncryptionError) do
|
|
109
|
-
TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4,
|
|
114
|
+
TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4,
|
|
115
|
+
Fiber.new { 'a' * length }))
|
|
110
116
|
end
|
|
111
117
|
end
|
|
112
118
|
end
|
|
@@ -15,7 +15,7 @@ describe HexaPDF::Encryption::Identity do
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it "returns the source Fiber unmodified for encryption_fiber/decryption_fiber" do
|
|
18
|
-
f = Fiber.new {'data'}
|
|
18
|
+
f = Fiber.new { 'data' }
|
|
19
19
|
assert_equal(f, @algorithm_class.encryption_fiber('key', f))
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -58,7 +58,6 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
58
58
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
|
|
62
61
|
before do
|
|
63
62
|
@document = HexaPDF::Document.new
|
|
64
63
|
@obj = @document.add({})
|
|
@@ -70,7 +69,7 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
70
69
|
@document.config['encryption.filter_map'][:Test] = TestHandler
|
|
71
70
|
end
|
|
72
71
|
|
|
73
|
-
describe "
|
|
72
|
+
describe "set_up_encryption" do
|
|
74
73
|
it "fails if the requested security handler cannot be found" do
|
|
75
74
|
assert_raises(HexaPDF::EncryptionError) do
|
|
76
75
|
HexaPDF::Encryption::SecurityHandler.set_up_encryption(@document, :non_standard)
|
|
@@ -125,7 +124,7 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
125
124
|
it "sets the correct /V value for the given key length and algorithm" do
|
|
126
125
|
[[40, :arc4, 1], [128, :arc4, 2], [128, :arc4, 4],
|
|
127
126
|
[128, :aes, 4], [256, :aes, 5]].each do |length, algorithm, version|
|
|
128
|
-
@handler.set_up_encryption(key_length: length, algorithm: algorithm,
|
|
127
|
+
@handler.set_up_encryption(key_length: length, algorithm: algorithm, force_v4: version == 4)
|
|
129
128
|
assert_equal(version, @handler.dict[:V])
|
|
130
129
|
end
|
|
131
130
|
end
|
|
@@ -200,9 +199,8 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
200
199
|
end
|
|
201
200
|
end
|
|
202
201
|
|
|
203
|
-
|
|
204
202
|
describe "set_up_decryption" do
|
|
205
|
-
it "
|
|
203
|
+
it "wraps the given hash in an encryption dictionary class, uses it for its dict, returns it" do
|
|
206
204
|
dict = @handler.set_up_decryption(Filter: :test, V: 1)
|
|
207
205
|
assert_equal(dict, @handler.dict)
|
|
208
206
|
assert_kind_of(HexaPDF::Encryption::EncryptionDictionary, @handler.dict)
|
|
@@ -222,13 +220,14 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
222
220
|
it "selects the correct algorithm based on the /V and /CF values" do
|
|
223
221
|
@enc = @handler.dup
|
|
224
222
|
|
|
225
|
-
[
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
223
|
+
[
|
|
224
|
+
[:arc4, 40, {V: 1}],
|
|
225
|
+
[:arc4, 80, {V: 2, Length: 80}],
|
|
226
|
+
[:arc4, 128, {V: 4, StrF: :Mine, CF: {Mine: {CFM: :V2}}}],
|
|
227
|
+
[:aes, 128, {V: 4, StrF: :Mine, CF: {Mine: {CFM: :AESV2}}}],
|
|
228
|
+
[:aes, 256, {V: 5, StrF: :Mine, CF: {Mine: {CFM: :AESV3}}}],
|
|
229
|
+
[:identity, 128, {V: 4, StrF: :Mine, CF: {Mine: {CFM: :None}}}],
|
|
230
|
+
[:identity, 128, {V: 4, CF: {Mine: {CFM: :AESV2}}}],
|
|
232
231
|
].each do |alg, length, dict|
|
|
233
232
|
@enc.strf = alg
|
|
234
233
|
@enc.set_up_encryption(key_length: length, algorithm: (alg == :identity ? :aes : alg))
|
|
@@ -239,8 +238,8 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
239
238
|
end
|
|
240
239
|
|
|
241
240
|
it "selects the correct algorithm for string, stream and embedded file decryption" do
|
|
242
|
-
@handler.set_up_decryption(
|
|
243
|
-
|
|
241
|
+
@handler.set_up_decryption(V: 4, StrF: :Mine, StmF: :Mine, EFF: :Mine,
|
|
242
|
+
CF: {Mine: {CFM: :V2}})
|
|
244
243
|
assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:embedded_file_algorithm))
|
|
245
244
|
assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:string_algorithm))
|
|
246
245
|
assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:stream_algorithm))
|
|
@@ -268,7 +267,6 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
268
267
|
end
|
|
269
268
|
end
|
|
270
269
|
|
|
271
|
-
|
|
272
270
|
describe "decrypt" do
|
|
273
271
|
before do
|
|
274
272
|
@handler.set_up_decryption(V: 1)
|
|
@@ -307,7 +305,6 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
307
305
|
end
|
|
308
306
|
end
|
|
309
307
|
|
|
310
|
-
|
|
311
308
|
describe "encryption" do
|
|
312
309
|
before do
|
|
313
310
|
@handler.set_up_encryption(key_length: 128, algorithm: :arc4)
|
|
@@ -337,7 +334,6 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
|
337
334
|
end
|
|
338
335
|
end
|
|
339
336
|
|
|
340
|
-
|
|
341
337
|
it "works correctly with different decryption and encryption handlers" do
|
|
342
338
|
test_file = File.join(TEST_DATA_DIR, 'standard-security-handler', 'nopwd-arc4-40bit-V1.pdf')
|
|
343
339
|
doc = HexaPDF::Document.new(io: StringIO.new(File.read(test_file)))
|
|
@@ -89,7 +89,6 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
|
|
93
92
|
before do
|
|
94
93
|
@document = HexaPDF::Document.new
|
|
95
94
|
@handler = HexaPDF::Encryption::StandardSecurityHandler.new(@document)
|
|
@@ -125,10 +124,12 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
125
124
|
|
|
126
125
|
it "sets the correct revision independent /P value" do
|
|
127
126
|
dict = @handler.set_up_encryption
|
|
128
|
-
assert_equal(@handler.class::Permissions::ALL |
|
|
127
|
+
assert_equal(@handler.class::Permissions::ALL | \
|
|
128
|
+
@handler.class::Permissions::RESERVED - 2**32,
|
|
129
129
|
dict[:P])
|
|
130
130
|
dict = @handler.set_up_encryption(permissions: @handler.class::Permissions::COPY_CONTENT)
|
|
131
|
-
assert_equal(@handler.class::Permissions::COPY_CONTENT |
|
|
131
|
+
assert_equal(@handler.class::Permissions::COPY_CONTENT | \
|
|
132
|
+
@handler.class::Permissions::RESERVED - 2**32,
|
|
132
133
|
dict[:P])
|
|
133
134
|
dict = @handler.set_up_encryption(permissions: [:modify_content, :modify_annotation])
|
|
134
135
|
assert_equal(@handler.class::Permissions::MODIFY_CONTENT | \
|
|
@@ -171,7 +172,7 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
171
172
|
assert_equal(:StdCF, d[:StmF])
|
|
172
173
|
end
|
|
173
174
|
|
|
174
|
-
dict = @handler.set_up_encryption(key_length: 128, algorithm: :arc4,
|
|
175
|
+
dict = @handler.set_up_encryption(key_length: 128, algorithm: :arc4, force_v4: true)
|
|
175
176
|
refute(dict.value.key?(:UE))
|
|
176
177
|
refute(dict.value.key?(:OE))
|
|
177
178
|
refute(dict.value.key?(:Perms))
|
|
@@ -190,12 +191,12 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
190
191
|
crypt_filter.call(dict, 6, :AESV3, 32)
|
|
191
192
|
end
|
|
192
193
|
|
|
193
|
-
it "uses the password keyword as fallback, the user password as owner password if
|
|
194
|
-
dict1 = @
|
|
195
|
-
dict2 = @
|
|
196
|
-
dict3 = @
|
|
197
|
-
dict4 = @
|
|
198
|
-
dict5 = @
|
|
194
|
+
it "uses the password keyword as fallback, the user password as owner password if necessary" do
|
|
195
|
+
dict1 = @handler.set_up_encryption(password: 'user', owner_password: 'owner')
|
|
196
|
+
dict2 = @handler.set_up_encryption(password: 'owner', user_password: 'user')
|
|
197
|
+
dict3 = @handler.set_up_encryption(user_password: 'user', owner_password: 'owner')
|
|
198
|
+
dict4 = @handler.set_up_encryption(user_password: 'test', owner_password: 'test')
|
|
199
|
+
dict5 = @handler.set_up_encryption(user_password: 'test')
|
|
199
200
|
|
|
200
201
|
assert_equal(dict1[:U], dict2[:U])
|
|
201
202
|
assert_equal(dict2[:U], dict3[:U])
|
|
@@ -213,7 +214,6 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
213
214
|
end
|
|
214
215
|
end
|
|
215
216
|
|
|
216
|
-
|
|
217
217
|
describe "prepare_decryption" do
|
|
218
218
|
it "fails if the /Filter value is incorrect" do
|
|
219
219
|
exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
|
|
@@ -278,7 +278,7 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
278
278
|
end
|
|
279
279
|
end
|
|
280
280
|
|
|
281
|
-
it "encryption key stays valid even if default
|
|
281
|
+
it "encryption key stays valid even if default dict values are set while setting up decryption" do
|
|
282
282
|
@document.encrypt(key_length: 128, algorithm: :aes)
|
|
283
283
|
assert(@document.security_handler.encryption_key_valid?)
|
|
284
284
|
|
|
@@ -13,8 +13,7 @@ describe HexaPDF::Filter::ASCII85Decode do
|
|
|
13
13
|
['Nov shmoz ka pop.12', ':2b:uF(fE/H6@!3+E27</ho*~>'],
|
|
14
14
|
['Nov shmoz ka pop.123', ':2b:uF(fE/H6@!3+E27</ho+;~>'],
|
|
15
15
|
["\0\0\0\0Nov shmoz ka pop.", 'z:2b:uF(fE/H6@!3+E27</c~>'],
|
|
16
|
-
["Nov \x0\x0\x0\x0shmoz ka pop.", ':2b:uzF(fE/H6@!3+E27</c~>']
|
|
17
|
-
]
|
|
16
|
+
["Nov \x0\x0\x0\x0shmoz ka pop.", ':2b:uzF(fE/H6@!3+E27</c~>']]
|
|
18
17
|
@decoded = @all_test_cases[0][0]
|
|
19
18
|
@encoded = @all_test_cases[0][1]
|
|
20
19
|
end
|
|
@@ -25,7 +24,7 @@ describe HexaPDF::Filter::ASCII85Decode do
|
|
|
25
24
|
end
|
|
26
25
|
|
|
27
26
|
it "ignores whitespace in the input" do
|
|
28
|
-
encoded = @encoded.dup.scan(/./).map {|a| "#{a} \r\t"}.join("\n")
|
|
27
|
+
encoded = @encoded.dup.scan(/./).map {|a| "#{a} \r\t" }.join("\n")
|
|
29
28
|
assert_equal(@decoded, collector(@obj.decoder(feeder(encoded))))
|
|
30
29
|
end
|
|
31
30
|
|
|
@@ -15,7 +15,8 @@ describe HexaPDF::Filter::ASCIIHexDecode do
|
|
|
15
15
|
|
|
16
16
|
describe "decoder" do
|
|
17
17
|
it "ignores whitespace in the input" do
|
|
18
|
-
|
|
18
|
+
with_whitespace = @encoded.scan(/./).map {|a| "#{a} \r\t" }.join("\n")
|
|
19
|
+
assert_equal(@decoded, collector(@obj.decoder(feeder(with_whitespace, 1))))
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
it "works without the EOD marker" do
|
|
@@ -26,6 +27,10 @@ describe HexaPDF::Filter::ASCIIHexDecode do
|
|
|
26
27
|
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded + '4e6f7gzz'))))
|
|
27
28
|
end
|
|
28
29
|
|
|
30
|
+
it "assumes the missing char is '0' if the input length is odd" do
|
|
31
|
+
assert_equal(@decoded.chop << ' ', collector(@obj.decoder(feeder(@encoded.chop.chop))))
|
|
32
|
+
end
|
|
33
|
+
|
|
29
34
|
it "fails on invalid characters" do
|
|
30
35
|
assert_raises(HexaPDF::FilterError) { @obj.decoder(feeder('f0f0z')).resume }
|
|
31
36
|
end
|
|
@@ -18,7 +18,7 @@ describe HexaPDF::Filter::FlateDecode do
|
|
|
18
18
|
|
|
19
19
|
describe "decoder" do
|
|
20
20
|
it "applies the Predictor after decoding" do
|
|
21
|
-
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded_predictor
|
|
21
|
+
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded_predictor), @predictor_opts)))
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it "fails on invalid input" do
|
|
@@ -29,7 +29,7 @@ describe HexaPDF::Filter::FlateDecode do
|
|
|
29
29
|
|
|
30
30
|
describe "encoder" do
|
|
31
31
|
it "applies the Predictor before encoding" do
|
|
32
|
-
assert_equal(@encoded_predictor, collector(@obj.encoder(feeder(@decoded
|
|
32
|
+
assert_equal(@encoded_predictor, collector(@obj.encoder(feeder(@decoded), @predictor_opts)))
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
@@ -8,18 +8,18 @@ describe HexaPDF::Filter::LZWDecode do
|
|
|
8
8
|
|
|
9
9
|
before do
|
|
10
10
|
@obj = HexaPDF::Filter::LZWDecode
|
|
11
|
-
@all_test_cases ||= [["-----A---B", "\x80\x0b\x60\x50\x22\x0c\x0c\x85\x01"],
|
|
12
|
-
['abcabcaaaabbbcdeffffffagggggg'
|
|
13
|
-
|
|
11
|
+
@all_test_cases ||= [["-----A---B".b, "\x80\x0b\x60\x50\x22\x0c\x0c\x85\x01".b],
|
|
12
|
+
['abcabcaaaabbbcdeffffffagggggg'.b,
|
|
13
|
+
"\x80\x18LF8\x14\x10\xC3\a1BLfC)\x9A\x1D\x0F0\x99\xE2Q8\b".b]]
|
|
14
14
|
@decoded = @all_test_cases[0][0]
|
|
15
15
|
@encoded = @all_test_cases[0][1]
|
|
16
|
-
@encoded_predictor = "\x80\x00\x85\xA0 \x04\x12\r\x05\n\x00\x9D\x90p\x10V\x02".
|
|
16
|
+
@encoded_predictor = "\x80\x00\x85\xA0 \x04\x12\r\x05\n\x00\x9D\x90p\x10V\x02".b
|
|
17
17
|
@predictor_opts = {Predictor: 12}
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
describe "decoder" do
|
|
21
21
|
it "applies the Predictor after decoding" do
|
|
22
|
-
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded_predictor
|
|
22
|
+
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded_predictor), @predictor_opts)))
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it "fails if an unknown code is found after CLEAR_TABLE" do
|
|
@@ -34,10 +34,10 @@ describe HexaPDF::Filter::LZWDecode do
|
|
|
34
34
|
stream = HexaPDF::Utils::BitStreamWriter.new
|
|
35
35
|
result = stream.write(256, 9)
|
|
36
36
|
result << stream.write(65, 9)
|
|
37
|
-
258.upto(510) {|i| result << stream.write(i, 9)}
|
|
38
|
-
511.upto(1022) {|i| result << stream.write(i, 10)}
|
|
39
|
-
1023.upto(2046) {|i| result << stream.write(i, 11)}
|
|
40
|
-
2047.upto(4095) {|i| result << stream.write(i, 12)}
|
|
37
|
+
258.upto(510) {|i| result << stream.write(i, 9) }
|
|
38
|
+
511.upto(1022) {|i| result << stream.write(i, 10) }
|
|
39
|
+
1023.upto(2046) {|i| result << stream.write(i, 11) }
|
|
40
|
+
2047.upto(4095) {|i| result << stream.write(i, 12) }
|
|
41
41
|
result << stream.write(96, 12)
|
|
42
42
|
result << stream.finalize
|
|
43
43
|
assert_raises(HexaPDF::FilterError) { @obj.decoder(feeder(result)).resume }
|
|
@@ -46,7 +46,7 @@ describe HexaPDF::Filter::LZWDecode do
|
|
|
46
46
|
|
|
47
47
|
describe "encoder" do
|
|
48
48
|
it "applies the Predictor before encoding" do
|
|
49
|
-
assert_equal(@encoded_predictor, collector(@obj.encoder(feeder(@decoded
|
|
49
|
+
assert_equal(@encoded_predictor, collector(@obj.encoder(feeder(@decoded), @predictor_opts)))
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -9,13 +9,15 @@ describe HexaPDF::Filter::Predictor do
|
|
|
9
9
|
module CommonPredictorTests
|
|
10
10
|
def test_decoding_through_decoder_method
|
|
11
11
|
@testcases.each do |name, data|
|
|
12
|
-
assert_equal(data[:source], collector(@obj.decoder(feeder(data[:result].dup), data)),
|
|
12
|
+
assert_equal(data[:source], collector(@obj.decoder(feeder(data[:result].dup), data)),
|
|
13
|
+
"test case: #{name}")
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def test_encoding_through_encoder_method
|
|
17
18
|
@testcases.each do |name, data|
|
|
18
|
-
assert_equal(data[:result], collector(@obj.encoder(feeder(data[:source].dup), data)),
|
|
19
|
+
assert_equal(data[:result], collector(@obj.encoder(feeder(data[:source].dup), data)),
|
|
20
|
+
"test case: #{name}")
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
end
|
|
@@ -31,6 +33,12 @@ describe HexaPDF::Filter::Predictor do
|
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
|
|
36
|
+
it "just returns the source if no processing needs to be done" do
|
|
37
|
+
source = feeder("test")
|
|
38
|
+
assert_same(source, @obj.encoder(source, Predictor: 1))
|
|
39
|
+
assert_same(source, @obj.encoder(source, {}))
|
|
40
|
+
end
|
|
41
|
+
|
|
34
42
|
describe "png predictor" do
|
|
35
43
|
include CommonPredictorTests
|
|
36
44
|
|
|
@@ -25,7 +25,7 @@ describe HexaPDF::Filter::RunLengthDecode do
|
|
|
25
25
|
|
|
26
26
|
describe "encoder" do
|
|
27
27
|
it "works with single byte input" do
|
|
28
|
-
assert_equal(@encoded.chars.map {|a| "\0#{a}"}.join << "\x80".
|
|
28
|
+
assert_equal(@encoded.chars.map {|a| "\0#{a}" }.join << "\x80".b,
|
|
29
29
|
collector(@obj.encoder(feeder(@encoded.dup, 1))))
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -6,46 +6,46 @@ require 'hexapdf/font/cmap/parser'
|
|
|
6
6
|
describe HexaPDF::Font::CMap::Parser do
|
|
7
7
|
describe "::parse" do
|
|
8
8
|
it "parses CMap data correctly" do
|
|
9
|
-
data =
|
|
10
|
-
/CIDInit /ProcSet findresource begin
|
|
11
|
-
12 dict begin
|
|
12
|
-
begincmap
|
|
13
|
-
/H usecmap
|
|
14
|
-
/CIDSystemInfo
|
|
15
|
-
<< /Registry (Adobe)
|
|
16
|
-
/Ordering (UCS)
|
|
17
|
-
/Supplement 0
|
|
18
|
-
>> def
|
|
19
|
-
/CMapName /Adobe-Identity-UCS def
|
|
20
|
-
/CMapType 2 def
|
|
21
|
-
/WMode 0 def
|
|
22
|
-
4 begincodespacerange
|
|
23
|
-
<00> <20>
|
|
24
|
-
<8140> <9ffc>
|
|
25
|
-
<a0> <de>
|
|
26
|
-
<e040> <fbec>
|
|
27
|
-
endcodespacerange
|
|
28
|
-
2 begincidchar
|
|
29
|
-
<8143> 8286
|
|
30
|
-
<8144> 8274
|
|
31
|
-
endcidchar
|
|
32
|
-
2 begincidrange
|
|
33
|
-
<8145> <8145> 8123
|
|
34
|
-
<8146> <8148> 9000
|
|
35
|
-
endcidrange
|
|
36
|
-
2 beginbfrange
|
|
37
|
-
<0000> <005E> <0020>
|
|
38
|
-
<1379> <137B> <90FE>
|
|
39
|
-
<005F> <0061> [ <00660066> <00660069> <00660066006C> ]
|
|
40
|
-
endbfrange
|
|
41
|
-
1 beginbfchar
|
|
42
|
-
<3A51> <D840DC3E>
|
|
43
|
-
endbfchar
|
|
44
|
-
endcmap
|
|
45
|
-
CMapName currentdict /CMap defineresource pop
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
EOF
|
|
9
|
+
data = <<~EOF
|
|
10
|
+
/CIDInit /ProcSet findresource begin
|
|
11
|
+
12 dict begin
|
|
12
|
+
begincmap
|
|
13
|
+
/H usecmap
|
|
14
|
+
/CIDSystemInfo
|
|
15
|
+
<< /Registry (Adobe)
|
|
16
|
+
/Ordering (UCS)
|
|
17
|
+
/Supplement 0
|
|
18
|
+
>> def
|
|
19
|
+
/CMapName /Adobe-Identity-UCS def
|
|
20
|
+
/CMapType 2 def
|
|
21
|
+
/WMode 0 def
|
|
22
|
+
4 begincodespacerange
|
|
23
|
+
<00> <20>
|
|
24
|
+
<8140> <9ffc>
|
|
25
|
+
<a0> <de>
|
|
26
|
+
<e040> <fbec>
|
|
27
|
+
endcodespacerange
|
|
28
|
+
2 begincidchar
|
|
29
|
+
<8143> 8286
|
|
30
|
+
<8144> 8274
|
|
31
|
+
endcidchar
|
|
32
|
+
2 begincidrange
|
|
33
|
+
<8145> <8145> 8123
|
|
34
|
+
<8146> <8148> 9000
|
|
35
|
+
endcidrange
|
|
36
|
+
2 beginbfrange
|
|
37
|
+
<0000> <005E> <0020>
|
|
38
|
+
<1379> <137B> <90FE>
|
|
39
|
+
<005F> <0061> [ <00660066> <00660069> <00660066006C> ]
|
|
40
|
+
endbfrange
|
|
41
|
+
1 beginbfchar
|
|
42
|
+
<3A51> <D840DC3E>
|
|
43
|
+
endbfchar
|
|
44
|
+
endcmap
|
|
45
|
+
CMapName currentdict /CMap defineresource pop
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
EOF
|
|
49
49
|
cmap = HexaPDF::Font::CMap.parse(data)
|
|
50
50
|
assert_equal("Adobe", cmap.registry)
|
|
51
51
|
assert_equal("UCS", cmap.ordering)
|