hexapdf 0.32.2 → 0.34.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/examples/026-optional_content.rb +55 -0
  19. data/examples/027-composer_optional_content.rb +83 -0
  20. data/lib/hexapdf/cli/command.rb +12 -3
  21. data/lib/hexapdf/cli/fonts.rb +1 -1
  22. data/lib/hexapdf/cli/form.rb +5 -5
  23. data/lib/hexapdf/cli/inspect.rb +5 -7
  24. data/lib/hexapdf/composer.rb +106 -53
  25. data/lib/hexapdf/configuration.rb +65 -40
  26. data/lib/hexapdf/content/canvas.rb +445 -267
  27. data/lib/hexapdf/content/color_space.rb +72 -25
  28. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  31. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  32. data/lib/hexapdf/content/graphic_object.rb +6 -7
  33. data/lib/hexapdf/content/graphics_state.rb +54 -45
  34. data/lib/hexapdf/content/operator.rb +54 -54
  35. data/lib/hexapdf/content/parser.rb +2 -2
  36. data/lib/hexapdf/content/processor.rb +15 -15
  37. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  38. data/lib/hexapdf/content.rb +5 -0
  39. data/lib/hexapdf/dictionary.rb +7 -5
  40. data/lib/hexapdf/dictionary_fields.rb +43 -16
  41. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  42. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  43. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  44. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  45. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  46. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  47. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  48. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  49. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  50. data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
  51. data/lib/hexapdf/digital_signature.rb +7 -2
  52. data/lib/hexapdf/document/destinations.rb +12 -11
  53. data/lib/hexapdf/document/files.rb +1 -1
  54. data/lib/hexapdf/document/fonts.rb +1 -1
  55. data/lib/hexapdf/document/layout.rb +170 -39
  56. data/lib/hexapdf/document/pages.rb +4 -3
  57. data/lib/hexapdf/document.rb +96 -55
  58. data/lib/hexapdf/encryption/aes.rb +5 -5
  59. data/lib/hexapdf/encryption/arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  61. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/identity.rb +1 -1
  63. data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
  64. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  65. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  66. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  67. data/lib/hexapdf/encryption.rb +7 -2
  68. data/lib/hexapdf/error.rb +18 -0
  69. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  70. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  71. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  72. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  73. data/lib/hexapdf/filter/pass_through.rb +1 -1
  74. data/lib/hexapdf/filter/predictor.rb +1 -1
  75. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  76. data/lib/hexapdf/filter.rb +55 -6
  77. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  78. data/lib/hexapdf/font/cmap.rb +1 -1
  79. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  82. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  83. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  84. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  85. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  86. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  87. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  88. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  89. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  90. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  91. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  92. data/lib/hexapdf/font_loader.rb +3 -0
  93. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  94. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  95. data/lib/hexapdf/image_loader/png.rb +2 -2
  96. data/lib/hexapdf/image_loader.rb +1 -1
  97. data/lib/hexapdf/importer.rb +13 -0
  98. data/lib/hexapdf/layout/box.rb +32 -5
  99. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  100. data/lib/hexapdf/layout/column_box.rb +20 -5
  101. data/lib/hexapdf/layout/frame.rb +53 -18
  102. data/lib/hexapdf/layout/image_box.rb +5 -0
  103. data/lib/hexapdf/layout/inline_box.rb +21 -9
  104. data/lib/hexapdf/layout/list_box.rb +50 -20
  105. data/lib/hexapdf/layout/page_style.rb +6 -5
  106. data/lib/hexapdf/layout/style.rb +64 -9
  107. data/lib/hexapdf/layout/table_box.rb +684 -0
  108. data/lib/hexapdf/layout/text_box.rb +12 -3
  109. data/lib/hexapdf/layout/text_fragment.rb +29 -3
  110. data/lib/hexapdf/layout/text_layouter.rb +32 -8
  111. data/lib/hexapdf/layout.rb +1 -0
  112. data/lib/hexapdf/name_tree_node.rb +1 -1
  113. data/lib/hexapdf/number_tree_node.rb +1 -1
  114. data/lib/hexapdf/object.rb +18 -7
  115. data/lib/hexapdf/parser.rb +7 -7
  116. data/lib/hexapdf/pdf_array.rb +1 -1
  117. data/lib/hexapdf/rectangle.rb +1 -1
  118. data/lib/hexapdf/reference.rb +1 -1
  119. data/lib/hexapdf/revision.rb +1 -1
  120. data/lib/hexapdf/revisions.rb +3 -3
  121. data/lib/hexapdf/serializer.rb +15 -15
  122. data/lib/hexapdf/stream.rb +5 -4
  123. data/lib/hexapdf/tokenizer.rb +14 -14
  124. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  125. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  128. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  130. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  131. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  132. data/lib/hexapdf/type/acro_form.rb +1 -1
  133. data/lib/hexapdf/type/action.rb +1 -1
  134. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  135. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  136. data/lib/hexapdf/type/actions/launch.rb +1 -1
  137. data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
  138. data/lib/hexapdf/type/actions/uri.rb +1 -1
  139. data/lib/hexapdf/type/actions.rb +2 -1
  140. data/lib/hexapdf/type/annotation.rb +3 -3
  141. data/lib/hexapdf/type/annotations/link.rb +1 -1
  142. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  143. data/lib/hexapdf/type/annotations/text.rb +2 -3
  144. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  145. data/lib/hexapdf/type/annotations.rb +1 -1
  146. data/lib/hexapdf/type/catalog.rb +11 -2
  147. data/lib/hexapdf/type/cid_font.rb +18 -4
  148. data/lib/hexapdf/type/embedded_file.rb +1 -1
  149. data/lib/hexapdf/type/file_specification.rb +2 -2
  150. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  151. data/lib/hexapdf/type/font_simple.rb +2 -2
  152. data/lib/hexapdf/type/font_type0.rb +3 -3
  153. data/lib/hexapdf/type/font_type3.rb +1 -1
  154. data/lib/hexapdf/type/form.rb +76 -6
  155. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  156. data/lib/hexapdf/type/icon_fit.rb +1 -1
  157. data/lib/hexapdf/type/image.rb +1 -1
  158. data/lib/hexapdf/type/info.rb +1 -1
  159. data/lib/hexapdf/type/mark_information.rb +1 -1
  160. data/lib/hexapdf/type/names.rb +2 -2
  161. data/lib/hexapdf/type/object_stream.rb +2 -1
  162. data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
  163. data/lib/hexapdf/type/optional_content_group.rb +370 -0
  164. data/lib/hexapdf/type/optional_content_membership.rb +63 -0
  165. data/lib/hexapdf/type/optional_content_properties.rb +158 -0
  166. data/lib/hexapdf/type/outline.rb +1 -1
  167. data/lib/hexapdf/type/outline_item.rb +1 -1
  168. data/lib/hexapdf/type/page.rb +46 -21
  169. data/lib/hexapdf/type/page_label.rb +5 -9
  170. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  171. data/lib/hexapdf/type/resources.rb +1 -1
  172. data/lib/hexapdf/type/trailer.rb +2 -2
  173. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  174. data/lib/hexapdf/type/xref_stream.rb +2 -2
  175. data/lib/hexapdf/type.rb +4 -0
  176. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
  177. data/lib/hexapdf/version.rb +1 -1
  178. data/lib/hexapdf/writer.rb +4 -4
  179. data/lib/hexapdf/xref_section.rb +2 -2
  180. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  181. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  182. data/test/hexapdf/content/test_canvas.rb +49 -1
  183. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  184. data/test/hexapdf/document/test_files.rb +2 -2
  185. data/test/hexapdf/document/test_layout.rb +105 -2
  186. data/test/hexapdf/document/test_pages.rb +6 -6
  187. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  188. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  189. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  190. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  191. data/test/hexapdf/layout/test_box.rb +14 -5
  192. data/test/hexapdf/layout/test_column_box.rb +65 -21
  193. data/test/hexapdf/layout/test_frame.rb +27 -15
  194. data/test/hexapdf/layout/test_image_box.rb +4 -0
  195. data/test/hexapdf/layout/test_inline_box.rb +17 -3
  196. data/test/hexapdf/layout/test_list_box.rb +84 -33
  197. data/test/hexapdf/layout/test_page_style.rb +3 -2
  198. data/test/hexapdf/layout/test_style.rb +60 -0
  199. data/test/hexapdf/layout/test_table_box.rb +728 -0
  200. data/test/hexapdf/layout/test_text_box.rb +26 -0
  201. data/test/hexapdf/layout/test_text_fragment.rb +33 -0
  202. data/test/hexapdf/layout/test_text_layouter.rb +36 -5
  203. data/test/hexapdf/test_composer.rb +10 -0
  204. data/test/hexapdf/test_dictionary.rb +10 -0
  205. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  206. data/test/hexapdf/test_document.rb +5 -0
  207. data/test/hexapdf/test_filter.rb +8 -0
  208. data/test/hexapdf/test_importer.rb +9 -0
  209. data/test/hexapdf/test_object.rb +16 -5
  210. data/test/hexapdf/test_stream.rb +7 -0
  211. data/test/hexapdf/test_writer.rb +3 -3
  212. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  213. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  214. data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
  215. data/test/hexapdf/type/test_catalog.rb +11 -0
  216. data/test/hexapdf/type/test_form.rb +119 -0
  217. data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
  218. data/test/hexapdf/type/test_optional_content_group.rb +158 -0
  219. data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
  220. data/test/hexapdf/type/test_page.rb +20 -6
  221. metadata +28 -8
@@ -47,12 +47,12 @@ module HexaPDF
47
47
  # Contains entries common to all encryption dictionaries. If a specific security handler
48
48
  # needs further fields it should derive a new subclass and add the new fields there.
49
49
  #
50
- # See: PDF1.7 s7.6.1
50
+ # See: PDF2.0 s7.6.2
51
51
  class EncryptionDictionary < Dictionary
52
52
 
53
53
  define_field :Filter, type: Symbol, required: true
54
54
  define_field :SubFilter, type: Symbol, version: '1.3'
55
- define_field :V, type: Integer, required: true
55
+ define_field :V, type: Integer, required: true, allowed_values: [0, 1, 2, 3, 4, 5]
56
56
  define_field :Lenth, type: Integer, default: 40, version: '1.4'
57
57
  define_field :CF, type: Dictionary, version: '1.5'
58
58
  define_field :StmF, type: Symbol, default: :Identity, version: '1.5'
@@ -70,12 +70,8 @@ module HexaPDF
70
70
  # Ensures that the encryption dictionary's content is valid.
71
71
  def perform_validation
72
72
  super
73
- unless [1, 2, 4, 5].include?(value[:V])
74
- yield("Value of /V is not one of 1, 2, 4 or 5", false)
75
- return
76
- end
77
- if value[:V] == 2 && (!key?(:Length) || value[:Length] < 40 ||
78
- value[:Length] > 128 || value[:Length] % 8 != 0)
73
+ length = self[:Length]
74
+ if self[:V] == 2 && (!key?(:Length) || length < 40 || length > 128 || length % 8 != 0)
79
75
  yield("Invalid value for /Length field when /V is 2", false)
80
76
  end
81
77
  end
@@ -94,8 +90,8 @@ module HexaPDF
94
90
  # * The method ::set_up_decryption is used when a security handler should be created from the
95
91
  # document's encryption dictionary.
96
92
  #
97
- # Security handlers could also be created with the ::new method but this is discouraged because
98
- # the above methods provide the correct handling in both cases.
93
+ # It is *not* recommended to create security handlers manually but only with those two methods
94
+ # listed above.
99
95
  #
100
96
  #
101
97
  # == Using SecurityHandler Instances
@@ -107,12 +103,16 @@ module HexaPDF
107
103
  # * #encrypt_string
108
104
  # * #encrypt_stream
109
105
  #
110
- # How the decryption/encryption key is actually computed is deferred to a sub class.
106
+ # How the decryption/encryption key is actually computed is deferred to a sub class, as per the
107
+ # PDF specification.
111
108
  #
112
109
  # Additionally, the #encryption_key_valid? method can be used to check whether the
113
110
  # SecurityHandler instance is built from/built for the current version of the encryption
114
111
  # dictionary.
115
112
  #
113
+ # Note that any manual changes to the encryption dictionary will invalidate the key and lead to
114
+ # an error!
115
+ #
116
116
  #
117
117
  # == Implementing a SecurityHandler Class
118
118
  #
@@ -151,8 +151,8 @@ module HexaPDF
151
151
  # The encryption algorithm.
152
152
  attr_reader :algorithm
153
153
 
154
- # Creates a new encrypted stream data object by utilizing the given stream data object as
155
- # template. The arguments +key+ and +algorithm+ are used for decrypting purposes.
154
+ # Creates a new encrypted stream data object by utilizing the given stream data object +obj+
155
+ # as template. The arguments +key+ and +algorithm+ are used for decrypting purposes.
156
156
  def initialize(obj, key, algorithm)
157
157
  obj.instance_variables.each {|v| instance_variable_set(v, obj.instance_variable_get(v)) }
158
158
  @key = key
@@ -214,7 +214,7 @@ module HexaPDF
214
214
 
215
215
  handler = handler.new(document)
216
216
  dict = document.trailer[:Encrypt] = handler.set_up_decryption(dict, **options)
217
- HexaPDF::Object.make_direct(dict.value)
217
+ HexaPDF::Object.make_direct(dict.value, document)
218
218
  document.revisions.current.update(dict)
219
219
  document.revisions.each do |r|
220
220
  loader = r.loader
@@ -264,7 +264,7 @@ module HexaPDF
264
264
  # Decrypts the strings and the possibly attached stream of the given indirect object in
265
265
  # place.
266
266
  #
267
- # See: PDF1.7 s7.6.2
267
+ # See: PDF2.0 s7.6.3
268
268
  def decrypt(obj)
269
269
  return obj if @is_encrypt_dict[obj] || obj.type == :XRef
270
270
 
@@ -292,7 +292,7 @@ module HexaPDF
292
292
  # Note that some strings won't be encrypted as per the specification. The returned string,
293
293
  # however, is always a different object.
294
294
  #
295
- # See: PDF1.7 s7.6.2
295
+ # See: PDF2.0 s7.6.3
296
296
  def encrypt_string(str, obj)
297
297
  return str.dup if str.empty? || obj == document.trailer[:Encrypt] || obj.type == :XRef ||
298
298
  (obj.type == :Sig && obj[:Contents].equal?(str))
@@ -302,6 +302,9 @@ module HexaPDF
302
302
  end
303
303
 
304
304
  # Returns a Fiber that encrypts the contents of the given stream object.
305
+ #
306
+ # Note that some streams *must not be* encrypted. For those, their standard stream encoding
307
+ # fiber is returned.
305
308
  def encrypt_stream(obj)
306
309
  return obj.stream_encoder if obj.type == :XRef
307
310
 
@@ -321,8 +324,8 @@ module HexaPDF
321
324
  end
322
325
  end
323
326
 
324
- # Computes the encryption key and sets up the algorithms for encrypting the document based on
325
- # the given options, and returns the corresponding encryption dictionary.
327
+ # Computes the encryption key, sets up the algorithms for encrypting the document based on the
328
+ # given options, and returns the corresponding encryption dictionary.
326
329
  #
327
330
  # The security handler specific +options+ as well as the +algorithm+ argument are passed on to
328
331
  # the #prepare_encryption method.
@@ -340,7 +343,7 @@ module HexaPDF
340
343
  # force_v4::
341
344
  # Forces the use of protocol version 4 when key_length=128 and algorithm=:arc4.
342
345
  #
343
- # See: PDF1.7 s7.6.1, PDF2.0 s7.6.1
346
+ # See: PDF2.0 s7.6.2
344
347
  def set_up_encryption(key_length: 128, algorithm: :aes, force_v4: false, **options)
345
348
  @dict = document.wrap({}, type: encryption_dictionary_class)
346
349
 
@@ -382,9 +385,13 @@ module HexaPDF
382
385
  #
383
386
  # The security handler specific +options+ are passed on to the #prepare_decryption method.
384
387
  #
385
- # See: PDF1.7 s7.6.1, PDF2.0 s7.6.1
388
+ # See: PDF2.0 s7.6.2
386
389
  def set_up_decryption(dictionary, **options)
387
390
  @dict = document.wrap(dictionary, type: encryption_dictionary_class)
391
+ @dict.validate do |msg, correctable, obj|
392
+ next if correctable
393
+ raise HexaPDF::Error, "Validation error for encryption dictionary (#{obj.oid},#{obj.gen}): #{msg}"
394
+ end
388
395
 
389
396
  case dict[:V]
390
397
  when 1, 2
@@ -495,7 +502,7 @@ module HexaPDF
495
502
 
496
503
  # Computes the key for decrypting the indirect object with the given algorithm.
497
504
  #
498
- # See: PDF1.7 s7.6.2 (algorithm 1), PDF2.0 s7.6.2.2 (algorithm 1.A)
505
+ # See: PDF2.0 s7.6.3.2 (algorithm 1), PDF2.0 s7.6.3.3 (algorithm 1.A)
499
506
  def object_key(oid, gen, algorithm)
500
507
  key = encryption_key
501
508
  return key if dict[:V] == 5
@@ -508,13 +515,13 @@ module HexaPDF
508
515
 
509
516
  # Returns the length of the encryption key in bytes based on the security handlers version.
510
517
  #
511
- # See: PDF1.7 s7.6.1, PDF2.0 s7.6.1
518
+ # See: PDF2.0 s7.6.2
512
519
  def key_length
513
520
  case dict[:V]
514
521
  when 1 then 5
515
522
  when 2 then dict[:Length] / 8
516
- when 4 then 16 # PDF2.0 s7.6.1 specifies that a /V of 4 is equal to length of 128bit
517
- when 5 then 32 # PDF2.0 s7.6.1 specifies that a /V of 5 is equal to length of 256bit
523
+ when 4 then 16 # PDF2.0 s7.6.2 specifies that a /V of 4 is equal to length of 128bit
524
+ when 5 then 32 # PDF2.0 s7.6.2 specifies that a /V of 5 is equal to length of 256bit
518
525
  end
519
526
  end
520
527
 
@@ -47,7 +47,7 @@ module HexaPDF
47
47
  # the encryption key and a set of permissions.
48
48
  class StandardEncryptionDictionary < EncryptionDictionary
49
49
 
50
- define_field :R, type: Integer, required: true
50
+ define_field :R, type: Integer, required: true, allowed_values: [2, 3, 4, 5, 6]
51
51
  define_field :O, type: PDFByteString, required: true
52
52
  define_field :OE, type: PDFByteString, version: '2.0'
53
53
  define_field :U, type: PDFByteString, required: true
@@ -71,12 +71,16 @@ module HexaPDF
71
71
  yield("Value of /OE, /UE or /Perms is missing for dictionary revision 6", false)
72
72
  return
73
73
  end
74
- if value[:U].length != 48 || value[:O].length != 48 || value[:UE].length != 32 ||
75
- value[:OE].length != 32 || value[:Perms].length != 16
76
- yield("Invalid size for /U, /O, /UE, /OE or /Perms values for revisions 6", false)
74
+ [:U, :O].each do |f|
75
+ if value[f].length != 48
76
+ yield("Invalid size (#{value[f].length} instead of 48) for /#{f} for revisions 6",
77
+ value[f].length > 48 && value[f][48..-1].squeeze("\x00").length == 1)
78
+ value[f].slice!(48..-1)
79
+ end
80
+ end
81
+ if value[:UE].length != 32 || value[:OE].length != 32 || value[:Perms].length != 16
82
+ yield("Invalid size for /UE, /OE or /Perms values for revisions 6", false)
77
83
  end
78
- else
79
- yield("Value of /R is not one of 2, 3, 4 or 6", false)
80
84
  end
81
85
  end
82
86
 
@@ -87,11 +91,13 @@ module HexaPDF
87
91
  #
88
92
  # == Overview
89
93
  #
90
- # The PDF specification defines one security handler that should be implemented by all PDF
91
- # conform libraries and applications. This standard security handler allows access permissions
92
- # and a user password as well as an owner password to be set. See
93
- # StandardSecurityHandler::EncryptionOptions for all valid options that can be used with this
94
- # security handler.
94
+ # The PDF specification defines one security handler that should be implemented by all
95
+ # conforming PDF libraries and applications. This standard security handler allows access
96
+ # permissions and a user password as well as an owner password to be set.
97
+ #
98
+ # See StandardSecurityHandler::EncryptionOptions for all valid options that can be used with
99
+ # this security handler when encrypting a document. And see #prepare_decryption for all allowed
100
+ # options when decrypting a document.
95
101
  #
96
102
  # The access permissions (see StandardSecurityHandler::Permissions) can be used to restrict what
97
103
  # a user is allowed to do with a PDF file.
@@ -100,7 +106,7 @@ module HexaPDF
100
106
  # password is supplied. To open such an encrypted PDF file, the +decryption_opts+ provided to
101
107
  # HexaPDF::Document.new needs to contain a :password key with the password.
102
108
  #
103
- # See: PDF1.7 s7.6.3, PDF2.0 s7.6.3
109
+ # See: PDF2.0 s7.6.4
104
110
  class StandardSecurityHandler < SecurityHandler
105
111
 
106
112
  # Defines all available permissions.
@@ -109,13 +115,13 @@ module HexaPDF
109
115
  # permission set. The used symbols are the lower case versions of the constants, i.e. the
110
116
  # symbol for MODIFY_CONSTANT would be :modify_constant.
111
117
  #
112
- # See: PDF1.7 s7.6.3.2
118
+ # See: PDF2.0 s7.6.4.2
113
119
  module Permissions
114
120
 
115
121
  # Printing (if HIGH_QUALITY_PRINT is also set, then high quality printing is allowed)
116
122
  PRINT = 1 << 2
117
123
 
118
- # Modification of the content by operations that are different from those controller by
124
+ # Modification of the content by operations that are different from those controlled by
119
125
  # MODIFY_ANNOTATION, FILL_IN_FORMS and ASSEMBLE_DOCUMENT
120
126
  MODIFY_CONTENT = 1 << 3
121
127
 
@@ -129,6 +135,9 @@ module HexaPDF
129
135
  FILL_IN_FORMS = 1 << 8
130
136
 
131
137
  # Extracting content
138
+ #
139
+ # PDF 2.0 specifies that this bit should always be set by writers and should be ignored by
140
+ # readers. Therefore this is part of the RESERVED constant.
132
141
  EXTRACT_CONTENT = 1 << 9
133
142
 
134
143
  # Assembling of the document (inserting, rotating or deleting of pages and creation of
@@ -142,8 +151,8 @@ module HexaPDF
142
151
  ALL = PRINT | MODIFY_CONTENT | COPY_CONTENT | MODIFY_ANNOTATION | FILL_IN_FORMS |
143
152
  EXTRACT_CONTENT | ASSEMBLE_DOCUMENT | HIGH_QUALITY_PRINT
144
153
 
145
- # Reserved permission bits
146
- RESERVED = 0xFFFFF000 | 0b11000000
154
+ # Reserved permission bits that should always be set
155
+ RESERVED = 0xFFFFF000 | 0b11000000 | EXTRACT_CONTENT
147
156
 
148
157
  # Maps permission symbols to their respective value
149
158
  SYMBOL_TO_PERMISSION = {
@@ -213,7 +222,7 @@ module HexaPDF
213
222
 
214
223
  # Maps the permissions to an integer for use by the standard security handler.
215
224
  #
216
- # See: PDF1.7 s7.6.3.2, ADB1.7 3.5.2 (table 3.20 and the paragraphs before)
225
+ # See: PDF2.0 s7.6.4.2, ADB1.7 3.5.2 (table 3.20 and the paragraphs before)
217
226
  def process_permissions(perms)
218
227
  if perms.kind_of?(Array)
219
228
  perms = perms.inject(0) do |result, perm|
@@ -363,7 +372,7 @@ module HexaPDF
363
372
 
364
373
  # The padding used for passwords with fewer than 32 bytes. Only used for revisions <= 4.
365
374
  #
366
- # See: PDF1.7 s7.6.3.3
375
+ # See: PDF2.0 s7.6.4.3
367
376
  PASSWORD_PADDING = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08" \
368
377
  "\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A".b
369
378
 
@@ -376,7 +385,7 @@ module HexaPDF
376
385
  # with the user password. If the password is the owner password,
377
386
  # #compute_owner_encryption_key has to be used instead.
378
387
  #
379
- # See: PDF1.7 s7.6.3.3 (algorithm 2), PDF2.0 s7.6.3.3.2 (algorithm 2.A (a)-(b),(e))
388
+ # See: PDF2.0 s7.6.4.3.2 (algorithm 2), PDF2.0 s7.6.4.3.3 (algorithm 2.A (a)-(b),(e))
380
389
  def compute_user_encryption_key(password)
381
390
  if dict[:R] <= 4
382
391
  data = password
@@ -403,11 +412,11 @@ module HexaPDF
403
412
  # For revisions <= 4 this is done by first retrieving the user password through the use of
404
413
  # the owner password and then using the #compute_user_encryption_key method.
405
414
  #
406
- # For revision 6 file encryption key is a string of random bytes that has been encrypted
407
- # with the owner password. If the password is the user password,
408
- # #compute_user_encryption_key has to be used.
415
+ # For revision 6 the file encryption key is a string of random bytes that has been encrypted
416
+ # with the owner password. If the password is the user password, #compute_user_encryption_key
417
+ # has to be used.
409
418
  #
410
- # See: PDF2.0 s7.6.3.3.2 (algorithm 2.A (a)-(d))
419
+ # See: PDF2.0 s7.6.4.3.2 (algorithm 2.A (a)-(d))
411
420
  def compute_owner_encryption_key(password)
412
421
  if dict[:R] <= 4
413
422
  compute_user_encryption_key(user_password_from_owner_password(password))
@@ -426,7 +435,7 @@ module HexaPDF
426
435
  # *Attention*: If revision 6 is used, the /U value has to be computed and set before this
427
436
  # method is used, otherwise the return value is incorrect!
428
437
  #
429
- # See: PDF1.7 s7.6.3.4 (algorithm 3), PDF2.0 s7.6.3.4.7 (algorithm 9 (a))
438
+ # See: PDF2.0 s7.6.4.4.2 (algorithm 3), PDF2.0 s7.6.4.4.8 (algorithm 9 (a))
430
439
  def compute_o_field(owner_password, user_password)
431
440
  if dict[:R] <= 4
432
441
  data = Digest::MD5.digest(owner_password)
@@ -454,7 +463,7 @@ module HexaPDF
454
463
  # Short explanation: Encrypts the file encryption key with a key based on the password and
455
464
  # the /O and /U values.
456
465
  #
457
- # See: PDF2.0 s7.6.3.4.7 (algorithm 9 (b))
466
+ # See: PDF2.0 s7.6.4.4.8 (algorithm 9 (b))
458
467
  def compute_oe_field(password, file_encryption_key)
459
468
  key = compute_hash(password, dict[:O][40, 8], dict[:U])
460
469
  aes_algorithm.new(key, "\0" * 16, :encrypt).process(file_encryption_key)
@@ -466,8 +475,8 @@ module HexaPDF
466
475
  # based on the user password. For revision 6 the /U value is a hash computed from the
467
476
  # password with added validation and key salts.
468
477
  #
469
- # See: PDF1.7 s7.6.3.4 (algorithm 4 for R=2, algorithm 5 for R=3 and R=4)
470
- # PDF2.0 s7.6.3.4.6 (algorithm 8 (a) for R=6)
478
+ # See: PDF2.0 s7.6.4.4.3 (algorithm 4 for R=2), PDF s7.6.4.4.4 (algorithm 5 for R=3 and R=4)
479
+ # PDF2.0 s7.6.4.4.7 (algorithm 8 (a) for R=6)
471
480
  def compute_u_field(password)
472
481
  if dict[:R] == 2
473
482
  key = compute_user_encryption_key(password)
@@ -491,7 +500,7 @@ module HexaPDF
491
500
  # Short explanation: Encrypts the file encryption key with a key based on the password and
492
501
  # the /U value.
493
502
  #
494
- # See: PDF2.0 s7.6.3.4.6 (algorithm 8 (b))
503
+ # See: PDF2.0 s7.6.4.4.7 (algorithm 8 (b))
495
504
  def compute_ue_field(password, file_encryption_key)
496
505
  key = compute_hash(password, dict[:U][40, 8])
497
506
  aes_algorithm.new(key, "\0" * 16, :encrypt).process(file_encryption_key)
@@ -501,7 +510,7 @@ module HexaPDF
501
510
  #
502
511
  # Uses /P and /EncryptMetadata values, so these have to be set beforehand.
503
512
  #
504
- # See: PDF2.0 s7.6.3.4.8 (algorithm 10)
513
+ # See: PDF2.0 s7.6.4.4.9 (algorithm 10)
505
514
  def compute_perms_field(file_encryption_key)
506
515
  data = [dict[:P]].pack('V')
507
516
  data << [0xFFFFFFFF].pack('V')
@@ -513,7 +522,7 @@ module HexaPDF
513
522
 
514
523
  # Authenticates the user password, i.e. decides whether the given user password is valid.
515
524
  #
516
- # See: PDF1.7 s7.6.3.4 (algorithm 6), PDF2.0 s7.6.3.4.9 (algorithm 11)
525
+ # See: PDF2.0 s7.6.4.4.5 (algorithm 6), PDF2.0 s7.6.4.4.10 (algorithm 11)
517
526
  def user_password_valid?(password)
518
527
  if dict[:R] == 2
519
528
  compute_u_field(password) == dict[:U]
@@ -526,7 +535,7 @@ module HexaPDF
526
535
 
527
536
  # Authenticates the owner password, i.e. decides whether the given owner password is valid.
528
537
  #
529
- # See: PDF1.7 s7.6.3.4 (algorithm 7), PDF2.0 s7.6.3.4.10 (algorithm 12)
538
+ # See: PDF2.0 s7.6.4.4.6 (algorithm 7), PDF2.0 s7.6.4.4.11 (algorithm 12)
530
539
  def owner_password_valid?(password)
531
540
  if dict[:R] <= 4
532
541
  user_password_valid?(user_password_from_owner_password(password))
@@ -539,7 +548,7 @@ module HexaPDF
539
548
  #
540
549
  # This method can only be used for revision 6.
541
550
  #
542
- # See: PDF2.0 s7.6.3.4.11 (algorithm 13)
551
+ # See: PDF2.0 s7.6.4.4.12 (algorithm 13)
543
552
  def check_perms_field(encryption_key)
544
553
  decrypted = aes_algorithm.new(encryption_key, "\0" * 16, :decrypt).process(dict[:Perms])
545
554
  if decrypted[9, 3] != "adb"
@@ -553,7 +562,7 @@ module HexaPDF
553
562
 
554
563
  # Returns the user password when given the owner password for revisions <= 4.
555
564
  #
556
- # See: PDF1.7 s7.6.3.4 (algorithm 7 (a) and (b))
565
+ # See: PDF2.0 s7.6.4.4.6 (algorithm 7 (a) and (b))
557
566
  def user_password_from_owner_password(owner_password)
558
567
  data = Digest::MD5.digest(owner_password)
559
568
  if dict[:R] >= 3
@@ -578,7 +587,7 @@ module HexaPDF
578
587
  # "#{password}#{salt}#{user_key}" where +user_key+ has to be empty when doing operations
579
588
  # with the user password.
580
589
  #
581
- # See: PDF2.0 s7.6.3.3.3 (algorithm 2.B)
590
+ # See: PDF2.0 s7.6.4.3.4 (algorithm 2.B)
582
591
  def compute_hash(password, salt, user_key = '')
583
592
  k = Digest::SHA256.digest("#{password}#{salt}#{user_key}")
584
593
  e = ''
@@ -606,8 +615,8 @@ module HexaPDF
606
615
  # * For revision 6 the password is converted into UTF-8 encoding that is normalized
607
616
  # according to the PDF2.0 specification.
608
617
  #
609
- # See: PDF1.7 s7.6.3.3 (algorithm 2 step a)),
610
- # PDF2.0 s7.6.3.3.2 (algorithm 2.A steps a) and b))
618
+ # See: PDF2.0 s7.6.4.3.2 (algorithm 2 step a)),
619
+ # PDF2.0 s7.6.4.3.3 (algorithm 2.A steps a) and b))
611
620
  def prepare_password(password)
612
621
  if dict[:R] <= 4
613
622
  password.to_s[0, 32].encode(Encoding::ISO_8859_1).force_encoding(Encoding::BINARY).
@@ -41,7 +41,7 @@ module HexaPDF
41
41
  # A PDF document may be encrypted so that
42
42
  #
43
43
  # * certain permissions are respected when the document is opened,
44
- # * a password must be specified so that a document can be openend or so that
44
+ # * a password must be specified so that a document can be openend, or so that
45
45
  # * a password must be specified to remove the restrictions and allow full access.
46
46
  #
47
47
  # This module contains all encryption and security related code to facilitate PDF encryption.
@@ -61,6 +61,9 @@ module HexaPDF
61
61
  # additionally allows setting permission information. This security handler is implemented by
62
62
  # the Encryption::StandardSecurityHandler class.
63
63
  #
64
+ # There is also a certificate-based security handler defined by the PDF specification. However,
65
+ # that handler is not implemented.
66
+ #
64
67
  #
65
68
  # === Encryption Algorithms
66
69
  #
@@ -78,8 +81,10 @@ module HexaPDF
78
81
  # Pure Ruby implementations of the algorithms which are naturally much slower than the OpenSSL
79
82
  # based ones. However, these implementation can be used on any Ruby implementation.
80
83
  #
84
+ # The ARC4 algorithm is deprecated with PDF 2.0 and should not be used when creating new
85
+ # documents.
81
86
  #
82
- # See: PDF1.7 s7.6
87
+ # See: PDF2.0 s7.6
83
88
  module Encryption
84
89
 
85
90
  autoload(:ARC4, 'hexapdf/encryption/arc4')
data/lib/hexapdf/error.rb CHANGED
@@ -82,4 +82,22 @@ module HexaPDF
82
82
  # Raised when the encryption method is not supported.
83
83
  class UnsupportedEncryptionError < EncryptionError; end
84
84
 
85
+ # Raised when a font wrapper implementation should encode a missing glyph.
86
+ class MissingGlyphError < Error
87
+
88
+ # Returns the glyph object that contains the information about the missing glyph.
89
+ attr_reader :glyph
90
+
91
+ # Creates a new MissingGlyphError for the given +glyph+.
92
+ def initialize(glyph)
93
+ @glyph = glyph
94
+ end
95
+
96
+ def message # :nodoc:
97
+ "No glyph for #{glyph.str.inspect} in font '#{glyph.font.full_name}' found. \n\n" \
98
+ "Use the configuration option 'font.on_missing_glyph' to customize missing glyph handling."
99
+ end
100
+
101
+ end
102
+
85
103
  end
@@ -45,7 +45,7 @@ module HexaPDF
45
45
  # This filter module implements the ASCII-85 filter which can encode arbitrary data into an
46
46
  # ASCII compatible format that expands the original data only by a factor of 4:5.
47
47
  #
48
- # See: HexaPDF::Filter, PDF1.7 s7.4.2
48
+ # See: HexaPDF::Filter, PDF2.0 s7.4.2
49
49
  module ASCII85Decode
50
50
 
51
51
  VALUE_TO_CHAR = {} #:nodoc:
@@ -44,7 +44,7 @@ module HexaPDF
44
44
  # This filter module implements the ASCII hex decode/encode filter which can encode arbitrary
45
45
  # data into the two byte ASCII hex format that expands the original data by a factor of 1:2.
46
46
  #
47
- # See: HexaPDF::Filter, PDF1.7 s7.4.2
47
+ # See: HexaPDF::Filter, PDF2.0 s7.4.2
48
48
  module ASCIIHexDecode
49
49
 
50
50
  # See HexaPDF::Filter
@@ -45,7 +45,7 @@ module HexaPDF
45
45
 
46
46
  # Implements the Deflate filter using the Zlib library.
47
47
  #
48
- # See: HexaPDF::Filter, PDF1.7 s7.4.4
48
+ # See: HexaPDF::Filter, PDF2.0 s7.4.4
49
49
  module FlateDecode
50
50
 
51
51
  # See HexaPDF::Filter
@@ -48,7 +48,7 @@ module HexaPDF
48
48
  # not aligned to byte boundaries, this filter is not as fast as the other filters. If speed is
49
49
  # a concern, the FlateDecode filter should be used instead.
50
50
  #
51
- # See: HexaPDF::Filter, PDF1.7 s7.4.4
51
+ # See: HexaPDF::Filter, PDF2.0 s7.4.4
52
52
  module LZWDecode
53
53
 
54
54
  CLEAR_TABLE = 256 # :nodoc:
@@ -40,7 +40,7 @@ module HexaPDF
40
40
  # The PassThrough filter just passes the source on unmodified. This is enough for basic
41
41
  # read-write capabilities but not if the unfiltered bytes are needed.
42
42
  #
43
- # See: HexaPDF::Filter, PDF1.7 s7.4
43
+ # See: HexaPDF::Filter, PDF2.0 s7.4
44
44
  module PassThrough
45
45
 
46
46
  # See HexaPDF::Filter
@@ -47,7 +47,7 @@ module HexaPDF
47
47
  # Although a predictor isn't a full PDF filter, it is implemented as one in HexaPDF terms to
48
48
  # allow easy chaining of the predictor.
49
49
  #
50
- # See: PDF1.7 s7.4.4.3, s7.4.4.4, https://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
50
+ # See: PDF2.0 s7.4.4.3, s7.4.4.4, https://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
51
51
  # (p64f), http://www.w3.org/TR/PNG-Filters.html
52
52
  #
53
53
  #-- Implemenation notes:
@@ -43,7 +43,7 @@ module HexaPDF
43
43
 
44
44
  # Implements the run length filter.
45
45
  #
46
- # See: HexaPDF::Filter, PDF1.7 s7.4.5
46
+ # See: HexaPDF::Filter, PDF2.0 s7.4.5
47
47
  module RunLengthDecode
48
48
 
49
49
  EOD = 128.chr #:nodoc:
@@ -48,6 +48,8 @@ module HexaPDF
48
48
  attr_reader :length
49
49
 
50
50
  # Initializes the Fiber and sets the +length+.
51
+ #
52
+ # A +length+ of +nil+ is equal to -1.
51
53
  def initialize(length, &block)
52
54
  super(&block)
53
55
  @length = length || -1
@@ -55,6 +57,47 @@ module HexaPDF
55
57
 
56
58
  end
57
59
 
60
+ # Implements part of the Fiber interface so that it can be used instead of a Fiber by HexaPDF
61
+ # when only a single string should be returned.
62
+ class FiberDoubleForString
63
+
64
+ # Creates a new FiberDoubleForString instance for the given string +str+ or for the string
65
+ # returned by invoking the block.
66
+ def initialize(str = nil, &block)
67
+ @block = block
68
+ @str = str
69
+ @block_used = false
70
+ end
71
+
72
+ # Returns the length of the wrapped string.
73
+ #
74
+ # May only be called before #resume!
75
+ def length
76
+ str.length
77
+ end
78
+
79
+ # Returns +true+ if #resume has not yet been called.
80
+ def alive?
81
+ !str.nil?
82
+ end
83
+
84
+ # Returns the wrapped string on the first invocation, +nil+ otherwise.
85
+ def resume
86
+ tmp = str
87
+ @str = nil
88
+ tmp
89
+ end
90
+
91
+ private
92
+
93
+ # Sets the string to the return value of the initially provided block if no string has been
94
+ # provided.
95
+ def str
96
+ @str ||= @block_used || @block.nil? ? nil : (@block_used = true; @block.call)
97
+ end
98
+
99
+ end
100
+
58
101
  # == Overview
59
102
  #
60
103
  # A stream filter is used to compress a stream or to encode it in an ASCII compatible way; or
@@ -83,7 +126,7 @@ module HexaPDF
83
126
  #
84
127
  # Such a fiber should *not* return +nil+ unless this signifies that no more data is coming!
85
128
  #
86
- # See: PDF1.7 s7.4
129
+ # See: PDF2.0 s7.4
87
130
  module Filter
88
131
 
89
132
  autoload(:ASCII85Decode, 'hexapdf/filter/ascii85_decode')
@@ -99,10 +142,16 @@ module HexaPDF
99
142
 
100
143
  autoload(:PassThrough, 'hexapdf/filter/pass_through')
101
144
 
102
- # Returns a Fiber that can be used as a source for decoders/encoders and that is based on a
103
- # String object.
145
+ # Returns a FiberDoubleForString that uses the string returned by the provided block and can be
146
+ # used as a source for decoders/encoders.
147
+ def self.source_from_proc(&block)
148
+ FiberDoubleForString.new(&block)
149
+ end
150
+
151
+ # Returns a FiberDoubleForString that returns the given string and can be used as a source for
152
+ # decoders/encoders.
104
153
  def self.source_from_string(str)
105
- FiberWithLength.new(str.length) { str.dup }
154
+ FiberDoubleForString.new(str.dup)
106
155
  end
107
156
 
108
157
  # Returns a Fiber that can be used as a source for decoders/encoders and that reads chunks of
@@ -149,7 +198,7 @@ module HexaPDF
149
198
  # Note that there will be a problem if the size of the file changes between the invocation of
150
199
  # this method and the actual consumption of the file!
151
200
  #
152
- # See ::source_from_io for a description of the available options.
201
+ # See ::source_from_io for a description of the +pos+, +length+ and +chunk_size+ options.
153
202
  def self.source_from_file(filename, pos: 0, length: -1, chunk_size: 0)
154
203
  fib_length = (length < 0 ? File.stat(filename).size - pos : length)
155
204
  FiberWithLength.new(fib_length) do
@@ -165,7 +214,7 @@ module HexaPDF
165
214
  # Returns the concatenated string chunks retrieved by resuming the given source Fiber until it
166
215
  # is dead.
167
216
  #
168
- # The returned string is always a string with +BINARY+ (= +ASCII-8BIT+) encoding.
217
+ # The returned string is always a string with binary (= +ASCII-8BIT+) encoding.
169
218
  def self.string_from_source(source)
170
219
  str = ''.b
171
220
  while source.alive? && (data = source.resume)
@@ -146,10 +146,10 @@ module HexaPDF
146
146
  # Parses the "bfrange" operator at the current position.
147
147
  #
148
148
  #--
149
- # PDF1.7 s9.10.3 and Adobe Technical Note #5411 have different views as to how "bfrange"
149
+ # PDF2.0 s9.10.3 and Adobe Technical Note #5411 have different views as to how "bfrange"
150
150
  # operators of the form "startCode endCode codePoint" should be handled.
151
151
  #
152
- # PDF1.7 mentions that the last byte of "codePoint" should be incremented, up to a maximum
152
+ # PDF2.0 mentions that the last byte of "codePoint" should be incremented, up to a maximum
153
153
  # of 255. However #5411 has the range "<1379> <137B> <90FE>" as example which contradicts
154
154
  # this.
155
155
  #
@@ -43,7 +43,7 @@ module HexaPDF
43
43
  # Represents a CMap, a mapping from character codes to CIDs (character IDs) or to their Unicode
44
44
  # value.
45
45
  #
46
- # See: PDF1.7 s9.7.5, s9.10.3; Adobe Technical Notes #5014 and #5411
46
+ # See: PDF2.0 s9.7.5, s9.10.3; Adobe Technical Notes #5014 and #5411
47
47
  class CMap
48
48
 
49
49
  autoload(:Parser, 'hexapdf/font/cmap/parser')
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # The difference encoding uses a base encoding that can be overlayed with additional mappings.
44
44
  #
45
- # See: PDF1.7 s9.6.6.1
45
+ # See: PDF2.0 s9.6.5.1
46
46
  class DifferenceEncoding < Base
47
47
 
48
48
  # The base encoding.