hexapdf 0.1.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.
Files changed (346) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTERS +3 -0
  3. data/LICENSE +26 -0
  4. data/README.md +88 -0
  5. data/Rakefile +121 -0
  6. data/VERSION +1 -0
  7. data/agpl-3.0.txt +661 -0
  8. data/bin/hexapdf +6 -0
  9. data/data/hexapdf/afm/Courier-Bold.afm +342 -0
  10. data/data/hexapdf/afm/Courier-BoldOblique.afm +342 -0
  11. data/data/hexapdf/afm/Courier-Oblique.afm +342 -0
  12. data/data/hexapdf/afm/Courier.afm +342 -0
  13. data/data/hexapdf/afm/Helvetica-Bold.afm +2827 -0
  14. data/data/hexapdf/afm/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/hexapdf/afm/Helvetica-Oblique.afm +3051 -0
  16. data/data/hexapdf/afm/Helvetica.afm +3051 -0
  17. data/data/hexapdf/afm/MustRead.html +1 -0
  18. data/data/hexapdf/afm/Symbol.afm +213 -0
  19. data/data/hexapdf/afm/Times-Bold.afm +2588 -0
  20. data/data/hexapdf/afm/Times-BoldItalic.afm +2384 -0
  21. data/data/hexapdf/afm/Times-Italic.afm +2667 -0
  22. data/data/hexapdf/afm/Times-Roman.afm +2419 -0
  23. data/data/hexapdf/afm/ZapfDingbats.afm +225 -0
  24. data/data/hexapdf/encoding/glyphlist.txt +4305 -0
  25. data/data/hexapdf/encoding/zapfdingbats.txt +225 -0
  26. data/examples/arc.rb +50 -0
  27. data/examples/graphics.rb +274 -0
  28. data/examples/hello_world.rb +16 -0
  29. data/examples/machupicchu.jpg +0 -0
  30. data/examples/merging.rb +24 -0
  31. data/examples/optimizing.rb +20 -0
  32. data/examples/show_char_bboxes.rb +55 -0
  33. data/examples/standard_pdf_fonts.rb +72 -0
  34. data/examples/truetype.rb +45 -0
  35. data/lib/hexapdf/cli/extract.rb +128 -0
  36. data/lib/hexapdf/cli/info.rb +121 -0
  37. data/lib/hexapdf/cli/inspect.rb +157 -0
  38. data/lib/hexapdf/cli/modify.rb +218 -0
  39. data/lib/hexapdf/cli.rb +121 -0
  40. data/lib/hexapdf/configuration.rb +392 -0
  41. data/lib/hexapdf/content/canvas.rb +1974 -0
  42. data/lib/hexapdf/content/color_space.rb +364 -0
  43. data/lib/hexapdf/content/graphic_object/arc.rb +267 -0
  44. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +208 -0
  45. data/lib/hexapdf/content/graphic_object/solid_arc.rb +173 -0
  46. data/lib/hexapdf/content/graphic_object.rb +81 -0
  47. data/lib/hexapdf/content/graphics_state.rb +579 -0
  48. data/lib/hexapdf/content/operator.rb +1072 -0
  49. data/lib/hexapdf/content/parser.rb +204 -0
  50. data/lib/hexapdf/content/processor.rb +451 -0
  51. data/lib/hexapdf/content/transformation_matrix.rb +172 -0
  52. data/lib/hexapdf/content.rb +47 -0
  53. data/lib/hexapdf/data_dir.rb +51 -0
  54. data/lib/hexapdf/dictionary.rb +303 -0
  55. data/lib/hexapdf/dictionary_fields.rb +382 -0
  56. data/lib/hexapdf/document.rb +589 -0
  57. data/lib/hexapdf/document_utils.rb +209 -0
  58. data/lib/hexapdf/encryption/aes.rb +206 -0
  59. data/lib/hexapdf/encryption/arc4.rb +93 -0
  60. data/lib/hexapdf/encryption/fast_aes.rb +79 -0
  61. data/lib/hexapdf/encryption/fast_arc4.rb +67 -0
  62. data/lib/hexapdf/encryption/identity.rb +63 -0
  63. data/lib/hexapdf/encryption/ruby_aes.rb +447 -0
  64. data/lib/hexapdf/encryption/ruby_arc4.rb +96 -0
  65. data/lib/hexapdf/encryption/security_handler.rb +494 -0
  66. data/lib/hexapdf/encryption/standard_security_handler.rb +616 -0
  67. data/lib/hexapdf/encryption.rb +94 -0
  68. data/lib/hexapdf/error.rb +73 -0
  69. data/lib/hexapdf/filter/ascii85_decode.rb +160 -0
  70. data/lib/hexapdf/filter/ascii_hex_decode.rb +87 -0
  71. data/lib/hexapdf/filter/dct_decode.rb +57 -0
  72. data/lib/hexapdf/filter/encryption.rb +59 -0
  73. data/lib/hexapdf/filter/flate_decode.rb +93 -0
  74. data/lib/hexapdf/filter/jpx_decode.rb +56 -0
  75. data/lib/hexapdf/filter/lzw_decode.rb +191 -0
  76. data/lib/hexapdf/filter/predictor.rb +266 -0
  77. data/lib/hexapdf/filter/run_length_decode.rb +108 -0
  78. data/lib/hexapdf/filter.rb +176 -0
  79. data/lib/hexapdf/font/cmap/parser.rb +146 -0
  80. data/lib/hexapdf/font/cmap/writer.rb +176 -0
  81. data/lib/hexapdf/font/cmap.rb +90 -0
  82. data/lib/hexapdf/font/encoding/base.rb +77 -0
  83. data/lib/hexapdf/font/encoding/difference_encoding.rb +64 -0
  84. data/lib/hexapdf/font/encoding/glyph_list.rb +150 -0
  85. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +221 -0
  86. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +265 -0
  87. data/lib/hexapdf/font/encoding/standard_encoding.rb +205 -0
  88. data/lib/hexapdf/font/encoding/symbol_encoding.rb +244 -0
  89. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +280 -0
  90. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +250 -0
  91. data/lib/hexapdf/font/encoding.rb +68 -0
  92. data/lib/hexapdf/font/true_type/font.rb +179 -0
  93. data/lib/hexapdf/font/true_type/table/cmap.rb +103 -0
  94. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +384 -0
  95. data/lib/hexapdf/font/true_type/table/directory.rb +92 -0
  96. data/lib/hexapdf/font/true_type/table/glyf.rb +166 -0
  97. data/lib/hexapdf/font/true_type/table/head.rb +143 -0
  98. data/lib/hexapdf/font/true_type/table/hhea.rb +109 -0
  99. data/lib/hexapdf/font/true_type/table/hmtx.rb +79 -0
  100. data/lib/hexapdf/font/true_type/table/loca.rb +79 -0
  101. data/lib/hexapdf/font/true_type/table/maxp.rb +112 -0
  102. data/lib/hexapdf/font/true_type/table/name.rb +218 -0
  103. data/lib/hexapdf/font/true_type/table/os2.rb +200 -0
  104. data/lib/hexapdf/font/true_type/table/post.rb +230 -0
  105. data/lib/hexapdf/font/true_type/table.rb +155 -0
  106. data/lib/hexapdf/font/true_type.rb +48 -0
  107. data/lib/hexapdf/font/true_type_wrapper.rb +240 -0
  108. data/lib/hexapdf/font/type1/afm_parser.rb +230 -0
  109. data/lib/hexapdf/font/type1/character_metrics.rb +67 -0
  110. data/lib/hexapdf/font/type1/font.rb +123 -0
  111. data/lib/hexapdf/font/type1/font_metrics.rb +117 -0
  112. data/lib/hexapdf/font/type1/pfb_parser.rb +71 -0
  113. data/lib/hexapdf/font/type1.rb +52 -0
  114. data/lib/hexapdf/font/type1_wrapper.rb +193 -0
  115. data/lib/hexapdf/font_loader/from_configuration.rb +70 -0
  116. data/lib/hexapdf/font_loader/standard14.rb +98 -0
  117. data/lib/hexapdf/font_loader.rb +85 -0
  118. data/lib/hexapdf/font_utils.rb +89 -0
  119. data/lib/hexapdf/image_loader/jpeg.rb +166 -0
  120. data/lib/hexapdf/image_loader/pdf.rb +89 -0
  121. data/lib/hexapdf/image_loader/png.rb +410 -0
  122. data/lib/hexapdf/image_loader.rb +68 -0
  123. data/lib/hexapdf/importer.rb +139 -0
  124. data/lib/hexapdf/name_tree_node.rb +78 -0
  125. data/lib/hexapdf/number_tree_node.rb +67 -0
  126. data/lib/hexapdf/object.rb +363 -0
  127. data/lib/hexapdf/parser.rb +349 -0
  128. data/lib/hexapdf/rectangle.rb +99 -0
  129. data/lib/hexapdf/reference.rb +98 -0
  130. data/lib/hexapdf/revision.rb +206 -0
  131. data/lib/hexapdf/revisions.rb +194 -0
  132. data/lib/hexapdf/serializer.rb +326 -0
  133. data/lib/hexapdf/stream.rb +279 -0
  134. data/lib/hexapdf/task/dereference.rb +109 -0
  135. data/lib/hexapdf/task/optimize.rb +230 -0
  136. data/lib/hexapdf/task.rb +68 -0
  137. data/lib/hexapdf/tokenizer.rb +406 -0
  138. data/lib/hexapdf/type/catalog.rb +107 -0
  139. data/lib/hexapdf/type/embedded_file.rb +87 -0
  140. data/lib/hexapdf/type/file_specification.rb +232 -0
  141. data/lib/hexapdf/type/font.rb +81 -0
  142. data/lib/hexapdf/type/font_descriptor.rb +109 -0
  143. data/lib/hexapdf/type/font_simple.rb +190 -0
  144. data/lib/hexapdf/type/font_true_type.rb +47 -0
  145. data/lib/hexapdf/type/font_type1.rb +162 -0
  146. data/lib/hexapdf/type/form.rb +103 -0
  147. data/lib/hexapdf/type/graphics_state_parameter.rb +79 -0
  148. data/lib/hexapdf/type/image.rb +73 -0
  149. data/lib/hexapdf/type/info.rb +70 -0
  150. data/lib/hexapdf/type/names.rb +69 -0
  151. data/lib/hexapdf/type/object_stream.rb +224 -0
  152. data/lib/hexapdf/type/page.rb +355 -0
  153. data/lib/hexapdf/type/page_tree_node.rb +269 -0
  154. data/lib/hexapdf/type/resources.rb +212 -0
  155. data/lib/hexapdf/type/trailer.rb +128 -0
  156. data/lib/hexapdf/type/viewer_preferences.rb +73 -0
  157. data/lib/hexapdf/type/xref_stream.rb +204 -0
  158. data/lib/hexapdf/type.rb +67 -0
  159. data/lib/hexapdf/utils/bit_field.rb +87 -0
  160. data/lib/hexapdf/utils/bit_stream.rb +148 -0
  161. data/lib/hexapdf/utils/lru_cache.rb +65 -0
  162. data/lib/hexapdf/utils/math_helpers.rb +55 -0
  163. data/lib/hexapdf/utils/object_hash.rb +130 -0
  164. data/lib/hexapdf/utils/pdf_doc_encoding.rb +93 -0
  165. data/lib/hexapdf/utils/sorted_tree_node.rb +339 -0
  166. data/lib/hexapdf/version.rb +39 -0
  167. data/lib/hexapdf/writer.rb +199 -0
  168. data/lib/hexapdf/xref_section.rb +152 -0
  169. data/lib/hexapdf.rb +34 -0
  170. data/man/man1/hexapdf.1 +249 -0
  171. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  172. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  173. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  174. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  175. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  176. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  177. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  178. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  179. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  180. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  181. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  182. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  183. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  184. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  185. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  186. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  187. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  188. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  189. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  190. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  191. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  192. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  193. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  194. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  195. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  196. data/test/data/images/cmyk.jpg +0 -0
  197. data/test/data/images/fillbytes.jpg +0 -0
  198. data/test/data/images/gray.jpg +0 -0
  199. data/test/data/images/greyscale-1bit.png +0 -0
  200. data/test/data/images/greyscale-2bit.png +0 -0
  201. data/test/data/images/greyscale-4bit.png +0 -0
  202. data/test/data/images/greyscale-8bit.png +0 -0
  203. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  204. data/test/data/images/greyscale-trns-8bit.png +0 -0
  205. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  206. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  207. data/test/data/images/indexed-1bit.png +0 -0
  208. data/test/data/images/indexed-2bit.png +0 -0
  209. data/test/data/images/indexed-4bit.png +0 -0
  210. data/test/data/images/indexed-8bit.png +0 -0
  211. data/test/data/images/indexed-alpha-4bit.png +0 -0
  212. data/test/data/images/indexed-alpha-8bit.png +0 -0
  213. data/test/data/images/rgb.jpg +0 -0
  214. data/test/data/images/truecolour-8bit.png +0 -0
  215. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  216. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  217. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  218. data/test/data/minimal.pdf +44 -0
  219. data/test/data/standard-security-handler/README +9 -0
  220. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  221. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  222. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  223. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  224. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  225. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  226. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  227. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  228. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  229. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  230. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  231. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  232. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  233. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  234. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  235. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  236. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  237. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  238. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  239. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  240. data/test/hexapdf/common_tokenizer_tests.rb +204 -0
  241. data/test/hexapdf/content/common.rb +31 -0
  242. data/test/hexapdf/content/graphic_object/test_arc.rb +93 -0
  243. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +91 -0
  244. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  245. data/test/hexapdf/content/test_canvas.rb +1113 -0
  246. data/test/hexapdf/content/test_color_space.rb +97 -0
  247. data/test/hexapdf/content/test_graphics_state.rb +138 -0
  248. data/test/hexapdf/content/test_operator.rb +619 -0
  249. data/test/hexapdf/content/test_parser.rb +66 -0
  250. data/test/hexapdf/content/test_processor.rb +156 -0
  251. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  252. data/test/hexapdf/encryption/common.rb +87 -0
  253. data/test/hexapdf/encryption/test_aes.rb +121 -0
  254. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  255. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  256. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  257. data/test/hexapdf/encryption/test_identity.rb +21 -0
  258. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  259. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  260. data/test/hexapdf/encryption/test_security_handler.rb +356 -0
  261. data/test/hexapdf/encryption/test_standard_security_handler.rb +274 -0
  262. data/test/hexapdf/filter/common.rb +53 -0
  263. data/test/hexapdf/filter/test_ascii85_decode.rb +60 -0
  264. data/test/hexapdf/filter/test_ascii_hex_decode.rb +33 -0
  265. data/test/hexapdf/filter/test_encryption.rb +24 -0
  266. data/test/hexapdf/filter/test_flate_decode.rb +35 -0
  267. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  268. data/test/hexapdf/filter/test_predictor.rb +183 -0
  269. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  270. data/test/hexapdf/font/cmap/test_parser.rb +67 -0
  271. data/test/hexapdf/font/cmap/test_writer.rb +58 -0
  272. data/test/hexapdf/font/encoding/test_base.rb +35 -0
  273. data/test/hexapdf/font/encoding/test_difference_encoding.rb +21 -0
  274. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  275. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  276. data/test/hexapdf/font/test_encoding.rb +27 -0
  277. data/test/hexapdf/font/test_true_type_wrapper.rb +110 -0
  278. data/test/hexapdf/font/test_type1_wrapper.rb +66 -0
  279. data/test/hexapdf/font/true_type/common.rb +19 -0
  280. data/test/hexapdf/font/true_type/table/test_cmap.rb +59 -0
  281. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +133 -0
  282. data/test/hexapdf/font/true_type/table/test_directory.rb +35 -0
  283. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  284. data/test/hexapdf/font/true_type/table/test_head.rb +76 -0
  285. data/test/hexapdf/font/true_type/table/test_hhea.rb +40 -0
  286. data/test/hexapdf/font/true_type/table/test_hmtx.rb +38 -0
  287. data/test/hexapdf/font/true_type/table/test_loca.rb +43 -0
  288. data/test/hexapdf/font/true_type/table/test_maxp.rb +62 -0
  289. data/test/hexapdf/font/true_type/table/test_name.rb +95 -0
  290. data/test/hexapdf/font/true_type/table/test_os2.rb +65 -0
  291. data/test/hexapdf/font/true_type/table/test_post.rb +89 -0
  292. data/test/hexapdf/font/true_type/test_font.rb +120 -0
  293. data/test/hexapdf/font/true_type/test_table.rb +41 -0
  294. data/test/hexapdf/font/type1/test_afm_parser.rb +51 -0
  295. data/test/hexapdf/font/type1/test_font.rb +68 -0
  296. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  297. data/test/hexapdf/font_loader/test_from_configuration.rb +28 -0
  298. data/test/hexapdf/font_loader/test_standard14.rb +22 -0
  299. data/test/hexapdf/image_loader/test_jpeg.rb +83 -0
  300. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  301. data/test/hexapdf/image_loader/test_png.rb +258 -0
  302. data/test/hexapdf/task/test_dereference.rb +46 -0
  303. data/test/hexapdf/task/test_optimize.rb +137 -0
  304. data/test/hexapdf/test_configuration.rb +82 -0
  305. data/test/hexapdf/test_data_dir.rb +32 -0
  306. data/test/hexapdf/test_dictionary.rb +284 -0
  307. data/test/hexapdf/test_dictionary_fields.rb +185 -0
  308. data/test/hexapdf/test_document.rb +574 -0
  309. data/test/hexapdf/test_document_utils.rb +144 -0
  310. data/test/hexapdf/test_filter.rb +96 -0
  311. data/test/hexapdf/test_font_utils.rb +47 -0
  312. data/test/hexapdf/test_importer.rb +78 -0
  313. data/test/hexapdf/test_object.rb +177 -0
  314. data/test/hexapdf/test_parser.rb +394 -0
  315. data/test/hexapdf/test_rectangle.rb +36 -0
  316. data/test/hexapdf/test_reference.rb +41 -0
  317. data/test/hexapdf/test_revision.rb +139 -0
  318. data/test/hexapdf/test_revisions.rb +93 -0
  319. data/test/hexapdf/test_serializer.rb +169 -0
  320. data/test/hexapdf/test_stream.rb +262 -0
  321. data/test/hexapdf/test_tokenizer.rb +30 -0
  322. data/test/hexapdf/test_writer.rb +120 -0
  323. data/test/hexapdf/test_xref_section.rb +35 -0
  324. data/test/hexapdf/type/test_catalog.rb +30 -0
  325. data/test/hexapdf/type/test_embedded_file.rb +16 -0
  326. data/test/hexapdf/type/test_file_specification.rb +148 -0
  327. data/test/hexapdf/type/test_font.rb +35 -0
  328. data/test/hexapdf/type/test_font_descriptor.rb +51 -0
  329. data/test/hexapdf/type/test_font_simple.rb +190 -0
  330. data/test/hexapdf/type/test_font_type1.rb +128 -0
  331. data/test/hexapdf/type/test_form.rb +60 -0
  332. data/test/hexapdf/type/test_info.rb +14 -0
  333. data/test/hexapdf/type/test_names.rb +9 -0
  334. data/test/hexapdf/type/test_object_stream.rb +84 -0
  335. data/test/hexapdf/type/test_page.rb +260 -0
  336. data/test/hexapdf/type/test_page_tree_node.rb +255 -0
  337. data/test/hexapdf/type/test_resources.rb +167 -0
  338. data/test/hexapdf/type/test_trailer.rb +109 -0
  339. data/test/hexapdf/type/test_xref_stream.rb +131 -0
  340. data/test/hexapdf/utils/test_bit_field.rb +47 -0
  341. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  342. data/test/hexapdf/utils/test_object_hash.rb +115 -0
  343. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  344. data/test/hexapdf/utils/test_sorted_tree_node.rb +232 -0
  345. data/test/test_helper.rb +56 -0
  346. metadata +427 -0
@@ -0,0 +1,169 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'stringio'
5
+ require 'hexapdf/serializer'
6
+ require 'hexapdf/object'
7
+ require 'hexapdf/stream'
8
+
9
+ describe HexaPDF::Serializer do
10
+ before do
11
+ @serializer = HexaPDF::Serializer.new
12
+ end
13
+
14
+ it "allows access to the top serialized object" do
15
+ object = nil
16
+ @serializer.singleton_class.send(:define_method, :serialize_symbol) do |obj|
17
+ object = @object
18
+ "/#{obj}"
19
+ end
20
+ @serializer.serialize(this: :is, null: nil)
21
+ assert_equal({this: :is, null: nil}, object)
22
+ end
23
+
24
+ def assert_serialized(result, object)
25
+ assert_equal(result, @serializer.serialize(object))
26
+ end
27
+
28
+ it "serializes nil" do
29
+ assert_serialized("null", nil)
30
+ end
31
+
32
+ it "serializes true" do
33
+ assert_serialized("true", true)
34
+ end
35
+
36
+ it "serializes false" do
37
+ assert_serialized("false", false)
38
+ end
39
+
40
+ it "serializes integers" do
41
+ assert_serialized("100", 100)
42
+ assert_serialized("-100", -100)
43
+ assert_serialized("0", 0)
44
+ assert_serialized("1208925819614629174706176", 1208925819614629174706176)
45
+ end
46
+
47
+ it "serializes floats with a precision of 4" do
48
+ assert_serialized("1.5", 1.5)
49
+ assert_serialized("-1.5", -1.5)
50
+ assert_serialized("9.123456", 9.123456)
51
+ assert_serialized("9.123457", 9.1234567)
52
+ assert_serialized("0.000005", 0.000005)
53
+ assert_serialized("-0.000005", -0.000005)
54
+ assert_serialized("0.0", 0.0)
55
+ end
56
+
57
+ it "serializes numerics" do
58
+ assert_equal("1", @serializer.serialize_numeric(1))
59
+ assert_equal("1.5", @serializer.serialize_numeric(1.5))
60
+ end
61
+
62
+ it "serializes symbols" do
63
+ assert_serialized("/Name", :Name)
64
+ assert_serialized("/A;Name_With-Various***Chars?", 'A;Name_With-Various***Chars?'.intern)
65
+ assert_serialized("/1.2", '1.2'.intern)
66
+ assert_serialized("/$$", '$$'.intern)
67
+ assert_serialized("/@pattern", '@pattern'.intern)
68
+ assert_serialized('/.notdef', '.notdef'.intern)
69
+ assert_serialized('/lime#20Green', 'lime Green'.intern)
70
+ assert_serialized('/paired#28#29parentheses', 'paired()parentheses'.intern)
71
+ assert_serialized('/The_Key_of_F#23_Minor', 'The_Key_of_F#_Minor'.intern)
72
+ assert_serialized('/', ''.intern)
73
+ assert_serialized('/H#c3#b6#c3#9fgang', "Hößgang".intern)
74
+ assert_serialized('/H#e8lp', "H\xE8lp".force_encoding('BINARY').intern)
75
+ end
76
+
77
+ it "serializes arrays" do
78
+ assert_serialized("[-12 2.4321/Name true(345)true]", [-12, 2.4321, :Name, true, '345', true])
79
+ assert_serialized("[]", [])
80
+ end
81
+
82
+ it "serializes hashes" do
83
+ assert_serialized("<</hallo 5/other true/name[5]>>", hallo: 5, other: true, name: [5])
84
+ assert_serialized("<<>>", {})
85
+ end
86
+
87
+ it "serializes strings" do
88
+ assert_serialized("(Hallo)", "Hallo")
89
+ assert_serialized("(Hallo\\r\n\t\\(\\)\\\\)", "Hallo\r\n\t()\\")
90
+ assert_serialized("(\xFE\xFF\x00H\x00a\x00l\x00\f\x00\b\x00\\()".force_encoding('BINARY'),
91
+ "Hal\f\b(")
92
+ end
93
+
94
+ it "serializes time like objects" do
95
+ begin
96
+ tz = ENV['TZ']
97
+ ENV['TZ'] = 'Europe/Vienna'
98
+ assert_serialized("(D:20150416094100)", Time.new(2015, 04, 16, 9, 41, 0, 0))
99
+ assert_serialized("(D:20150416094100+01'00')", Time.new(2015, 04, 16, 9, 41, 0, 3600))
100
+ assert_serialized("(D:20150416094100-01'20')", Time.new(2015, 04, 16, 9, 41, 0, -4800))
101
+ assert_serialized("(D:20150416000000+02'00')", Date.parse("2015-04-16 9:41:00 +02:00"))
102
+ assert_serialized("(D:20150416094100+02'00')", DateTime.parse("2015-04-16 9:41:00 +02:00"))
103
+ ensure
104
+ ENV['TZ'] = tz
105
+ end
106
+ end
107
+
108
+ it "serializes HexaPDF objects" do
109
+ assert_serialized("/Name", HexaPDF::Object.new(:Name))
110
+ assert_serialized("/Name", HexaPDF::Object.new(:Name, oid: 1))
111
+ assert_serialized("<</Name 2 0 R>>",
112
+ HexaPDF::Object.new({Name: HexaPDF::Object.new(5, oid: 2)}, oid: 1))
113
+ end
114
+
115
+ it "serializes HexaPDF reference objects" do
116
+ assert_serialized("5 3 R", HexaPDF::Reference.new(5, 3))
117
+ end
118
+
119
+ describe "stream serialization" do
120
+ before do
121
+ @doc = Object.new
122
+ def (@doc).unwrap(obj); obj; end
123
+ def (@doc).config; {chunk_size: 100}; end
124
+ @stream = HexaPDF::Stream.new({Key: "value", Length: 5}, oid: 2, document: @doc)
125
+ end
126
+
127
+ it "serializes streams" do
128
+ @stream.stream = "somedata"
129
+ assert_serialized("<</Key(value)/Length 8>>stream\nsomedata\nendstream", @stream)
130
+ assert_serialized("<</Name 2 0 R>>", HexaPDF::Object.new(Name: @stream))
131
+ end
132
+
133
+ it "serializes stream more efficiently when an IO is provided" do
134
+ @stream.stream = HexaPDF::StreamData.new(proc { "some" }, length: 6)
135
+ io = StringIO.new(''.b)
136
+ @serializer.serialize_to_io(@stream, io)
137
+ assert_equal("<</Key(value)/Length 6>>stream\nsome\nendstream", io.string)
138
+ end
139
+
140
+ it "fails if a stream without object identifier is serialized" do
141
+ @stream.oid = 0
142
+ assert_raises(HexaPDF::Error) { @serializer.serialize(@stream) }
143
+ assert_raises(HexaPDF::Error) { @serializer.serialize(Name: @stream) }
144
+ end
145
+ end
146
+
147
+ describe "with an encrypter" do
148
+ before do
149
+ @serializer.encrypter = encrypter = Object.new
150
+ def encrypter.encrypt_string(str, obj); "enc:#{obj.oid}:#{str}"; end
151
+ def encrypter.encrypt_stream(obj); Fiber.new { "encs:#{obj.oid}:#{obj.stream}" }; end
152
+ end
153
+
154
+ it "encrypts strings in indirect PDF objects" do
155
+ assert_serialized("(enc:1:test)", HexaPDF::Object.new("test", oid: 1))
156
+ assert_serialized("<</x[(enc:1:test)]>>", HexaPDF::Object.new({x: ["test"]}, oid: 1))
157
+ end
158
+
159
+ it "doesn't encrypt strings in direct PDF objects" do
160
+ assert_serialized("(test)", HexaPDF::Object.new("test"))
161
+ assert_serialized("(test)", "test")
162
+ end
163
+
164
+ it "encrypts streams" do
165
+ obj = HexaPDF::Stream.new({}, oid: 1, stream: "stream")
166
+ assert_serialized("<</Length 13>>stream\nencs:1:stream\nendstream", obj)
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,262 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'ostruct'
5
+ require 'stringio'
6
+ require 'tempfile'
7
+ require 'hexapdf/configuration'
8
+ require 'hexapdf/stream'
9
+
10
+
11
+ describe HexaPDF::StreamData do
12
+ it "fails if no valid source is specified on creation" do
13
+ assert_raises(ArgumentError) { HexaPDF::StreamData.new }
14
+ end
15
+
16
+ it "normalizes the filter value" do
17
+ s = HexaPDF::StreamData.new(:source, filter: :test)
18
+ assert_equal([:test], s.filter)
19
+ s = HexaPDF::StreamData.new(:source, filter: [:a, nil, :b])
20
+ assert_equal([:a, :b], s.filter)
21
+ s = HexaPDF::StreamData.new(:source)
22
+ assert_equal([], s.filter)
23
+ end
24
+
25
+ it "normalizes the decode_parms value" do
26
+ s = HexaPDF::StreamData.new(:source, decode_parms: :test)
27
+ assert_equal([:test], s.decode_parms)
28
+ s = HexaPDF::StreamData.new(:source, decode_parms: [:a, nil, :b])
29
+ assert_equal([:a, nil, :b], s.decode_parms)
30
+ s = HexaPDF::StreamData.new(:source)
31
+ assert_equal([nil], s.decode_parms)
32
+ end
33
+
34
+ describe "fiber" do
35
+ it "returns a fiber for a Proc source" do
36
+ s = HexaPDF::StreamData.new(proc { :source })
37
+ assert_equal(:source, s.fiber.resume)
38
+ end
39
+
40
+ it "returns a fiber for a source specified via a block" do
41
+ s = HexaPDF::StreamData.new { :source }
42
+ assert_equal(:source, s.fiber.resume)
43
+ end
44
+
45
+ it "returns a fiber for an IO source" do
46
+ s = HexaPDF::StreamData.new(StringIO.new('source'))
47
+ assert_equal('source', s.fiber.resume)
48
+ end
49
+
50
+ it "returns a fiber for a string representing a file name" do
51
+ begin
52
+ file = Tempfile.new('hexapdf-stream')
53
+ file.write('source')
54
+ file.close
55
+ s = HexaPDF::StreamData.new(file.path)
56
+ assert_equal('source', s.fiber.resume)
57
+ ensure
58
+ file.unlink
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ describe HexaPDF::Stream do
66
+ include TestHelper
67
+
68
+ before do
69
+ @document = OpenStruct.new
70
+ @document.config = HexaPDF::Configuration.with_defaults
71
+ @document.instance_variable_set(:@version, '1.2')
72
+ def (@document).unwrap(obj); obj; end
73
+ def (@document).deref(obj); obj; end
74
+
75
+ @stm = HexaPDF::Stream.new({}, oid: 1, document: @document)
76
+ end
77
+
78
+ it "#initialize accepts the stream keyword" do
79
+ stm = HexaPDF::Stream.new({}, document: @document, stream: 'other')
80
+ assert_equal('other', stm.stream)
81
+ end
82
+
83
+ it "must always be indirect" do
84
+ @stm.must_be_indirect = false
85
+ assert(@stm.must_be_indirect?)
86
+ end
87
+
88
+ describe "stream=" do
89
+ it "allows assigning nil" do
90
+ @stm.stream = nil
91
+ assert_equal('', @stm.raw_stream)
92
+ assert_equal('', @stm.stream)
93
+ assert_equal(Encoding::BINARY, @stm.stream.encoding)
94
+ end
95
+
96
+ it "allows assigning a string" do
97
+ @stm.stream = 'hallo'
98
+ assert_equal('hallo', @stm.raw_stream)
99
+ assert_equal('hallo', @stm.stream)
100
+ end
101
+
102
+ it "retains the encoding if a String is assigned" do
103
+ @stm.stream = 'hallo'
104
+ assert_equal(Encoding::UTF_8, @stm.stream.encoding)
105
+ @stm.stream = 'hallo'.encode('ISO-8859-1')
106
+ assert_equal(Encoding::ISO_8859_1, @stm.stream.encoding)
107
+ end
108
+
109
+ it "allows assigning a StreamData object" do
110
+ @stmdata = HexaPDF::StreamData.new(StringIO.new('testing'))
111
+ @stm.stream = @stmdata
112
+ assert_equal(@stmdata, @stm.raw_stream)
113
+ assert_equal('testing', @stm.stream)
114
+ assert_equal(Encoding::BINARY, @stm.stream.encoding)
115
+ end
116
+
117
+ it "fails on any object class other than String, StreamData, NilClass" do
118
+ assert_raises(ArgumentError) { @stm.stream = 5 }
119
+ end
120
+ end
121
+
122
+ describe "stream" do
123
+ it "doesn't allow changing the returned value directly" do
124
+ @stm.stream = 'data'
125
+ @stm.stream.upcase!
126
+ assert_equal('data', @stm.stream)
127
+
128
+ @stm.stream = HexaPDF::StreamData.new { "data" }
129
+ @stm.stream.upcase!
130
+ assert_equal('data', @stm.stream)
131
+ end
132
+ end
133
+
134
+ def encoded_data(str, encoders = [])
135
+ map = HexaPDF::GlobalConfiguration['filter.map']
136
+ tmp = feeder(str)
137
+ encoders.each {|e| tmp = ::Object.const_get(map[e]).encoder(tmp)}
138
+ collector(tmp)
139
+ end
140
+
141
+ describe "stream_decoder" do
142
+ it "works with a string stream" do
143
+ @stm.stream = 'testing'
144
+ result = collector(@stm.stream_decoder)
145
+ assert_equal('testing', result)
146
+ assert_equal(Encoding::BINARY, result.encoding)
147
+ end
148
+
149
+ it "works with an IO object inside StreamData" do
150
+ io = StringIO.new(encoded_data('testing', [:A85, :AHx]))
151
+ @stm.stream = HexaPDF::StreamData.new(io, filter: [:AHx, :A85])
152
+ assert_equal('testing', collector(@stm.stream_decoder))
153
+ end
154
+
155
+ it "works with a Proc object inside StreamData" do
156
+ @stm.stream = HexaPDF::StreamData.new(proc {'testing'})
157
+ assert_equal('testing', collector(@stm.stream_decoder))
158
+ end
159
+
160
+ it "fails if an unknown filter name is used" do
161
+ @stm.stream = HexaPDF::StreamData.new(feeder('testing'), filter: [:Unknown])
162
+ assert_raises(HexaPDF::Error) { @stm.stream_decoder }
163
+ end
164
+ end
165
+
166
+ describe "stream_encoder" do
167
+ it "uses the :Filter and :DecodeParms entries of the value attribute correctly" do
168
+ @stm.value[:Filter] = nil
169
+ @stm.stream = 'test'
170
+ assert_equal('test', collector(@stm.stream_encoder))
171
+
172
+ @stm.value[:Filter] = :AHx
173
+ @stm.stream = 'test'
174
+ assert_equal('74657374>', collector(@stm.stream_encoder))
175
+
176
+ @stm.value[:Filter] = [:AHx, :Fl]
177
+ @stm.value[:DecodeParms] = nil
178
+ @stm.stream = 'abcdefg'
179
+ assert_equal("78da4b4c4a4e494d4b07000adb02bd>", collector(@stm.stream_encoder))
180
+
181
+ @stm.value[:Filter] = [:AHx, :Fl]
182
+ @stm.value[:DecodeParms] = [nil, {Predictor: 12}]
183
+ @stm.stream = 'abcdefg'
184
+ assert_equal("78da634a6462444000058f0076>", collector(@stm.stream_encoder))
185
+
186
+ @stm.value[:Filter] = [:AHx, nil, :Fl]
187
+ @stm.value[:DecodeParms] = [nil, nil, {Predictor: 10}]
188
+ @stm.stream = 'abcdefg'
189
+ assert_equal("78da6348644862486648614865486348070012fa02bd>", collector(@stm.stream_encoder))
190
+ end
191
+
192
+ it "decodes a StreamData stream before encoding" do
193
+ @stm.value[:Filter] = :AHx
194
+ data_proc = proc { encoded_data('test', [:A85, :AHx]) }
195
+ @stm.stream = HexaPDF::StreamData.new(data_proc, filter: [:AHx, :A85])
196
+ assert_equal('74657374>', collector(@stm.stream_encoder))
197
+ end
198
+
199
+ it "decodes only what is necessary of a StreamData stream on encoding" do
200
+ @stm.value[:Filter] = :AHx
201
+ data_proc = proc { encoded_data('test', [:AHx, :A85]) }
202
+ @stm.stream = HexaPDF::StreamData.new(data_proc, filter: [:A85, :AHx])
203
+ assert_equal('74657374>', collector(@stm.stream_encoder))
204
+
205
+ @stm.value[:Filter] = [:Unknown]
206
+ @stm.stream = HexaPDF::StreamData.new(proc { 'test' }, filter: [:Unknown])
207
+ assert_equal('test', collector(@stm.stream_encoder))
208
+ end
209
+ end
210
+
211
+ describe "set_filter" do
212
+ it "sets correct filter values without decode parameters" do
213
+ @stm.set_filter(:Test)
214
+ assert_equal(:Test, @stm.value[:Filter])
215
+ refute(@stm.value.key?(:DecodeParms))
216
+
217
+ @stm.set_filter([:Test, :Test1])
218
+ assert_equal([:Test, :Test1], @stm.value[:Filter])
219
+ refute(@stm.value.key?(:DecodeParms))
220
+ end
221
+
222
+ it "sets correct filter/decode parameter values" do
223
+ @stm.set_filter([:Test, :Test], :Other)
224
+ assert_equal([:Test, :Test], @stm.value[:Filter])
225
+ assert_equal(:Other, @stm.value[:DecodeParms])
226
+
227
+ @stm.set_filter([:Test, :Test], [:Other, :Other])
228
+ assert_equal([:Test, :Test], @stm.value[:Filter])
229
+ assert_equal([:Other, :Other], @stm.value[:DecodeParms])
230
+ end
231
+
232
+ it "deletes the /Filter and/or decode parameters values when arguments are nil" do
233
+ @stm.set_filter(:Test, :Other)
234
+ @stm.set_filter(nil, :Other)
235
+ refute(@stm.value.key?(:Filter))
236
+ refute(@stm.value.key?(:DecodeParms))
237
+
238
+ @stm.set_filter(:Test, :Other)
239
+ @stm.set_filter(:Test, nil)
240
+ assert_equal(:Test, @stm[:Filter])
241
+ refute(@stm.value.key?(:DecodeParms))
242
+ end
243
+ end
244
+
245
+ describe "validation" do
246
+ it "validates the /Filter entry" do
247
+ assert(@stm.validate)
248
+
249
+ @stm.set_filter(:FlateDecode)
250
+ assert(@stm.validate(auto_correct: false))
251
+ assert_equal(:FlateDecode, @stm[:Filter])
252
+
253
+ @stm.set_filter(:AHx)
254
+ assert(@stm.validate(auto_correct: true))
255
+ assert_equal(:ASCIIHexDecode, @stm[:Filter])
256
+
257
+ @stm.set_filter([:FlateDecode, :AHx])
258
+ assert(@stm.validate(auto_correct: true))
259
+ assert_equal([:FlateDecode, :ASCIIHexDecode], @stm[:Filter])
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/tokenizer'
5
+ require 'stringio'
6
+ require_relative 'common_tokenizer_tests'
7
+
8
+ describe HexaPDF::Tokenizer do
9
+ include CommonTokenizerTests
10
+
11
+ def create_tokenizer(str)
12
+ @tokenizer = HexaPDF::Tokenizer.new(StringIO.new(str.b))
13
+ end
14
+
15
+ it "handles object references" do
16
+ create_tokenizer("1 0 R 2 15 R ")
17
+ assert_equal(HexaPDF::Reference.new(1, 0), @tokenizer.next_token)
18
+ assert_equal(HexaPDF::Reference.new(2, 15), @tokenizer.next_token)
19
+ @tokenizer.pos = 0
20
+ assert_equal(HexaPDF::Reference.new(1, 0), @tokenizer.next_object)
21
+ assert_equal(HexaPDF::Reference.new(2, 15), @tokenizer.next_object)
22
+ end
23
+
24
+ it "next_token: should not fail when resetting the position (due to the use of the internal StringScanner buffer)" do
25
+ create_tokenizer("0 1 2 3 4 " * 4000)
26
+ 4000.times do
27
+ 5.times {|i| assert_equal(i, @tokenizer.next_token)}
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,120 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/writer'
5
+ require 'hexapdf/document'
6
+ require 'stringio'
7
+
8
+ describe HexaPDF::Writer do
9
+ before do
10
+ @std_input_io = StringIO.new(<<EOF.force_encoding(Encoding::BINARY))
11
+ %PDF-1.7
12
+ %\xCF\xEC\xFF\xE8\xD7\xCB\xCD
13
+ 1 0 obj
14
+ 10
15
+ endobj
16
+ 2 0 obj
17
+ 20
18
+ endobj
19
+ xref
20
+ 0 3
21
+ 0000000000 65535 f
22
+ 0000000018 00000 n
23
+ 0000000036 00000 n
24
+ trailer
25
+ <</Size 3>>
26
+ startxref
27
+ 54
28
+ %%EOF
29
+ 2 0 obj
30
+ <</Length 10>>stream
31
+ Some data!
32
+ endstream
33
+ endobj
34
+ xref
35
+ 2 1
36
+ 0000000162 00000 n
37
+ trailer
38
+ <</Size 3/Prev 54>>
39
+ startxref
40
+ 219
41
+ %%EOF
42
+ 3 0 obj
43
+ <</Producer(HexaPDF version 0.1.0)>>
44
+ endobj
45
+ xref
46
+ 3 1
47
+ 0000000296 00000 n
48
+ trailer
49
+ <</Prev 219/Size 4/Root<</Type/Catalog>>/Info 3 0 R>>
50
+ startxref
51
+ 348
52
+ %%EOF
53
+ EOF
54
+
55
+ @compressed_input_io = StringIO.new(<<EOF.force_encoding(Encoding::BINARY))
56
+ %PDF-1.7
57
+ %\xCF\xEC\xFF\xE8\xD7\xCB\xCD
58
+ 5 0 obj
59
+ <</Type/ObjStm/N 1/First 4/Filter/FlateDecode/Length 15>>stream
60
+ x\xDA3T0P04P\x00\x00\x04\xA1\x01#
61
+ endstream
62
+ endobj
63
+ 2 0 obj
64
+ 20
65
+ endobj
66
+ 3 0 obj
67
+ <</Size 6/Type/XRef/W[1 1 2]/Index[0 4 5 1]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 31>>stream
68
+ x\xDAcb`\xF8\xFF\x9F\x89\x89\x95\x91\x91\xE9\x7F\x19\x03\x03\x13\x83\x10\x88he`\x00\x00B4\x04\x1E
69
+ endstream
70
+ endobj
71
+ startxref
72
+ 141
73
+ %%EOF
74
+ 6 0 obj
75
+ <</Producer(HexaPDF version 0.1.0)>>
76
+ endobj
77
+ 2 0 obj
78
+ <</Length 10>>stream
79
+ Some data!
80
+ endstream
81
+ endobj
82
+ 4 0 obj
83
+ <</Size 7/Prev 141/Root<</Type/Catalog>>/Info 6 0 R/Type/XRef/W[1 2 2]/Index[2 1 4 1 6 1]/Filter/FlateDecode/DecodeParms<</Columns 5/Predictor 12>>/Length 22>>stream
84
+ x\xDAcbdlc``b`\xB0\x04\x93\x93\x19\x18\x00\f\x0F\x01[
85
+ endstream
86
+ endobj
87
+ startxref
88
+ 447
89
+ %%EOF
90
+ EOF
91
+ end
92
+
93
+ def assert_document_conversion(input_io)
94
+ document = HexaPDF::Document.new(io: input_io)
95
+ document.trailer.info[:Producer] = "unknown"
96
+ output_io = StringIO.new(''.force_encoding(Encoding::BINARY))
97
+ HexaPDF::Writer.write(document, output_io)
98
+ assert_equal(input_io.string, output_io.string)
99
+ end
100
+
101
+ it "writes a complete document" do
102
+ assert_document_conversion(@std_input_io)
103
+ assert_document_conversion(@compressed_input_io)
104
+ end
105
+
106
+ it "raises an error if no xref stream is in a revision but object streams are" do
107
+ document = HexaPDF::Document.new
108
+ document.add(Type: :ObjStm)
109
+ assert_raises(HexaPDF::Error) { HexaPDF::Writer.new(document, StringIO.new).write }
110
+ end
111
+
112
+ it "raises an error if the class is misused and an xref section contains invalid entries" do
113
+ document = HexaPDF::Document.new
114
+ io = StringIO.new
115
+ writer = HexaPDF::Writer.new(document, io)
116
+ xref_section = HexaPDF::XRefSection.new
117
+ xref_section.add_compressed_entry(1, 2, 3)
118
+ assert_raises(HexaPDF::Error) { writer.send(:write_xref_section, xref_section) }
119
+ end
120
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/xref_section'
5
+
6
+ describe HexaPDF::XRefSection do
7
+ before do
8
+ @xref_section = HexaPDF::XRefSection.new
9
+ end
10
+
11
+ describe "each_subsection" do
12
+ def assert_subsections(result)
13
+ assert_equal(result, @xref_section.each_subsection.map {|s| s.map(&:oid)})
14
+ end
15
+
16
+ it "works for newly initialized objects" do
17
+ assert_subsections([[]])
18
+ end
19
+
20
+ it "works for a single subsection" do
21
+ @xref_section.add_in_use_entry(1, 0, 0)
22
+ @xref_section.add_in_use_entry(2, 0, 0)
23
+ assert_subsections([[1, 2]])
24
+ end
25
+
26
+ it "works for multiple subsections" do
27
+ @xref_section.add_in_use_entry(10, 0, 0)
28
+ @xref_section.add_in_use_entry(11, 0, 0)
29
+ @xref_section.add_in_use_entry(1, 0, 0)
30
+ @xref_section.add_in_use_entry(2, 0, 0)
31
+ @xref_section.add_in_use_entry(20, 0, 0)
32
+ assert_subsections([[1, 2], [10, 11], [20]])
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/catalog'
6
+
7
+ describe HexaPDF::Type::Catalog do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @catalog = @doc.add(Type: :Catalog)
11
+ end
12
+
13
+ it "must always be indirect" do
14
+ @catalog.must_be_indirect = false
15
+ assert(@catalog.must_be_indirect?)
16
+ end
17
+
18
+ it "creates the page tree on access" do
19
+ assert_nil(@catalog[:Pages])
20
+ pages = @catalog.pages
21
+ assert_equal(:Pages, pages.type)
22
+ end
23
+
24
+ describe "validation" do
25
+ it "creates the page tree if necessary" do
26
+ refute(@catalog.validate(auto_correct: false))
27
+ assert(@catalog.validate)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+ require 'hexapdf/type/embedded_file'
3
+
4
+ describe HexaPDF::Type::EmbeddedFile::MacInfo do
5
+ it "uses a custom type" do
6
+ obj = HexaPDF::Type::EmbeddedFile::MacInfo.new({})
7
+ assert_equal(:XXEmbeddedFileParametersMacInfo, obj.type)
8
+ end
9
+ end
10
+
11
+ describe HexaPDF::Type::EmbeddedFile::Parameters do
12
+ it "uses a custom type" do
13
+ obj = HexaPDF::Type::EmbeddedFile::Parameters.new({})
14
+ assert_equal(:XXEmbeddedFileParameters, obj.type)
15
+ end
16
+ end