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.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/LICENSE +29 -0
  4. data/README.md +129 -0
  5. data/Rakefile +109 -0
  6. data/agpl-3.0.txt +661 -0
  7. data/examples/001-hello_world.rb +16 -0
  8. data/examples/002-graphics.rb +275 -0
  9. data/examples/003-arcs.rb +50 -0
  10. data/examples/004-optimizing.rb +23 -0
  11. data/examples/005-merging.rb +27 -0
  12. data/examples/006-standard_pdf_fonts.rb +73 -0
  13. data/examples/007-truetype.rb +42 -0
  14. data/examples/008-show_char_bboxes.rb +55 -0
  15. data/examples/009-text_layouter_alignment.rb +47 -0
  16. data/examples/010-text_layouter_inline_boxes.rb +64 -0
  17. data/examples/011-text_layouter_line_wrapping.rb +57 -0
  18. data/examples/012-text_layouter_styling.rb +122 -0
  19. data/examples/013-text_layouter_shapes.rb +176 -0
  20. data/examples/014-text_in_polygon.rb +60 -0
  21. data/examples/015-boxes.rb +76 -0
  22. data/examples/016-frame_automatic_box_placement.rb +90 -0
  23. data/examples/017-frame_text_flow.rb +60 -0
  24. data/examples/018-composer.rb +44 -0
  25. data/examples/019-acro_form.rb +88 -0
  26. data/examples/emoji-smile.png +0 -0
  27. data/examples/emoji-wink.png +0 -0
  28. data/examples/machupicchu.jpg +0 -0
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
  31. data/lib/hexapdf/version.rb +1 -1
  32. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  33. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  34. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  35. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  36. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  37. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  38. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  39. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  40. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  41. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  42. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  43. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  44. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  45. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  46. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  47. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  48. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  49. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  50. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  51. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  52. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  53. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  54. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  55. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  56. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  57. data/test/data/images/cmyk.jpg +0 -0
  58. data/test/data/images/fillbytes.jpg +0 -0
  59. data/test/data/images/gray.jpg +0 -0
  60. data/test/data/images/greyscale-1bit.png +0 -0
  61. data/test/data/images/greyscale-2bit.png +0 -0
  62. data/test/data/images/greyscale-4bit.png +0 -0
  63. data/test/data/images/greyscale-8bit.png +0 -0
  64. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  65. data/test/data/images/greyscale-trns-8bit.png +0 -0
  66. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  67. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  68. data/test/data/images/indexed-1bit.png +0 -0
  69. data/test/data/images/indexed-2bit.png +0 -0
  70. data/test/data/images/indexed-4bit.png +0 -0
  71. data/test/data/images/indexed-8bit.png +0 -0
  72. data/test/data/images/indexed-alpha-4bit.png +0 -0
  73. data/test/data/images/indexed-alpha-8bit.png +0 -0
  74. data/test/data/images/rgb.jpg +0 -0
  75. data/test/data/images/truecolour-8bit.png +0 -0
  76. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  77. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  78. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  79. data/test/data/images/ycck.jpg +0 -0
  80. data/test/data/minimal.pdf +44 -0
  81. data/test/data/standard-security-handler/README +9 -0
  82. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  83. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  84. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  85. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  86. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  87. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  88. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  89. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  90. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  91. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  92. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  93. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  94. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  95. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  96. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  97. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  98. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  99. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  100. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  101. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  102. data/test/hexapdf/common_tokenizer_tests.rb +236 -0
  103. data/test/hexapdf/content/common.rb +39 -0
  104. data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
  105. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
  106. data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
  107. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  108. data/test/hexapdf/content/test_canvas.rb +1279 -0
  109. data/test/hexapdf/content/test_color_space.rb +176 -0
  110. data/test/hexapdf/content/test_graphics_state.rb +151 -0
  111. data/test/hexapdf/content/test_operator.rb +619 -0
  112. data/test/hexapdf/content/test_parser.rb +99 -0
  113. data/test/hexapdf/content/test_processor.rb +163 -0
  114. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  115. data/test/hexapdf/document/test_files.rb +72 -0
  116. data/test/hexapdf/document/test_fonts.rb +60 -0
  117. data/test/hexapdf/document/test_images.rb +72 -0
  118. data/test/hexapdf/document/test_pages.rb +130 -0
  119. data/test/hexapdf/encryption/common.rb +87 -0
  120. data/test/hexapdf/encryption/test_aes.rb +129 -0
  121. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  122. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  123. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  124. data/test/hexapdf/encryption/test_identity.rb +21 -0
  125. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  126. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  127. data/test/hexapdf/encryption/test_security_handler.rb +380 -0
  128. data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
  129. data/test/hexapdf/filter/common.rb +53 -0
  130. data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
  131. data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
  132. data/test/hexapdf/filter/test_crypt.rb +21 -0
  133. data/test/hexapdf/filter/test_encryption.rb +24 -0
  134. data/test/hexapdf/filter/test_flate_decode.rb +44 -0
  135. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  136. data/test/hexapdf/filter/test_predictor.rb +219 -0
  137. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  138. data/test/hexapdf/font/cmap/test_parser.rb +102 -0
  139. data/test/hexapdf/font/cmap/test_writer.rb +66 -0
  140. data/test/hexapdf/font/encoding/test_base.rb +45 -0
  141. data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
  142. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  143. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  144. data/test/hexapdf/font/test_cmap.rb +104 -0
  145. data/test/hexapdf/font/test_encoding.rb +27 -0
  146. data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
  147. data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
  148. data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
  149. data/test/hexapdf/font/true_type/common.rb +17 -0
  150. data/test/hexapdf/font/true_type/table/common.rb +27 -0
  151. data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
  152. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
  153. data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
  154. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  155. data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
  156. data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
  157. data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
  158. data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
  159. data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
  160. data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
  161. data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
  162. data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
  163. data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
  164. data/test/hexapdf/font/true_type/test_builder.rb +42 -0
  165. data/test/hexapdf/font/true_type/test_font.rb +116 -0
  166. data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
  167. data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
  168. data/test/hexapdf/font/true_type/test_table.rb +48 -0
  169. data/test/hexapdf/font/type1/common.rb +6 -0
  170. data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
  171. data/test/hexapdf/font/type1/test_font.rb +104 -0
  172. data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
  173. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  174. data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
  175. data/test/hexapdf/font_loader/test_from_file.rb +36 -0
  176. data/test/hexapdf/font_loader/test_standard14.rb +33 -0
  177. data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
  178. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  179. data/test/hexapdf/image_loader/test_png.rb +259 -0
  180. data/test/hexapdf/layout/test_box.rb +154 -0
  181. data/test/hexapdf/layout/test_frame.rb +350 -0
  182. data/test/hexapdf/layout/test_image_box.rb +73 -0
  183. data/test/hexapdf/layout/test_inline_box.rb +71 -0
  184. data/test/hexapdf/layout/test_line.rb +206 -0
  185. data/test/hexapdf/layout/test_style.rb +790 -0
  186. data/test/hexapdf/layout/test_text_box.rb +140 -0
  187. data/test/hexapdf/layout/test_text_fragment.rb +375 -0
  188. data/test/hexapdf/layout/test_text_layouter.rb +758 -0
  189. data/test/hexapdf/layout/test_text_shaper.rb +62 -0
  190. data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
  191. data/test/hexapdf/task/test_dereference.rb +51 -0
  192. data/test/hexapdf/task/test_optimize.rb +162 -0
  193. data/test/hexapdf/test_composer.rb +258 -0
  194. data/test/hexapdf/test_configuration.rb +93 -0
  195. data/test/hexapdf/test_data_dir.rb +32 -0
  196. data/test/hexapdf/test_dictionary.rb +340 -0
  197. data/test/hexapdf/test_dictionary_fields.rb +269 -0
  198. data/test/hexapdf/test_document.rb +641 -0
  199. data/test/hexapdf/test_filter.rb +100 -0
  200. data/test/hexapdf/test_importer.rb +106 -0
  201. data/test/hexapdf/test_object.rb +258 -0
  202. data/test/hexapdf/test_parser.rb +645 -0
  203. data/test/hexapdf/test_pdf_array.rb +169 -0
  204. data/test/hexapdf/test_rectangle.rb +73 -0
  205. data/test/hexapdf/test_reference.rb +50 -0
  206. data/test/hexapdf/test_revision.rb +188 -0
  207. data/test/hexapdf/test_revisions.rb +196 -0
  208. data/test/hexapdf/test_serializer.rb +195 -0
  209. data/test/hexapdf/test_stream.rb +274 -0
  210. data/test/hexapdf/test_tokenizer.rb +80 -0
  211. data/test/hexapdf/test_type.rb +18 -0
  212. data/test/hexapdf/test_writer.rb +140 -0
  213. data/test/hexapdf/test_xref_section.rb +61 -0
  214. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
  215. data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
  216. data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
  217. data/test/hexapdf/type/acro_form/test_field.rb +259 -0
  218. data/test/hexapdf/type/acro_form/test_form.rb +357 -0
  219. data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
  220. data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
  221. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
  222. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  223. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  224. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  225. data/test/hexapdf/type/annotations/test_text.rb +34 -0
  226. data/test/hexapdf/type/annotations/test_widget.rb +225 -0
  227. data/test/hexapdf/type/test_annotation.rb +97 -0
  228. data/test/hexapdf/type/test_catalog.rb +48 -0
  229. data/test/hexapdf/type/test_cid_font.rb +61 -0
  230. data/test/hexapdf/type/test_file_specification.rb +141 -0
  231. data/test/hexapdf/type/test_font.rb +67 -0
  232. data/test/hexapdf/type/test_font_descriptor.rb +61 -0
  233. data/test/hexapdf/type/test_font_simple.rb +176 -0
  234. data/test/hexapdf/type/test_font_true_type.rb +31 -0
  235. data/test/hexapdf/type/test_font_type0.rb +120 -0
  236. data/test/hexapdf/type/test_font_type1.rb +142 -0
  237. data/test/hexapdf/type/test_font_type3.rb +26 -0
  238. data/test/hexapdf/type/test_form.rb +120 -0
  239. data/test/hexapdf/type/test_image.rb +261 -0
  240. data/test/hexapdf/type/test_info.rb +9 -0
  241. data/test/hexapdf/type/test_object_stream.rb +117 -0
  242. data/test/hexapdf/type/test_page.rb +598 -0
  243. data/test/hexapdf/type/test_page_tree_node.rb +315 -0
  244. data/test/hexapdf/type/test_resources.rb +209 -0
  245. data/test/hexapdf/type/test_trailer.rb +116 -0
  246. data/test/hexapdf/type/test_xref_stream.rb +143 -0
  247. data/test/hexapdf/utils/test_bit_field.rb +63 -0
  248. data/test/hexapdf/utils/test_bit_stream.rb +69 -0
  249. data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
  250. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  251. data/test/hexapdf/utils/test_object_hash.rb +120 -0
  252. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  253. data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
  254. data/test/test_helper.rb +58 -0
  255. metadata +263 -3
@@ -0,0 +1,143 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/type/xref_stream'
5
+
6
+ describe HexaPDF::Type::XRefStream do
7
+ before do
8
+ @doc = Object.new
9
+ def (@doc).deref(obj); obj; end
10
+ def (@doc).wrap(obj, **); obj; end
11
+ @obj = HexaPDF::Type::XRefStream.new({}, oid: 1, document: @doc)
12
+ end
13
+
14
+ describe "xref_section" do
15
+ it "handles a missing /Index field" do
16
+ @obj[:Size] = 1
17
+ @obj[:W] = [2, 2, 2]
18
+ @obj.stream = [0, 65535, 1].pack('n*')
19
+ section = @obj.xref_section
20
+ assert_equal(1, section.each.to_a.size)
21
+ assert(section[0, 1].free?)
22
+ end
23
+
24
+ it "handles the three different field types and ignores unknown types" do
25
+ @obj[:Index] = [0, 4]
26
+ @obj[:W] = [2, 2, 2]
27
+ @obj.stream = [0, 65535, 1, 1, 200, 0, 2, 1, 5, 3, 0, 0].pack('n*')
28
+ section = @obj.xref_section
29
+ assert(section[0, 1].free?)
30
+ assert(section[1, 0].in_use?)
31
+ assert_equal(200, section[1, 0].pos)
32
+ assert(section[2, 0].compressed?)
33
+ assert_equal(1, section[2, 0].objstm)
34
+ assert_equal(5, section[2, 0].pos)
35
+ end
36
+
37
+ it "uses the default value for field one if its length is zero" do
38
+ @obj[:Index] = [3, 1]
39
+ @obj[:W] = [0, 1, 1]
40
+ @obj.stream = [200, 0].pack('C*')
41
+ section = @obj.xref_section
42
+ assert(section[3, 0].in_use?)
43
+ assert_equal(200, section[3, 0].pos)
44
+ end
45
+
46
+ it "uses the default value for field three if its length is zero" do
47
+ @obj[:Index] = [3, 1]
48
+ @obj[:W] = [1, 1, 0]
49
+ @obj.stream = [1, 200].pack('C*')
50
+ section = @obj.xref_section
51
+ assert(section[3, 0].in_use?)
52
+ assert_equal(200, section[3, 0].pos)
53
+ end
54
+
55
+ it "uses the default values for field one/three if their lengths are zero" do
56
+ @obj[:Index] = [3, 1]
57
+ @obj[:W] = [0, 1, 0]
58
+ @obj.stream = [200].pack('C*')
59
+ section = @obj.xref_section
60
+ assert(section[3, 0].in_use?)
61
+ assert_equal(200, section[3, 0].pos)
62
+ end
63
+
64
+ it "can handle multiple subsections" do
65
+ @obj[:Index] = [3, 1, 10, 1]
66
+ @obj[:W] = [0, 1, 0]
67
+ @obj.stream = [200, 250].pack('C*')
68
+ section = @obj.xref_section
69
+ assert(section[3, 0].in_use?)
70
+ assert_equal(200, section[3, 0].pos)
71
+ assert(section[10, 0].in_use?)
72
+ assert_equal(250, section[10, 0].pos)
73
+ end
74
+
75
+ it "fails if there is not enough data available" do
76
+ @obj[:Index] = [1, 2, 10, 4]
77
+ @obj[:W] = [1, 2, 1]
78
+ @obj.stream = "abcd"
79
+ assert_raises(HexaPDF::MalformedPDFError) { @obj.xref_section }
80
+ end
81
+ end
82
+
83
+ describe "trailer" do
84
+ it "returns a dictionary without xref stream specific values" do
85
+ @obj[:Size] = 5
86
+ @obj[:ID] = ["a", "b"]
87
+ @obj[:Root] = 'x'
88
+ @obj[:Index] = [0, 5]
89
+ @obj[:W] = [1, 2, 2]
90
+ dict = @obj.trailer
91
+ assert_equal(3, dict.length)
92
+ assert_equal(5, dict[:Size])
93
+ assert_equal(["a", "b"], dict[:ID])
94
+ assert_equal('x', dict[:Root])
95
+ end
96
+ end
97
+
98
+ describe "update_with_xref_section_and_trailer" do
99
+ before do
100
+ @section = HexaPDF::XRefSection.new
101
+ @section.add_free_entry(0, 65535)
102
+ @section.add_in_use_entry(1, 0, 200)
103
+ @section.add_compressed_entry(2, 1, 5)
104
+ end
105
+
106
+ it "sets all necessary dictionary values" do
107
+ @obj.update_with_xref_section_and_trailer(@section, Size: 100)
108
+ assert_equal(:XRef, @obj.value[:Type])
109
+ assert_equal(100, @obj.value[:Size])
110
+ assert_equal([0, 3], @obj.value[:Index])
111
+ assert_equal([1, 1, 2], @obj.value[:W])
112
+
113
+ @section.add_in_use_entry(1, 0, 256**2)
114
+ @obj.update_with_xref_section_and_trailer(@section, Size: 100)
115
+ assert_equal([1, 4, 2], @obj.value[:W])
116
+ end
117
+
118
+ it "updates the stream with the new information" do
119
+ @obj.update_with_xref_section_and_trailer(@section, Size: 100)
120
+ section = @obj.xref_section
121
+ @section.each do |oid, gen, data|
122
+ if section[oid, gen] == data
123
+ section.delete(oid)
124
+ else
125
+ flunk("Data for object p#{oid}, #{gen}] is not equal")
126
+ end
127
+ end
128
+ assert_equal(0, section.each.to_a.size)
129
+ end
130
+
131
+ it "can write multiple subsections" do
132
+ @section.add_free_entry(10, 1)
133
+ @section.add_in_use_entry(11, 1, 100)
134
+ @obj.update_with_xref_section_and_trailer(@section, Size: 100)
135
+ assert_equal([0, 3, 10, 2], @obj.value[:Index])
136
+ end
137
+
138
+ it "fails for unsupported cross-reference entry types" do
139
+ @section.send(:[]=, 3, 0, HexaPDF::XRefSection::Entry.new(:unknown, 3, 0))
140
+ assert_raises(HexaPDF::Error) { @obj.update_with_xref_section_and_trailer(@section, {}) }
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/bit_field'
5
+
6
+ class TestBitField
7
+
8
+ extend HexaPDF::Utils::BitField
9
+
10
+ attr_accessor :data
11
+
12
+ bit_field(:data, {bit0: 0, bit1: 1, bit5: 5}, lister: "list", getter: "get", setter: "set",
13
+ unsetter: 'unset')
14
+
15
+ end
16
+
17
+ describe HexaPDF::Utils::BitField do
18
+ before do
19
+ @obj = TestBitField.new
20
+ end
21
+
22
+ it "allows inspection of the defined bits" do
23
+ assert_equal({bit0: 0, bit1: 1, bit5: 5}, TestBitField::DATA_BIT_MAPPING)
24
+ end
25
+
26
+ it "returns all bit names using the lister method" do
27
+ @obj.data = 0b100011
28
+ assert_equal([:bit0, :bit1, :bit5], @obj.list)
29
+ @obj.data = 0b100001
30
+ assert_equal([:bit0, :bit5], @obj.list)
31
+ end
32
+
33
+ it "can check whether a given bit is set via the getter method" do
34
+ refute(@obj.get(:bit0))
35
+ @obj.data = 0b000001
36
+ assert(@obj.get(:bit0))
37
+ assert(@obj.get(0))
38
+ refute(@obj.get(:bit1))
39
+ refute(@obj.get(1))
40
+ end
41
+
42
+ it "can set a given bit via the setter method" do
43
+ assert_nil(@obj.data)
44
+ @obj.set(:bit0, :bit1, :bit5)
45
+ assert_equal(0b100011, @obj.data)
46
+ @obj.set(:bit0, 5, clear_existing: true)
47
+ assert_equal(0b100001, @obj.data)
48
+ end
49
+
50
+ it "can unset a given bit via the unsetter method" do
51
+ @obj.set(:bit0, :bit5)
52
+ assert_equal(0b100001, @obj.data)
53
+ @obj.unset(:bit5)
54
+ assert_equal(0b000001, @obj.data)
55
+ end
56
+
57
+ it "fails if an unknown bit name or bit index is used with one of the methods" do
58
+ e = assert_raises(ArgumentError) { @obj.get(10) }
59
+ assert_equal("Invalid bit field name or index '10' for TestBitField#data", e.message)
60
+ e = assert_raises(ArgumentError) { @obj.get(:bit10) }
61
+ assert_equal("Invalid bit field name or index 'bit10' for TestBitField#data", e.message)
62
+ end
63
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/bit_stream'
5
+
6
+ describe HexaPDF::Utils::BitStreamReader do
7
+ before do
8
+ @reader = HexaPDF::Utils::BitStreamReader.new
9
+ end
10
+
11
+ it "allows appending data" do
12
+ assert_equal(0, @reader.remaining_bits)
13
+ @reader << "data"
14
+ assert_equal(32, @reader.remaining_bits)
15
+ @reader << "some"
16
+ assert_equal(64, @reader.remaining_bits)
17
+ @reader.read(4)
18
+ assert_equal(60, @reader.remaining_bits)
19
+ @reader << "more"
20
+ assert_equal(92, @reader.remaining_bits)
21
+ end
22
+
23
+ it "allows checking whether a certain number of bits can be read" do
24
+ refute(@reader.read?(1))
25
+ @reader << "data"
26
+ assert(@reader.read?(1))
27
+ assert(@reader.read?(32))
28
+ refute(@reader.read?(33))
29
+ end
30
+
31
+ describe "read" do
32
+ it "allows reading any number of bits" do
33
+ @reader << "\xaa" * 8 # 10101010 * 8
34
+ assert_equal(1, @reader.read(1))
35
+ assert_equal(0, @reader.read(1))
36
+ assert_equal(2, @reader.read(2))
37
+ assert_equal(10, @reader.read(4))
38
+ assert_equal(5, @reader.read(3))
39
+ assert_equal((0b01010 << 8) | 0xaa, @reader.read(13))
40
+ assert_equal(5, @reader.read(3))
41
+ assert_equal((0b01010 << 7) | (0xaa >> 1), @reader.read(12))
42
+ assert_equal(2, @reader.read(3))
43
+ end
44
+
45
+ it "allows reading many bits" do
46
+ @reader << "\x80" << "\x00" * 20
47
+ assert_equal(2**127, @reader.read(128))
48
+ end
49
+
50
+ it "returns nil if enough bits are available" do
51
+ assert_nil(@reader.read(1))
52
+ end
53
+ end
54
+ end
55
+
56
+ describe HexaPDF::Utils::BitStreamWriter do
57
+ before do
58
+ @writer = HexaPDF::Utils::BitStreamWriter.new
59
+ end
60
+
61
+ it "allows writing any number of bits" do
62
+ result = @writer.write(1, 1)
63
+ result << @writer.write(0b101, 3)
64
+ result << @writer.write(0xff, 8)
65
+ result << @writer.write(0x5ddd, 15)
66
+ result << @writer.finalize
67
+ assert_equal("\xdf\xfb\xbb\xa0".b, result)
68
+ end
69
+ end
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/graphics_helpers'
5
+
6
+ describe HexaPDF::Utils::GraphicsHelpers do
7
+ include HexaPDF::Utils::GraphicsHelpers
8
+
9
+ describe "calculate_dimensions" do
10
+ it "returns the requested dimensions if both are specified" do
11
+ assert_equal([7, 8], calculate_dimensions(5, 6, rwidth: 7, rheight: 8))
12
+ end
13
+
14
+ it "returns the requested width and an adjusted height" do
15
+ assert_equal([10, 12], calculate_dimensions(5, 6, rwidth: 10))
16
+ end
17
+
18
+ it "returns the requested width and the given height if width is zero" do
19
+ assert_equal([10, 6], calculate_dimensions(0, 6, rwidth: 10))
20
+ end
21
+
22
+ it "returns the requested height and an adjusted width" do
23
+ assert_equal([10, 12], calculate_dimensions(5, 6, rheight: 12))
24
+ end
25
+
26
+ it "returns the requested height and the given width if height is zero" do
27
+ assert_equal([5, 12], calculate_dimensions(5, 0, rheight: 12))
28
+ end
29
+ end
30
+
31
+ describe "point_on_line" do
32
+ it "returns the correct point" do
33
+ assert_equal([5, 5], point_on_line(0, 0, 10, 10, distance: Math.sqrt(50)))
34
+ assert_equal([5, 5], point_on_line(10, 10, 0, 0, distance: Math.sqrt(50)))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/lru_cache'
5
+
6
+ describe HexaPDF::Utils::LRUCache do
7
+ before do
8
+ @cache = HexaPDF::Utils::LRUCache.new(5)
9
+ 5.times {|i| @cache[i] = i * 2 }
10
+ end
11
+
12
+ it "removes the LRU item when the size is reached" do
13
+ assert([1, 2], @cache.instance_variable_get(:@cache).first)
14
+ @cache[6] = 7
15
+ assert([2, 4], @cache.instance_variable_get(:@cache).first)
16
+ end
17
+
18
+ it "freshes an item on access" do
19
+ @cache[1]
20
+ assert([2, 4], @cache.instance_variable_get(:@cache).first)
21
+ end
22
+ end
@@ -0,0 +1,120 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/object_hash'
5
+
6
+ describe HexaPDF::Utils::ObjectHash do
7
+ before do
8
+ @hash = HexaPDF::Utils::ObjectHash.new
9
+ end
10
+
11
+ describe "[]" do
12
+ it "works with both an object number and a generation number" do
13
+ @hash[1, 5] = 5
14
+ assert_equal(5, @hash[1, 5])
15
+ assert_nil(@hash[1, 4])
16
+ assert_nil(@hash[2, 5])
17
+ end
18
+
19
+ it "works with an object number only" do
20
+ @hash[1, 5] = 5
21
+ assert_equal(5, @hash[1])
22
+ assert_nil(@hash[2])
23
+ end
24
+ end
25
+
26
+ describe "[]=" do
27
+ it "allows adding an entry" do
28
+ @hash[1, 5] = 5
29
+ assert_equal(5, @hash[1, 5])
30
+ end
31
+
32
+ it "allows overwriting an existing entry for an object number" do
33
+ @hash[1, 0] = 5
34
+ @hash[1, 0] = 6
35
+ assert_equal(6, @hash[1, 0])
36
+
37
+ @hash[1, 1] = 5
38
+ assert_equal(5, @hash[1, 1])
39
+ assert_nil(@hash[1, 0])
40
+ end
41
+ end
42
+
43
+ describe "entry?" do
44
+ it "checks if an entry for a specific object number exists" do
45
+ refute(@hash.entry?(1))
46
+ @hash[1, 1] = 5
47
+ assert(@hash.entry?(1))
48
+ end
49
+
50
+ it "checks if an entry for a specific object and generation number exists" do
51
+ refute(@hash.entry?(1, 1))
52
+ @hash[1, 1] = 5
53
+ assert(@hash.entry?(1, 1))
54
+ refute(@hash.entry?(1, 0))
55
+ end
56
+ end
57
+
58
+ it "returns the generation number for an object number with gen_for_oid" do
59
+ assert_nil(@hash.gen_for_oid(1))
60
+ @hash[1, 5] = 5
61
+ assert_equal(5, @hash.gen_for_oid(1))
62
+ end
63
+
64
+ it "deletes an entry via delete" do
65
+ @hash[1, 0] = 5
66
+ @hash.delete(1)
67
+ assert_nil(@hash[1])
68
+ end
69
+
70
+ describe "each" do
71
+ it "acts as an enumerable object" do
72
+ @hash[1, 0] = 5
73
+ @hash[2, 3] = 6
74
+ @hash[3, 2] = 7
75
+ assert_equal([[1, 0, 5], [2, 3, 6], [3, 2, 7]], @hash.each.to_a)
76
+
77
+ @hash.each do |oid, gen, data|
78
+ assert_equal(data, @hash[oid, gen])
79
+ end
80
+ end
81
+
82
+ it "allows key insertion during iteration" do
83
+ @hash[1, 0] = 5
84
+ count = 0
85
+ @hash.each { count += 1; @hash[2, 0] = 6 }
86
+ assert_equal(1, count)
87
+ end
88
+ end
89
+
90
+ describe "max_oid" do
91
+ it "is zero when no objects are stored" do
92
+ assert_equal(0, @hash.max_oid)
93
+ @hash[1, 0] = 5
94
+ @hash.delete(1)
95
+ assert_equal(0, @hash.max_oid)
96
+ end
97
+
98
+ it "changes accordingly when data is inserted" do
99
+ @hash[1, 0] = 5
100
+ assert_equal(1, @hash.max_oid)
101
+ @hash[5, 0] = 5
102
+ assert_equal(5, @hash.max_oid)
103
+ @hash[3, 0] = 5
104
+ assert_equal(5, @hash.max_oid)
105
+ end
106
+
107
+ it "changes accordingly when data is deleted" do
108
+ @hash[1, 0] = @hash[3, 0] = @hash[5, 0] = 5
109
+ @hash.delete(1)
110
+ assert_equal(5, @hash.max_oid)
111
+ @hash.delete(5)
112
+ assert_equal(3, @hash.max_oid)
113
+ end
114
+ end
115
+
116
+ it "can return a list of all object IDs" do
117
+ @hash[1, 0] = @hash[3, 1] = 7
118
+ assert_equal([3, 1], @hash.oids)
119
+ end
120
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/utils/pdf_doc_encoding'
5
+
6
+ describe HexaPDF::Utils::PDFDocEncoding do
7
+ before do
8
+ @obj = HexaPDF::Utils::PDFDocEncoding
9
+ end
10
+
11
+ describe "convert_to_utf8" do
12
+ it "converts the given string to UTF-8" do
13
+ result = @obj.convert_to_utf8("Testing\x9c\x92".b)
14
+ assert_equal(Encoding::UTF_8, result.encoding)
15
+ assert_equal("Testing\u0153\u2122", result)
16
+ end
17
+ end
18
+ end