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,406 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'strscan'
35
+ require 'hexapdf/error'
36
+ require 'hexapdf/reference'
37
+
38
+ module HexaPDF
39
+
40
+ # Tokenizes the content of an IO object following the PDF rules.
41
+ #
42
+ # See: PDF1.7 s7.2
43
+ class Tokenizer
44
+
45
+ # Represents a keyword in a PDF file.
46
+ class Token < String; end
47
+
48
+ TOKEN_DICT_START = Token.new('<<'.b) # :nodoc:
49
+ TOKEN_DICT_END = Token.new('>>'.b) # :nodoc:
50
+ TOKEN_ARRAY_START = Token.new('['.b) # :nodoc:
51
+ TOKEN_ARRAY_END = Token.new(']'.b) # :nodoc:
52
+
53
+ # This object is returned when there are no more tokens to read.
54
+ NO_MORE_TOKENS = ::Object.new
55
+
56
+ # Characters defined as whitespace.
57
+ #
58
+ # See: PDF1.7 s7.2.2
59
+ WHITESPACE = "\0\t\n\f\r "
60
+
61
+ # Characters defined as delimiters.
62
+ #
63
+ # See: PDF1.7 s7.2.2
64
+ DELIMITER = "()<>{}/[]%"
65
+
66
+ WHITESPACE_MULTI_RE = /[#{WHITESPACE}]+/ # :nodoc:
67
+
68
+ WHITESPACE_OR_DELIMITER_RE = /(?=[#{Regexp.escape(WHITESPACE)}#{Regexp.escape(DELIMITER)}])/ # :nodoc:
69
+
70
+
71
+ # The IO object from the tokens are read.
72
+ attr_reader :io
73
+
74
+ # Creates a new tokenizer.
75
+ def initialize(io)
76
+ @io = io
77
+ @ss = StringScanner.new(''.b)
78
+ @original_pos = -1
79
+ self.pos = 0
80
+ end
81
+
82
+ # Returns the current position of the tokenizer inside in the IO object.
83
+ #
84
+ # Note that this position might be different from +io.pos+ since the latter could have been
85
+ # changed somewhere else.
86
+ def pos
87
+ @original_pos + @ss.pos
88
+ end
89
+
90
+ # Sets the position at which the next token should be read.
91
+ #
92
+ # Note that this does **not** set +io.pos+ directly (at the moment of invocation)!
93
+ def pos=(pos)
94
+ if pos >= @original_pos && pos <= @original_pos + @ss.string.size
95
+ @ss.pos = pos - @original_pos
96
+ else
97
+ @original_pos = pos
98
+ @next_read_pos = pos
99
+ @ss.string.clear
100
+ @ss.reset
101
+ end
102
+ end
103
+
104
+ # Returns a single token read from the current position and advances the scan pointer.
105
+ #
106
+ # Comments and a run of whitespace characters are ignored. The value +NO_MORE_TOKENS+ is
107
+ # returned if there are no more tokens available.
108
+ def next_token
109
+ prepare_string_scanner(20)
110
+ prepare_string_scanner(20) while @ss.skip(WHITESPACE_MULTI_RE)
111
+ case (@ss.eos? ? -1 : @ss.string.getbyte(@ss.pos))
112
+ when 43, 45, 46, 48..57 # + - . 0..9
113
+ parse_number
114
+ when 47 # /
115
+ parse_name
116
+ when 40 # (
117
+ parse_literal_string
118
+ when 60 # <
119
+ if @ss.string.getbyte(@ss.pos + 1) != 60
120
+ parse_hex_string
121
+ else
122
+ @ss.pos += 2
123
+ TOKEN_DICT_START
124
+ end
125
+ when 62 # >
126
+ unless @ss.string.getbyte(@ss.pos + 1) == 62
127
+ raise HexaPDF::MalformedPDFError.new("Delimiter '>' found at invalid position", pos: pos)
128
+ end
129
+ @ss.pos += 2
130
+ TOKEN_DICT_END
131
+ when 91 # [
132
+ @ss.pos += 1
133
+ TOKEN_ARRAY_START
134
+ when 93 # ]
135
+ @ss.pos += 1
136
+ TOKEN_ARRAY_END
137
+ when 123, 125 # { }
138
+ Token.new(@ss.get_byte)
139
+ when 37 # %
140
+ until @ss.skip_until(/(?=[\r\n])/)
141
+ return NO_MORE_TOKENS unless prepare_string_scanner
142
+ end
143
+ next_token
144
+ when -1 # we reached the end of the file
145
+ NO_MORE_TOKENS
146
+ else # everything else consisting of regular characters
147
+ parse_keyword
148
+ end
149
+ end
150
+
151
+ # Returns the next token but does not advance the scan pointer.
152
+ def peek_token
153
+ pos = self.pos
154
+ tok = next_token
155
+ self.pos = pos
156
+ tok
157
+ end
158
+
159
+ # Returns the PDF object at the current position. This is different from #next_token because
160
+ # references, arrays and dictionaries consist of multiple tokens.
161
+ #
162
+ # If the +allow_end_array_token+ argument is +true+, the ']' token is permitted to facilitate
163
+ # the use of this method during array parsing.
164
+ #
165
+ # See: PDF1.7 s7.3
166
+ def next_object(allow_end_array_token: false, allow_keyword: false)
167
+ token = next_token
168
+
169
+ if token.kind_of?(Token)
170
+ case token
171
+ when TOKEN_DICT_START
172
+ token = parse_dictionary
173
+ when TOKEN_ARRAY_START
174
+ token = parse_array
175
+ when TOKEN_ARRAY_END
176
+ unless allow_end_array_token
177
+ raise HexaPDF::MalformedPDFError.new("Found invalid end array token ']'", pos: pos)
178
+ end
179
+ else
180
+ unless allow_keyword
181
+ raise HexaPDF::MalformedPDFError.new("Invalid object, got token #{token}", pos: pos)
182
+ end
183
+ end
184
+ end
185
+
186
+ token
187
+ end
188
+
189
+ # Reads the byte (an integer) at the current position and advances the scan pointer.
190
+ def next_byte
191
+ prepare_string_scanner(1)
192
+ @ss.pos += 1
193
+ @ss.string.getbyte(@ss.pos - 1)
194
+ end
195
+
196
+ # Reads the cross-reference subsection entry at the current position and advances the scan
197
+ # pointer.
198
+ #
199
+ # See: PDF1.7 7.5.4
200
+ def next_xref_entry
201
+ prepare_string_scanner(20)
202
+ unless @ss.skip(/(\d{10}) (\d{5}) ([nf])(?: \r| \n|\r\n)/)
203
+ raise HexaPDF::MalformedPDFError.new("Invalid cross-reference subsection entry", pos: pos)
204
+ end
205
+ [@ss[1].to_i, @ss[2].to_i, @ss[3]]
206
+ end
207
+
208
+ # Skips all whitespace at the current position.
209
+ #
210
+ # See: PDF1.7 s7.2.2
211
+ def skip_whitespace
212
+ prepare_string_scanner
213
+ prepare_string_scanner while @ss.skip(WHITESPACE_MULTI_RE)
214
+ end
215
+
216
+ # Utility method for scanning until the given regular expression matches.
217
+ #
218
+ # If the end of the file is reached in the process, +nil+ is returned. Otherwise the matched
219
+ # string is returned.
220
+ def scan_until(re)
221
+ until (data = @ss.scan_until(re))
222
+ return nil unless prepare_string_scanner
223
+ end
224
+ data
225
+ end
226
+
227
+ private
228
+
229
+ TOKEN_CACHE = Hash.new {|h, k| h[k] = Token.new(k)} # :nodoc:
230
+ TOKEN_CACHE['true'] = true
231
+ TOKEN_CACHE['false'] = false
232
+ TOKEN_CACHE['null'] = nil
233
+
234
+ # Parses the keyword at the current position.
235
+ #
236
+ # See: PDF1.7 s7.2
237
+ def parse_keyword
238
+ str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/).freeze
239
+ TOKEN_CACHE[str.freeze]
240
+ end
241
+
242
+ REFERENCE_RE = /[#{WHITESPACE}]+([+-]?\d+)[#{WHITESPACE}]+R(?=[#{Regexp.escape(WHITESPACE)}#{Regexp.escape(DELIMITER)}])/ # :nodoc:
243
+
244
+ # Parses the number (integer or real) at the current position.
245
+ #
246
+ # See: PDF1.7 s7.3.3
247
+ def parse_number
248
+ if (val = @ss.scan(/[+-]?\d++(?!\.)/))
249
+ tmp = val.to_i
250
+ # Handle object references, see PDF1.7 s7.3.10
251
+ prepare_string_scanner(10)
252
+ tmp = Reference.new(tmp, @ss[1].to_i) if @ss.scan(REFERENCE_RE)
253
+ tmp
254
+ else
255
+ val = @ss.scan(/[+-]?(?:\d+\.\d*|\.\d+)/)
256
+ val << '0'.freeze if val.getbyte(-1) == 46 # dot '.'
257
+ Float(val)
258
+ end
259
+ end
260
+
261
+ LITERAL_STRING_ESCAPE_MAP = { #:nodoc:
262
+ 'n' => "\n",
263
+ 'r' => "\r",
264
+ 't' => "\t",
265
+ 'b' => "\b",
266
+ 'f' => "\f",
267
+ '(' => "(",
268
+ ')' => ")",
269
+ '\\' => "\\",
270
+ }
271
+
272
+ # Parses the literal string at the current position.
273
+ #
274
+ # See: PDF1.7 s7.3.4.2
275
+ def parse_literal_string
276
+ @ss.pos += 1
277
+ str = "".b
278
+ parentheses = 1
279
+
280
+ while parentheses != 0
281
+ data = scan_until(/([()\\\r])/)
282
+ char = @ss[1]
283
+ unless data
284
+ raise HexaPDF::MalformedPDFError.new("Unclosed literal string found", pos: pos)
285
+ end
286
+
287
+ str << data
288
+ prepare_string_scanner if @ss.eos?
289
+ case char
290
+ when '(' then parentheses += 1
291
+ when ')' then parentheses -= 1
292
+ when "\r"
293
+ str[-1] = "\n"
294
+ @ss.pos += 1 if @ss.peek(1) == "\n"
295
+ when '\\'
296
+ str.chop!
297
+ byte = @ss.get_byte
298
+ if (data = LITERAL_STRING_ESCAPE_MAP[byte])
299
+ str << data
300
+ elsif byte == "\r" || byte == "\n"
301
+ @ss.pos += 1 if byte == "\r" && @ss.peek(1) == "\n"
302
+ elsif byte >= '0' && byte <= '7'
303
+ byte += @ss.scan(/[0-7]{0,2}/)
304
+ str << byte.oct.chr
305
+ else
306
+ str << byte
307
+ end
308
+ end
309
+ end
310
+
311
+ str.chop! # remove last parsed closing parenthesis
312
+ str
313
+ end
314
+
315
+ # Parses the hex string at the current position.
316
+ #
317
+ # See: PDF1.7 s7.3.4.3
318
+ def parse_hex_string
319
+ @ss.pos += 1
320
+ data = scan_until(/(?=>)/)
321
+ unless data
322
+ raise HexaPDF::MalformedPDFError.new("Unclosed hex string found", pos: pos)
323
+ end
324
+
325
+ @ss.pos += 1
326
+ data.tr!(WHITESPACE, "".freeze)
327
+ [data].pack('H*'.freeze)
328
+ end
329
+
330
+ # Parses the name at the current position.
331
+ #
332
+ # See: PDF1.7 s7.3.5
333
+ def parse_name
334
+ @ss.pos += 1
335
+ str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
336
+ str.gsub!(/#[A-Fa-f0-9]{2}/) {|m| m[1, 2].hex.chr }
337
+ if str.force_encoding(Encoding::UTF_8).valid_encoding?
338
+ str.to_sym
339
+ else
340
+ str.force_encoding(Encoding::BINARY).to_sym
341
+ end
342
+ end
343
+
344
+ # Parses the array at the current position.
345
+ #
346
+ # It is assumed that the initial '[' has already been scanned.
347
+ #
348
+ # See: PDF1.7 s7.3.6
349
+ def parse_array
350
+ result = []
351
+ while true
352
+ obj = next_object(allow_end_array_token: true)
353
+ break if obj.equal?(TOKEN_ARRAY_END)
354
+ result << obj
355
+ end
356
+ result
357
+ end
358
+
359
+ # Parses the dictionary at the current position.
360
+ #
361
+ # It is assumed that the initial '<<' has already been scanned.
362
+ #
363
+ # See: PDF1.7 s7.3.7
364
+ def parse_dictionary
365
+ result = {}
366
+ while true
367
+ # Use #next_token because we either need a Name or the '>>' token here, the latter would
368
+ # throw an error with #next_object.
369
+ key = next_token
370
+ break if key.equal?(TOKEN_DICT_END)
371
+ unless key.kind_of?(Symbol)
372
+ raise HexaPDF::MalformedPDFError.new("Dictionary keys must be PDF name objects", pos: pos)
373
+ end
374
+
375
+ val = next_object
376
+ next if val.nil?
377
+
378
+ result[key] = val
379
+ end
380
+ result
381
+ end
382
+
383
+
384
+ # Prepares the StringScanner by filling its string instance with enough bytes.
385
+ #
386
+ # The number of needed bytes can be specified via the optional +needed_bytes+ argument.
387
+ #
388
+ # Returns +true+ if the end of the underlying IO stream has not been reached, yet.
389
+ def prepare_string_scanner(needed_bytes = nil)
390
+ return if needed_bytes && @ss.rest_size >= needed_bytes
391
+ @io.seek(@next_read_pos)
392
+ return false if @io.eof?
393
+
394
+ @ss << @io.read(8192)
395
+ if @ss.pos > 8192 && @ss.string.length > 16384
396
+ @ss.string.slice!(0, 8192)
397
+ @ss.pos -= 8192
398
+ @original_pos += 8192
399
+ end
400
+ @next_read_pos = @io.pos
401
+ true
402
+ end
403
+
404
+ end
405
+
406
+ end
@@ -0,0 +1,107 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/dictionary'
35
+ require 'hexapdf/number_tree_node'
36
+ require 'hexapdf/stream'
37
+
38
+ module HexaPDF
39
+ module Type
40
+
41
+ # Represents the PDF's catalog dictionary which is at the root of the document's object
42
+ # hierarchy.
43
+ #
44
+ # The catalog dictionary is linked via the /Root entry from the Trailer.
45
+ #
46
+ # See: PDF1.7 s7.7.2, Trailer
47
+ class Catalog < Dictionary
48
+
49
+ define_field :Type, type: Symbol, required: true, default: :Catalog
50
+ define_field :Version, type: Symbol, version: '1.4'
51
+ define_field :Extensions, type: Dictionary, version: '1.7'
52
+ # Pages field is required but this is handled in #perform_validation
53
+ define_field :Pages, type: :Pages, indirect: true
54
+ define_field :PageLabels, type: NumberTreeNode, version: '1.3'
55
+ define_field :Names, type: :XXNames, version: '1.2'
56
+ define_field :Dests, type: Dictionary, version: '1.1'
57
+ define_field :ViewerPreferences, type: :XXViewerPreferences, version: '1.2'
58
+ define_field :PageLayout, type: Symbol, default: :SinglePage
59
+ define_field :PageMode, type: Symbol, default: :UseNone
60
+ define_field :Outlines, type: Dictionary, indirect: true
61
+ define_field :Threads, type: Array, version: '1.1'
62
+ define_field :OpenAction, type: [Array, Dictionary, Hash], version: '1.1'
63
+ define_field :AA, type: Dictionary, version: '1.4'
64
+ define_field :URI, type: Dictionary, version: '1.1'
65
+ define_field :AcroForm, type: Dictionary, version: '1.2'
66
+ define_field :Metadata, type: Stream, indirect: true, version: '1.4'
67
+ define_field :StructTreeRoot, type: Dictionary, version: '1.3'
68
+ define_field :MarkInfo, type: Dictionary, version: '1.4'
69
+ define_field :Lang, type: String, version: '1.4'
70
+ define_field :SpiderInfo, type: Dictionary, version: '1.3'
71
+ define_field :OutputIntents, type: Array, version: '1.4'
72
+ define_field :PieceInfo, type: Dictionary, version: '1.4'
73
+ define_field :OCProperties, type: Dictionary, version: '1.5'
74
+ define_field :Perms, type: Dictionary, version: '1.5'
75
+ define_field :Legal, type: Dictionary, version: '1.5'
76
+ define_field :Requirements, type: Array, version: '1.7'
77
+ define_field :Collection, type: Dictionary, version: '1.7'
78
+ define_field :NeedsRendering, type: Boolean, version: '1.7'
79
+
80
+ # Returns +true+ since catalog objects must always be indirect.
81
+ def must_be_indirect?
82
+ true
83
+ end
84
+
85
+ # Returns the root node of the page tree.
86
+ #
87
+ # See: PageTreeNode
88
+ def pages
89
+ self[:Pages] ||= document.add(Type: :Pages)
90
+ end
91
+
92
+ private
93
+
94
+ # Ensures that there is a valid page tree.
95
+ def perform_validation
96
+ super
97
+ unless key?(:Pages)
98
+ yield("A PDF document needs a page tree", true)
99
+ value[:Pages] = document.add(Type: :Pages)
100
+ value[:Pages].validate {|msg, correctable| yield(msg, correctable)}
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,87 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/stream'
35
+
36
+ module HexaPDF
37
+ module Type
38
+
39
+ # Represents an embedded file stream.
40
+ #
41
+ # An embedded file stream contains the data of, and optionally some meta data about, a file
42
+ # that is embedded into the PDF file. Each embedded file is either associated with a certain
43
+ # Type::FileSpecification dictionary or with the document as a whole through the /EmbeddedFiles
44
+ # entry in the document catalog's /Names dictionary.
45
+ #
46
+ # See: PDF1.7 s7.11.4, FileSpecification
47
+ class EmbeddedFile < Stream
48
+
49
+ # The type used for the /Mac field of an EmbeddedFile::Parameters dictionary.
50
+ class MacInfo < Dictionary
51
+
52
+ define_field :Subtype, type: Integer
53
+ define_field :Creator, type: Integer
54
+ define_field :ResFork, type: Stream
55
+
56
+ # Returns +:XXEmbeddedFileParametersMacInfo+
57
+ def type
58
+ :XXEmbeddedFileParametersMacInfo
59
+ end
60
+
61
+ end
62
+
63
+ # The type used for the /Params field of an EmbeddedFileStream.
64
+ class Parameters < Dictionary
65
+
66
+ define_field :Size, type: Integer
67
+ define_field :CreationDate, type: PDFDate
68
+ define_field :ModDate, type: PDFDate
69
+ define_field :Mac, type: :XXEmbeddedFileParametersMacInfo
70
+ define_field :CheckSum, type: PDFByteString
71
+
72
+ # Returns +:XXEmbeddedFileParameters+
73
+ def type
74
+ :XXEmbeddedFileParameters
75
+ end
76
+
77
+ end
78
+
79
+
80
+ define_field :Type, type: Symbol, default: :EmbeddedFile, version: '1.3'
81
+ define_field :Subtype, type: Symbol
82
+ define_field :Params, type: :XXEmbeddedFileParameters
83
+
84
+ end
85
+
86
+ end
87
+ end