hexapdf 0.45.0 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -47
  3. data/examples/019-acro_form.rb +5 -0
  4. data/lib/hexapdf/cli/inspect.rb +5 -0
  5. data/lib/hexapdf/composer.rb +1 -1
  6. data/lib/hexapdf/configuration.rb +8 -0
  7. data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
  8. data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
  9. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
  10. data/lib/hexapdf/document/layout.rb +48 -27
  11. data/lib/hexapdf/document.rb +24 -2
  12. data/lib/hexapdf/importer.rb +15 -5
  13. data/lib/hexapdf/layout/box.rb +25 -28
  14. data/lib/hexapdf/layout/frame.rb +1 -1
  15. data/lib/hexapdf/layout/inline_box.rb +17 -23
  16. data/lib/hexapdf/layout/list_box.rb +24 -29
  17. data/lib/hexapdf/layout/page_style.rb +23 -16
  18. data/lib/hexapdf/layout/style.rb +2 -2
  19. data/lib/hexapdf/layout/text_box.rb +2 -6
  20. data/lib/hexapdf/parser.rb +5 -1
  21. data/lib/hexapdf/revisions.rb +1 -1
  22. data/lib/hexapdf/stream.rb +3 -3
  23. data/lib/hexapdf/tokenizer.rb +3 -2
  24. data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
  25. data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
  26. data/lib/hexapdf/type/acro_form/field.rb +8 -0
  27. data/lib/hexapdf/type/acro_form/form.rb +2 -1
  28. data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
  29. data/lib/hexapdf/version.rb +1 -1
  30. data/test/hexapdf/digital_signature/common.rb +66 -84
  31. data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
  32. data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
  33. data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
  34. data/test/hexapdf/digital_signature/test_handler.rb +2 -1
  35. data/test/hexapdf/document/test_layout.rb +28 -5
  36. data/test/hexapdf/layout/test_box.rb +12 -5
  37. data/test/hexapdf/layout/test_frame.rb +12 -2
  38. data/test/hexapdf/layout/test_inline_box.rb +17 -28
  39. data/test/hexapdf/layout/test_list_box.rb +5 -5
  40. data/test/hexapdf/layout/test_page_style.rb +7 -2
  41. data/test/hexapdf/layout/test_text_box.rb +3 -9
  42. data/test/hexapdf/layout/test_text_layouter.rb +0 -3
  43. data/test/hexapdf/test_document.rb +27 -0
  44. data/test/hexapdf/test_importer.rb +17 -0
  45. data/test/hexapdf/test_revisions.rb +54 -41
  46. data/test/hexapdf/type/acro_form/test_form.rb +9 -0
  47. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd31e769d2a906198da2a4194085cb2a884fa3879442b75add168d7f81d67d8b
4
- data.tar.gz: 43c2b4ba4df2f997d470835995f2581aa306c639c63ddc892e648d94605f3b22
3
+ metadata.gz: f9c1a35d4ad93b48faa1f728bcddc91778da584c8d673e2f15557bd22050a438
4
+ data.tar.gz: 2ef8ca70891723643080a402f0808882f66f01a816c422477cc03fad34774859
5
5
  SHA512:
6
- metadata.gz: f17a303dba8104974564a213c72c0f0862c520964a3255b575544489ccb5a17a468d093d3970817903c4eb798e888592410db18447d3264d535f3a01a4a94c82
7
- data.tar.gz: d5727e2f2bfb5ed827ac92eecc8cd9e0ba73044150ba07d03623dccde43dc29db1cddc2fbce24bfd63268522e7965519e188271c2bc9c00162b1a660fc468b74
6
+ metadata.gz: 87c109bd8a6711b4df27a40c689a025d816075d6c68c21a1cc22924b5ae827cd44d98e45bff8f43c85403dd82d6a6e54b66c99bfe135298cba33292e9511a1fc
7
+ data.tar.gz: e0529e3e244be8366e722ea29ab06a8b922f18698526c79a28d5d11f02da5ee103cba71ecbc6882fefe3de27f02d38f8ce8b505fefbb45839069c74aefaed9ae
data/CHANGELOG.md CHANGED
@@ -1,3 +1,43 @@
1
+ ## 0.46.0 - 2024-08-11
2
+
3
+ ### Added
4
+
5
+ * [HexaPDF::DigitalSignature::CMSHandler#embedded_tsa_signature] to return the
6
+ embedded timestamp authority signature if any
7
+ * [HexaPDF::DigitalSignature::Signing::DefaultHandler#signing_time] for setting
8
+ a custom signing time
9
+ * [HexaPDF::Document#duplicate] for making an in-memory copy of a PDF document
10
+ * Configuration option 'font.default' for setting the default font for the
11
+ document layout engine
12
+
13
+ ### Changed
14
+
15
+ * [HexaPDF::Document::Layout::CellArgumentCollector#[]=] to allow stepped ranges
16
+ * [HexaPDF::Document::Layout::ChildrenCollector] to also return the box when
17
+ creating and adding one to the list
18
+ * [HexaPDF::Layout::InlineBox] to allow usage without predefined width
19
+ * [HexaPDF::DigitalSignature::CMSHandler#verify] to recognize non-repudiation
20
+ signatures
21
+ * [HexaPDF::DigitalSignature::CMSHandler#signing_time] to use time from an
22
+ embedded timestamp authority signature if possible
23
+ * [HexaPDF::Layout::Box#fit] to return success for boxes with content
24
+ width/height of zero
25
+ * [HexaPDF::Importer::copy] to optionally allow copying the catalog and page
26
+ tree nodes
27
+
28
+ ### Fixed
29
+
30
+ * Setting of correct x-position in fit result for boxes with flow positioning
31
+ * [HexaPDF::Layout::ListBox#fit] to respect the set height
32
+ * CLI command `hexapdf inspect` to work in case of missing Unicde mappings
33
+ * [HexaPDF::Type::AcroForm::Form#delete_field] to correctly work for fields with
34
+ an embedded widget
35
+ * Parsing of "linearized" PDF files where the first cross-reference section
36
+ isn't actually used
37
+ * [HexaPDF::Layout::PageStyle#create_page] to return new frame objects on each
38
+ invocation
39
+
40
+
1
41
  ## 0.45.0 - 2024-06-18
2
42
 
3
43
  ### Added
@@ -375,8 +415,8 @@
375
415
 
376
416
  ### Fixed
377
417
 
378
- * [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for
379
- the default range starting at page 1
418
+ * [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for the
419
+ default range starting at page 1
380
420
  * [HexaPDF::Type::Page#flatten_annotations] to correctly handle scaled
381
421
  appearances
382
422
  * Using an unknown style name in [HexaPDF:Document::Layout] method by providing
@@ -387,6 +427,8 @@
387
427
  than the item content height
388
428
  * [HexaPDF::Dictionary] setting default values on wrong classes in certain
389
429
  situations
430
+ * [HexaPDF::Importer#import] to correctly import stream objects backed by a
431
+ [HexaPDF::FiberDoubleForString]
390
432
 
391
433
 
392
434
  ## 0.33.0 - 2023-08-02
@@ -439,8 +481,8 @@
439
481
  * [HexaPDF::Content::Canvas#text] to set the leading only when multiple lines
440
482
  are drawn
441
483
  * [HexaPDF::Layout::TextBox#split] to use float comparison
442
- * Validation of standard encryption dictionary to auto-correct invalid /U and
443
- /O fields in case they are padded with zeros
484
+ * Validation of standard encryption dictionary to auto-correct invalid /U and /O
485
+ fields in case they are padded with zeros
444
486
  * [HexaPDF::Document#wrap] handling of sub-type mapping in case of missing type
445
487
  * [HexaPDF::Type::AcroForm::AppearanceGenerator] to also take a text field
446
488
  widget's width into account when auto-sizing
@@ -761,8 +803,8 @@
761
803
  * Support for the document outline
762
804
  * [HexaPDF::Layout::Style#line_height] for setting a custom line height
763
805
  independent of the font size
764
- * [HexaPDF::Document::Destinations#use_or_create] as unified interface for
765
- using or creating destinations
806
+ * [HexaPDF::Document::Destinations#use_or_create] as unified interface for using
807
+ or creating destinations
766
808
  * [HexaPDF::Document::Destinations::Destination#valid?] and class method for
767
809
  checking whether a destination array is valid
768
810
 
@@ -771,8 +813,8 @@
771
813
  * Calculation of text related [HexaPDF::Layout::Style] values for Type3 fonts
772
814
  * [HexaPDF::Encryption::SecurityHandler#encrypt_string] to either return a
773
815
  dupped or encrypted string
774
- * [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering
775
- a non-zero width breakpoint penalty
816
+ * [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering a
817
+ non-zero width breakpoint penalty
776
818
  * [HexaPDF::Type::ObjectStream] to parse the initial stream data right after
777
819
  initialization to avoid access errors
778
820
  * [HexaPDF::Revisions::from_io] to merge a completely empty revision with just a
@@ -854,8 +896,7 @@
854
896
  fragment if there would not be enough height left anyway
855
897
  * [HexaPDF::Layout::WidthFromPolygon] to work correctly in case of very small
856
898
  floating point errors
857
- * HexaPDF::Layout::TextFragment#inspect to work in case of interspersed
858
- numbers
899
+ * HexaPDF::Layout::TextFragment#inspect to work in case of interspersed numbers
859
900
  * [HexaPDF::Layout::TextBox#split] to work for position :flow when box is wider
860
901
  than the initial available width
861
902
  * [HexaPDF::Layout::Frame#fit] to create minimally sized mask rectangles
@@ -1137,8 +1178,8 @@
1137
1178
  dictionary are indirect objects
1138
1179
  * [HexaPDF::Content::GraphicObject::EndpointArc] to correctly determine the
1139
1180
  start and end points
1140
- * HexaPDF::Dictionary#perform_validation to correctly handle objects that
1141
- should not be indirect objects
1181
+ * HexaPDF::Dictionary#perform_validation to correctly handle objects that should
1182
+ not be indirect objects
1142
1183
 
1143
1184
 
1144
1185
  ## 0.17.3 - 2021-10-31
@@ -1260,8 +1301,8 @@
1260
1301
 
1261
1302
  ### Fixed
1262
1303
 
1263
- * [HexaPDF::Type::Annotation#appearance] to handle cases where there is
1264
- no valid appearance stream
1304
+ * [HexaPDF::Type::Annotation#appearance] to handle cases where there is no valid
1305
+ appearance stream
1265
1306
 
1266
1307
 
1267
1308
  ## 0.15.3 - 2021-05-01
@@ -1316,8 +1357,8 @@
1316
1357
  empty background color arrays
1317
1358
  * [HexaPDF::Type::AcroForm::Field#delete_widget] to update the wrapper object
1318
1359
  stored in the document in case the widget is embedded
1319
- * Processing of invalid PDF files containing a space,CR,LF combination after
1320
- the 'stream' keyword
1360
+ * Processing of invalid PDF files containing a space,CR,LF combination after the
1361
+ 'stream' keyword
1321
1362
  * Cross-reference stream reconstruction with respect to detection of linearized
1322
1363
  files
1323
1364
  * Detection of existing appearances for AcroForm push button fields when
@@ -1412,8 +1453,8 @@
1412
1453
 
1413
1454
  * [HexaPDF::Utils::ObjectHash#oids] to be public instead of private
1414
1455
  * Cross-reference table parsing to handle invalidly numbered main sections
1415
- * [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating
1416
- values for existing keys
1456
+ * [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating values
1457
+ for existing keys
1417
1458
  * Appearance creation methods of AcroForm objects to allow forcing the creation
1418
1459
  of new appearances
1419
1460
  * [HexaPDF::Type::AcroForm::AppearanceGenerator#create_text_appearances] to
@@ -1451,8 +1492,8 @@
1451
1492
  new 'parser.try_xref_reconstruction' option
1452
1493
  * Two new `hexapdf inspect` commands for showing page objects and page content
1453
1494
  streams by page number
1454
- * Flag `--check` to the CLI command `hexapdf info` for checking a file for
1455
- parse and validation errors
1495
+ * Flag `--check` to the CLI command `hexapdf info` for checking a file for parse
1496
+ and validation errors
1456
1497
  * [HexaPDF::Type::AcroForm::Field#embedded_widget?] for checking if a widget is
1457
1498
  embedded in the field object
1458
1499
  * [HexaPDF::Type::AcroForm::Field#delete_widget] for deleting a widget
@@ -1509,8 +1550,8 @@
1509
1550
 
1510
1551
  ### Added
1511
1552
 
1512
- * [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given
1513
- glyph name
1553
+ * [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given glyph
1554
+ name
1514
1555
 
1515
1556
  ### Fixed
1516
1557
 
@@ -1526,11 +1567,11 @@
1526
1567
  [HexaPDF::Type::AcroForm::Field]
1527
1568
  * [HexaPDF::Type::AcroForm::TextField] and
1528
1569
  [HexaPDF::Type::AcroForm::VariableTextField] for basic text field support
1529
- * [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and
1530
- check box support
1570
+ * [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and check
1571
+ box support
1531
1572
  * [HexaPDF::Type::AcroForm::ChoiceField] for combo box and list box support
1532
- * [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for
1533
- generating appearance streams for form fields
1573
+ * [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for generating
1574
+ appearance streams for form fields
1534
1575
  * Various convenience methods for [HexaPDF::Type::AcroForm::Form]
1535
1576
  * Various convenience methods for [HexaPDF::Type::AcroForm::Field]
1536
1577
  * Various convenience methods for [HexaPDF::Type::Annotations::Widget]
@@ -1549,8 +1590,8 @@
1549
1590
  * [HexaPDF::Type::Annotation::Border] class
1550
1591
  * [HexaPDF::Content::ColorSpace::device_color_from_specification] for easily
1551
1592
  getting a device color object
1552
- * [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a device
1553
- color object without normalizing values
1593
+ * [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
1594
+ device color object without normalizing values
1554
1595
  * [HexaPDF::Type::Annotation#appearance] for returning the associated appearance
1555
1596
  dictionary
1556
1597
  * [HexaPDF::Type::Annotation#appearance?] for checking whether an appearance for
@@ -1669,8 +1710,8 @@
1669
1710
 
1670
1711
  ### Fixed
1671
1712
 
1672
- * Conversion of [HexaPDF::Rectangle] type when the original is not a plain
1673
- Array but a [HexaPDF::PDFArray]
1713
+ * Conversion of [HexaPDF::Rectangle] type when the original is not a plain Array
1714
+ but a [HexaPDF::PDFArray]
1674
1715
 
1675
1716
 
1676
1717
  ## 0.11.1 - 2019-11-19
@@ -1831,12 +1872,12 @@
1831
1872
 
1832
1873
  ### Added
1833
1874
 
1834
- * [HexaPDF::Layout::Frame] for box positioning and easier text layouting
1835
- inside an arbitrary polygon
1875
+ * [HexaPDF::Layout::Frame] for box positioning and easier text layouting inside
1876
+ an arbitrary polygon
1836
1877
  * [HexaPDF::Layout::TextBox] for displaying text in a rectangular and for
1837
1878
  flowing text inside a frame
1838
- * [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from
1839
- a polygon for use with the text layouting engine
1879
+ * [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from a
1880
+ polygon for use with the text layouting engine
1840
1881
  * [HexaPDF::Type::Image#width] and [HexaPDF::Type::Image#height] convenience
1841
1882
  methods
1842
1883
  * [HexaPDF::Type::FontType3] for Type 3 font support
@@ -1888,12 +1929,12 @@
1888
1929
  character in a text fragment is \r
1889
1930
  * [HexaPDF::Layout::TextLayouter] to work if an optional break point (think
1890
1931
  soft-hyphen) is followed by whitespace
1891
- * [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the
1892
- table directory
1932
+ * [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the table
1933
+ directory
1893
1934
  * [HexaPDF::Font::TrueType::Builder] to pad the table data to achieve the
1894
1935
  correct alignment
1895
- * [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were
1896
- not thread safe
1936
+ * [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were not
1937
+ thread safe
1897
1938
  * All color space classes to accept the color space definition as argument to
1898
1939
  `::new`
1899
1940
 
@@ -1925,9 +1966,8 @@
1925
1966
  * Cross-reference subsection parsing can handle missing whitespace
1926
1967
  * Renamed HexaPDF::Layout::LineFragment to [HexaPDF::Layout::Line]
1927
1968
  * Renamed HexaPDF::Layout::TextBox to [HexaPDF::Layout::TextLayouter]
1928
- * [HexaPDF::Layout::TextFragment::new] and
1929
- [HexaPDF::Layout::TextLayouter::new] to either take a Style object or
1930
- style options
1969
+ * [HexaPDF::Layout::TextFragment::new] and [HexaPDF::Layout::TextLayouter::new]
1970
+ to either take a Style object or style options
1931
1971
  * [HexaPDF::Layout::TextLayouter#fit] method signature
1932
1972
  * [HexaPDF::Layout::InlineBox] to wrap a generic box
1933
1973
  * HexaPDF::Document::Fonts#load to [HexaPDF::Document::Fonts#add] for
@@ -1989,8 +2029,8 @@
1989
2029
 
1990
2030
  * Handling of invalid glyphs is done using the special
1991
2031
  [HexaPDF::Font::InvalidGlyph] class
1992
- * Configuration option 'font.on_missing_glyph'; returns an invalid glyph
1993
- instead of raising an error
2032
+ * Configuration option 'font.on_missing_glyph'; returns an invalid glyph instead
2033
+ of raising an error
1994
2034
  * Bounding box of TrueType glyphs without contours is set to `[0, 0, 0, 0]`
1995
2035
  * Ligature pairs for AFM fonts are stored like kerning pairs
1996
2036
  * Use TrueType configuration option 'font.true_type.unknown_format' in all
@@ -2007,8 +2047,8 @@
2007
2047
 
2008
2048
  * [HexaPDF::Task::Dereference] to work correctly when encountering invalid
2009
2049
  references
2010
- * [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary
2011
- plus sign
2050
+ * [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary plus
2051
+ sign
2012
2052
  * Usage of Strings instead of Symbols for AFM font kerning and ligature pairs
2013
2053
  * Processing the contents of form XObjects in case they don't have a resources
2014
2054
  dictionary
@@ -2031,8 +2071,8 @@
2031
2071
  * CLI option `--verbose` for more verbose output; also changed the default
2032
2072
  verbosity level to only display warnings and not informational messages
2033
2073
  * CLI option `--quiet` for suppressing additional and diagnostic output
2034
- * CLI option `--strict` for enabling strict parsing and validation; also
2035
- changed the default from strict to non-strict parsing/validation
2074
+ * CLI option `--strict` for enabling strict parsing and validation; also changed
2075
+ the default from strict to non-strict parsing/validation
2036
2076
  * CLI optimization option `--optimize-fonts` for optimizing embedded fonts
2037
2077
  * Method `#word_spacing_applicable?` to font types
2038
2078
  * Support for marked-content points and sequences in [HexaPDF::Content::Canvas]
@@ -6,6 +6,11 @@
6
6
  # This example show-cases how to create the various form field types and their
7
7
  # possible standard appearances.
8
8
  #
9
+ # The [HexaPDF::Type::AcroForm::Form] and [HexaPDF::Type::AcroForm::Field]
10
+ # classes provide a plethora of convenience methods for working with forms, like
11
+ # for creating fields and their widgets, getting field properties like the full
12
+ # hierarchical field name or for setting the field value.
13
+ #
9
14
  # Usage:
10
15
  # : `ruby acro_form.rb`
11
16
  #
@@ -117,6 +117,11 @@ module HexaPDF
117
117
 
118
118
  def execute(file, *commands) #:nodoc:
119
119
  with_document(file, password: @password) do |doc|
120
+ doc.config['font.on_missing_unicode_mapping'] = lambda do |code, font|
121
+ $stderr.puts("No Unicode mapping for code point #{code} in font #{font[:BaseFont]}, " \
122
+ "using the Unicode replacement character")
123
+ "\u{FFFD}"
124
+ end
120
125
  @doc = doc
121
126
  if commands.empty?
122
127
  begin
@@ -450,7 +450,7 @@ module HexaPDF
450
450
  (box = draw_box; break) unless box
451
451
  elsif !@frame.find_next_region
452
452
  unless drawn_on_page
453
- raise HexaPDF::Error, "Box doesn't fit on empty page"
453
+ raise HexaPDF::Error, "Box didn't fit multiple times, even on empty page"
454
454
  end
455
455
  new_page
456
456
  drawn_on_page = false
@@ -277,6 +277,13 @@ module HexaPDF
277
277
  #
278
278
  # See PDF2.0 s7.4.1, ADB sH.3 3.3
279
279
  #
280
+ # font.default::
281
+ # This font is used by the layout engine when no font is specified but one is needed.
282
+ #
283
+ # This is used, for example, for the font set on styles that don't have a font set.
284
+ #
285
+ # The default value is 'Times'.
286
+ #
280
287
  # font.fallback::
281
288
  # An array of fallback font names to be used when replacing invalid glyphs.
282
289
  #
@@ -518,6 +525,7 @@ module HexaPDF
518
525
  Crypt: 'HexaPDF::Filter::Crypt',
519
526
  Encryption: 'HexaPDF::Filter::Encryption',
520
527
  },
528
+ 'font.default' => 'Times',
521
529
  'font.fallback' => ['ZapfDingbats', 'Symbol'],
522
530
  'font.map' => {},
523
531
  'font.on_invalid_glyph' => method(:font_on_invalid_glyph),
@@ -59,7 +59,11 @@ module HexaPDF
59
59
 
60
60
  # Returns the time of signing.
61
61
  def signing_time
62
- signer_info.signed_time rescue super
62
+ if embedded_tsa_signature
63
+ embedded_tsa_signature.signers.first.signed_time
64
+ else
65
+ signer_info.signed_time rescue super
66
+ end
63
67
  end
64
68
 
65
69
  # Returns the certificate chain.
@@ -78,6 +82,23 @@ module HexaPDF
78
82
  @pkcs7.signers.first
79
83
  end
80
84
 
85
+ # Returns the OpenSSL::PKCS7 object for the embedded TSA signature if there is one or +nil+
86
+ # otherwise.
87
+ def embedded_tsa_signature
88
+ return @embedded_tsa_signature if defined?(@embedded_tsa_signature)
89
+
90
+ @embedded_tsa_signature = nil
91
+ p7 = OpenSSL::ASN1.decode(signature_dict.contents.sub(/\x00*\z/, ''))
92
+ signed_data = p7.value[1].value[0]
93
+ signer_info = signed_data.value[-1].value[0] # first (and only) signer info
94
+ return unless signer_info.value[-1].tag == 1 # check for unsigned attributes
95
+ timestamp_token = signer_info.value[-1].value.find do |unsigned_attr|
96
+ unsigned_attr.value[0].value == "id-smime-aa-timeStampToken"
97
+ end
98
+ return unless timestamp_token
99
+ @embedded_tsa_signature = OpenSSL::PKCS7.new(timestamp_token.value[1].value[0])
100
+ end
101
+
81
102
  # Verifies the signature using the provided OpenSSL::X509::Store object.
82
103
  def verify(store, allow_self_signed: false)
83
104
  result = super
@@ -101,9 +122,16 @@ module HexaPDF
101
122
  return result
102
123
  end
103
124
 
125
+ if embedded_tsa_signature
126
+ result.log(:info, 'Signing time comes from timestamp authority')
127
+ end
128
+
104
129
  key_usage = signer_certificate.extensions.find {|ext| ext.oid == 'keyUsage' }
105
- unless key_usage && key_usage.value.split(', ').include?("Digital Signature")
106
- result.log(:error, "Certificate key usage is missing 'Digital Signature'")
130
+ key_usage = key_usage&.value&.split(', ')
131
+ if key_usage&.include?("Non Repudiation") && !key_usage.include?("Digital Signature")
132
+ result.log(:info, 'Certificate used for non-repudiation')
133
+ elsif !key_usage || !key_usage.include?("Digital Signature")
134
+ result.log(:error, "Certificate key usage is missing 'Digital Signature' or 'Non Repudiation'")
107
135
  end
108
136
 
109
137
  if signature_dict.signature_type == 'ETSI.RFC3161'
@@ -211,6 +211,13 @@ module HexaPDF
211
211
  # The contact information. If used, will be set on the signature dictionary.
212
212
  attr_accessor :contact_info
213
213
 
214
+ # The custom signing time.
215
+ #
216
+ # The signing time is usually the time when signing actually happens. This is also what
217
+ # HexaPDF uses. If it is known that signing happened at a different point in time, that time
218
+ # can be provided using this accessor.
219
+ attr_accessor :signing_time
220
+
214
221
  # The size of the serialized signature that should be reserved.
215
222
  #
216
223
  # If this attribute is not set, an empty string will be signed using #sign to determine the
@@ -277,7 +284,7 @@ module HexaPDF
277
284
  def finalize_objects(_signature_field, signature)
278
285
  signature[:Filter] = :'Adobe.PPKLite'
279
286
  signature[:SubFilter] = (signature_type == :pades ? :'ETSI.CAdES.detached' : :'adbe.pkcs7.detached')
280
- signature[:M] = Time.now
287
+ signature[:M] = self.signing_time ||= Time.now
281
288
  signature[:Reason] = reason if reason
282
289
  signature[:Location] = location if location
283
290
  signature[:ContactInfo] = contact_info if contact_info
@@ -312,6 +319,7 @@ module HexaPDF
312
319
  type: signature_type,
313
320
  certificate: certificate, key: key,
314
321
  digest_algorithm: digest_algorithm,
322
+ signing_time: signing_time,
315
323
  timestamp_handler: timestamp_handler,
316
324
  certificates: certificate_chain, &external_signing).to_der
317
325
  else
@@ -84,6 +84,9 @@ module HexaPDF
84
84
  # Allowed values: sha256, sha384, sha512.
85
85
  attr_accessor :digest_algorithm
86
86
 
87
+ # The signing time to use instead of Time.now.
88
+ attr_accessor :signing_time
89
+
87
90
  # The timestamp handler instance that should be used for timestamping.
88
91
  attr_accessor :timestamp_handler
89
92
 
@@ -119,9 +122,10 @@ module HexaPDF
119
122
 
120
123
  # Creates the set of signed attributes for the signer information structure.
121
124
  def create_signed_attrs(data, signing_time: true)
125
+ signing_time = (self.signing_time || Time.now).utc if signing_time
122
126
  set(
123
127
  attribute('content-type', oid('id-data')),
124
- (attribute('id-signingTime', utc_time(Time.now.utc)) if signing_time),
128
+ (attribute('id-signingTime', utc_time(signing_time)) if signing_time),
125
129
  attribute(
126
130
  'message-digest',
127
131
  binary(OpenSSL::Digest.digest(@digest_algorithm, data))
@@ -77,9 +77,9 @@ module HexaPDF
77
77
  #
78
78
  # One style property, Layout::Style#font, is handled specially:
79
79
  #
80
- # * If no font is set on a style, the font "Times" is automatically set because otherwise there
81
- # would be problems with text drawing operations (font is the only style property that has no
82
- # valid default value).
80
+ # * If no font is set on a style, the default font specified via the configuration option
81
+ # 'font.default' is automatically set because otherwise there would be problems with text
82
+ # drawing operations (font is the only style property that has no valid default value).
83
83
  #
84
84
  # * Standard style objects only allow font wrapper objects to be set via the Layout::Style#font
85
85
  # method. This class makes usage easier by allowing strings or an array [name, options_hash]
@@ -151,7 +151,9 @@ module HexaPDF
151
151
  # :nodoc:
152
152
  def method_missing(name, *args, **kwargs, &block)
153
153
  if @layout.box_creation_method?(name)
154
- @children << @layout.send(name, *args, **kwargs, &block)
154
+ box = @layout.send(name, *args, **kwargs, &block)
155
+ @children << box
156
+ box
155
157
  else
156
158
  super
157
159
  end
@@ -354,6 +356,7 @@ module HexaPDF
354
356
  width: width, height: height, properties: properties,
355
357
  style: box_style)
356
358
  end
359
+ alias text text_box
357
360
 
358
361
  # Creates a HexaPDF::Layout::TextBox like #text_box but allows parts of the text to be
359
362
  # formatted differently.
@@ -456,6 +459,7 @@ module HexaPDF
456
459
  box_class_for_name(:text).new(items: data, width: width, height: height,
457
460
  properties: properties, style: box_style)
458
461
  end
462
+ alias formatted_text formatted_text_box
459
463
 
460
464
  # Creates a HexaPDF::Layout::ImageBox for the given image.
461
465
  #
@@ -477,6 +481,7 @@ module HexaPDF
477
481
  box_class_for_name(:image).new(image: image, width: width, height: height,
478
482
  properties: properties, style: style)
479
483
  end
484
+ alias image image_box
480
485
 
481
486
  # This helper class is used by Layout#table_box to allow specifying the keyword arguments used
482
487
  # when converting cell data to box instances.
@@ -495,8 +500,25 @@ module HexaPDF
495
500
  @number_of_columns = number_of_columns
496
501
  end
497
502
 
498
- # Stores the keyword arguments in +args+ for the given 0-based rows and columns which can
499
- # either be a single number or a range of numbers.
503
+ # Stores the hash +args+ containing styling properties for the cells specified via the given
504
+ # 0-based rows and columns.
505
+ #
506
+ # Rows and columns can either be single numbers, ranges of numbers or stepped ranges (i.e.
507
+ # Enumerator::ArithmeticSequence instances).
508
+ #
509
+ # Examples:
510
+ #
511
+ # # Gray background for all cells
512
+ # args[] = {cell: {background_color: "gray"}}
513
+ #
514
+ # # Cell at (2, 3) gets a bigger font size
515
+ # args[2, 3] = {font_size: 50}
516
+ #
517
+ # # First column of every row has bold font
518
+ # args[0..-1, 0] = {font: 'Helvetica bold'}
519
+ #
520
+ # # Every second row has a blue background
521
+ # args[(0..-1).step(2)] = {cell: {background_color: "blue"}}
500
522
  def []=(rows = 0..-1, cols = 0..-1, args)
501
523
  rows = adjust_range(rows.kind_of?(Integer) ? rows..rows : rows, @number_of_rows)
502
524
  cols = adjust_range(cols.kind_of?(Integer) ? cols..cols : cols, @number_of_columns)
@@ -509,7 +531,7 @@ module HexaPDF
509
531
  # is merged.
510
532
  def retrieve_arguments_for(row, col)
511
533
  @argument_infos.each_with_object({}) do |arg_info, result|
512
- next unless arg_info.rows.cover?(row) && arg_info.cols.cover?(col)
534
+ next unless arg_info.rows.include?(row) && arg_info.cols.include?(col)
513
535
  if arg_info.args[:cell]
514
536
  arg_info.args[:cell] = (result[:cell] || {}).merge(arg_info.args[:cell])
515
537
  end
@@ -522,7 +544,8 @@ module HexaPDF
522
544
  # Adjusts the +range+ so that both the begin and the end of the range are zero or positive
523
545
  # integers smaller than +max+.
524
546
  def adjust_range(range, max)
525
- (range.begin % max)..(range.end % max)
547
+ r = (range.begin % max)..(range.end % max)
548
+ range.kind_of?(Range) ? r : r.step(range.step)
526
549
  end
527
550
 
528
551
  end
@@ -540,7 +563,8 @@ module HexaPDF
540
563
  # Additional arguments for the #text_box invocations can be specified using the optional block
541
564
  # that yields a CellArgumentCollector instance. This allows customization of the text boxes.
542
565
  # By specifying the special key +:cell+ it is also possible to assign style properties to the
543
- # cells themselves.
566
+ # cells themselves, irrespective of the type of content of the cells. See
567
+ # CellArgumentCollector#[]= for details.
544
568
  #
545
569
  # See HexaPDF::Layout::TableBox::new for details on +column_widths+, +header+, +footer+, and
546
570
  # +cell_style+.
@@ -586,6 +610,7 @@ module HexaPDF
586
610
  footer: footer, cell_style: cell_style, width: width,
587
611
  height: height, properties: properties, style: style)
588
612
  end
613
+ alias table table_box
589
614
 
590
615
  LOREM_IPSUM = [ # :nodoc:
591
616
  "Lorem ipsum dolor sit amet, con\u{00AD}sectetur adipis\u{00AD}cing elit, sed " \
@@ -605,22 +630,13 @@ module HexaPDF
605
630
  def lorem_ipsum_box(sentences: 4, count: 1, **text_box_properties)
606
631
  text_box(([LOREM_IPSUM[0, sentences].join(" ")] * count).join("\n\n"), **text_box_properties)
607
632
  end
633
+ alias lorem_ipsum lorem_ipsum_box
608
634
 
609
- BOX_METHOD_NAMES = [:text, :formatted_text, :image, :table, :lorem_ipsum] #:nodoc:
610
-
611
- # Allows creating boxes using more convenient method names:
612
- #
613
- # * #text for #text_box
614
- # * #formatted_text for #formatted_text_box
615
- # * #image for #image_box
616
- # * #lorem_ipsum for #lorem_ipsum_box
617
- # * The name of a pre-defined box class like #column will invoke #box appropriately. Same if
618
- # used with a '_box' suffix.
635
+ # Allows creating boxes using more convenient method names: The name of a pre-defined box
636
+ # class like #column will invoke #box appropriately. Same if used with a '_box' suffix.
619
637
  def method_missing(name, *args, **kwargs, &block)
620
638
  name_without_box = name.to_s.sub(/_box$/, '').intern
621
- if BOX_METHOD_NAMES.include?(name)
622
- send("#{name}_box", *args, **kwargs, &block)
623
- elsif @document.config['layout.boxes.map'].key?(name_without_box)
639
+ if @document.config['layout.boxes.map'].key?(name_without_box)
624
640
  box(name_without_box, *args, **kwargs, &block)
625
641
  else
626
642
  super
@@ -632,6 +648,8 @@ module HexaPDF
632
648
  box_creation_method?(name) || super
633
649
  end
634
650
 
651
+ BOX_METHOD_NAMES = [:text, :formatted_text, :image, :table, :lorem_ipsum] #:nodoc:
652
+
635
653
  # :nodoc:
636
654
  def box_creation_method?(name)
637
655
  name = name.to_s.sub(/_box$/, '').intern
@@ -648,8 +666,8 @@ module HexaPDF
648
666
  end
649
667
  end
650
668
 
651
- # Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and +properties+
652
- # arguments.
669
+ # Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and
670
+ # +properties+ arguments.
653
671
  #
654
672
  # The +style+ argument specifies the style to retrieve. It can either be a registered style
655
673
  # name (see #style), a hash with style properties or +nil+. In the latter case the registered
@@ -658,15 +676,18 @@ module HexaPDF
658
676
  # If the +properties+ hash is not empty, the retrieved style is duplicated and the properties
659
677
  # hash is applied to it.
660
678
  #
661
- # Finally, a default font (the one from the :base style or otherwise 'Times') is set if
662
- # necessary to ensure that the style object works in all cases.
679
+ # Finally, a default font (the one from the :base style or otherwise the one set using the
680
+ # configuration option 'font.default') is set if necessary to ensure that the style object
681
+ # works in all cases.
663
682
  def retrieve_style(style, properties = nil)
664
683
  if style.kind_of?(Symbol) && !@styles.key?(style)
665
684
  raise HexaPDF::Error, "Style #{style} not defined"
666
685
  end
667
686
  style = HexaPDF::Layout::Style.create(@styles[style] || style || @styles[:base])
668
687
  style = style.dup.update(**properties) unless properties.nil? || properties.empty?
669
- style.font(@styles[:base].font? && @styles[:base].font || 'Times') unless style.font?
688
+ unless style.font?
689
+ style.font(@styles[:base].font? && @styles[:base].font || @document.config['font.default'])
690
+ end
670
691
  unless style.font.respond_to?(:pdf_object)
671
692
  name, options = *style.font
672
693
  style.font(@document.fonts.add(name, **(options || {})))