hexapdf 0.32.2 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
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.