origami-docspring 2.2.0 → 2.3.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/examples/attachments/attachment.rb +7 -8
  4. data/examples/attachments/nested_document.rb +6 -5
  5. data/examples/encryption/encryption.rb +5 -4
  6. data/examples/events/events.rb +7 -6
  7. data/examples/flash/flash.rb +10 -9
  8. data/examples/forms/javascript.rb +14 -13
  9. data/examples/forms/xfa.rb +67 -66
  10. data/examples/javascript/hello_world.rb +6 -5
  11. data/examples/javascript/js_emulation.rb +26 -26
  12. data/examples/loop/goto.rb +12 -11
  13. data/examples/loop/named.rb +17 -16
  14. data/examples/signature/signature.rb +11 -11
  15. data/examples/uri/javascript.rb +25 -24
  16. data/examples/uri/open-uri.rb +5 -4
  17. data/examples/uri/submitform.rb +11 -10
  18. data/lib/origami/3d.rb +330 -334
  19. data/lib/origami/acroform.rb +267 -268
  20. data/lib/origami/actions.rb +266 -278
  21. data/lib/origami/annotations.rb +659 -670
  22. data/lib/origami/array.rb +192 -196
  23. data/lib/origami/boolean.rb +66 -70
  24. data/lib/origami/catalog.rb +360 -363
  25. data/lib/origami/collections.rb +132 -133
  26. data/lib/origami/compound.rb +125 -129
  27. data/lib/origami/destinations.rb +226 -237
  28. data/lib/origami/dictionary.rb +155 -154
  29. data/lib/origami/encryption.rb +967 -923
  30. data/lib/origami/extensions/fdf.rb +270 -275
  31. data/lib/origami/extensions/ppklite.rb +323 -328
  32. data/lib/origami/filespec.rb +170 -173
  33. data/lib/origami/filters/ascii.rb +162 -167
  34. data/lib/origami/filters/ccitt/tables.rb +248 -252
  35. data/lib/origami/filters/ccitt.rb +309 -312
  36. data/lib/origami/filters/crypt.rb +31 -34
  37. data/lib/origami/filters/dct.rb +47 -50
  38. data/lib/origami/filters/flate.rb +57 -60
  39. data/lib/origami/filters/jbig2.rb +50 -53
  40. data/lib/origami/filters/jpx.rb +40 -43
  41. data/lib/origami/filters/lzw.rb +151 -155
  42. data/lib/origami/filters/predictors.rb +250 -255
  43. data/lib/origami/filters/runlength.rb +111 -115
  44. data/lib/origami/filters.rb +319 -325
  45. data/lib/origami/font.rb +173 -177
  46. data/lib/origami/functions.rb +62 -66
  47. data/lib/origami/graphics/colors.rb +203 -208
  48. data/lib/origami/graphics/instruction.rb +79 -81
  49. data/lib/origami/graphics/path.rb +141 -144
  50. data/lib/origami/graphics/patterns.rb +156 -160
  51. data/lib/origami/graphics/render.rb +51 -47
  52. data/lib/origami/graphics/state.rb +144 -142
  53. data/lib/origami/graphics/text.rb +185 -188
  54. data/lib/origami/graphics/xobject.rb +818 -804
  55. data/lib/origami/graphics.rb +25 -26
  56. data/lib/origami/header.rb +63 -65
  57. data/lib/origami/javascript.rb +718 -651
  58. data/lib/origami/linearization.rb +284 -285
  59. data/lib/origami/metadata.rb +156 -135
  60. data/lib/origami/name.rb +98 -100
  61. data/lib/origami/null.rb +49 -51
  62. data/lib/origami/numeric.rb +133 -135
  63. data/lib/origami/obfuscation.rb +180 -182
  64. data/lib/origami/object.rb +634 -631
  65. data/lib/origami/optionalcontent.rb +147 -149
  66. data/lib/origami/outline.rb +46 -48
  67. data/lib/origami/outputintents.rb +76 -77
  68. data/lib/origami/page.rb +637 -596
  69. data/lib/origami/parser.rb +214 -221
  70. data/lib/origami/parsers/fdf.rb +44 -45
  71. data/lib/origami/parsers/pdf/lazy.rb +147 -154
  72. data/lib/origami/parsers/pdf/linear.rb +104 -109
  73. data/lib/origami/parsers/pdf.rb +109 -107
  74. data/lib/origami/parsers/ppklite.rb +44 -46
  75. data/lib/origami/pdf.rb +886 -896
  76. data/lib/origami/reference.rb +116 -120
  77. data/lib/origami/signature.rb +617 -625
  78. data/lib/origami/stream.rb +560 -558
  79. data/lib/origami/string.rb +366 -368
  80. data/lib/origami/template/patterns.rb +50 -52
  81. data/lib/origami/template/widgets.rb +111 -114
  82. data/lib/origami/trailer.rb +153 -157
  83. data/lib/origami/tree.rb +55 -57
  84. data/lib/origami/version.rb +19 -19
  85. data/lib/origami/webcapture.rb +87 -90
  86. data/lib/origami/xfa/config.rb +409 -414
  87. data/lib/origami/xfa/connectionset.rb +113 -117
  88. data/lib/origami/xfa/datasets.rb +38 -42
  89. data/lib/origami/xfa/localeset.rb +33 -37
  90. data/lib/origami/xfa/package.rb +49 -52
  91. data/lib/origami/xfa/pdf.rb +54 -59
  92. data/lib/origami/xfa/signature.rb +33 -37
  93. data/lib/origami/xfa/sourceset.rb +34 -38
  94. data/lib/origami/xfa/stylesheet.rb +35 -39
  95. data/lib/origami/xfa/template.rb +1630 -1634
  96. data/lib/origami/xfa/xdc.rb +33 -37
  97. data/lib/origami/xfa/xfa.rb +132 -123
  98. data/lib/origami/xfa/xfdf.rb +34 -38
  99. data/lib/origami/xfa/xmpmeta.rb +34 -38
  100. data/lib/origami/xfa.rb +50 -53
  101. data/lib/origami/xreftable.rb +462 -462
  102. data/lib/origami.rb +37 -38
  103. data/test/test_actions.rb +22 -20
  104. data/test/test_annotations.rb +54 -52
  105. data/test/test_forms.rb +23 -21
  106. data/test/test_native_types.rb +82 -78
  107. data/test/test_object_tree.rb +25 -24
  108. data/test/test_pages.rb +43 -41
  109. data/test/test_pdf.rb +2 -0
  110. data/test/test_pdf_attachment.rb +23 -21
  111. data/test/test_pdf_create.rb +16 -15
  112. data/test/test_pdf_encrypt.rb +69 -66
  113. data/test/test_pdf_parse.rb +131 -129
  114. data/test/test_pdf_parse_lazy.rb +53 -53
  115. data/test/test_pdf_sign.rb +67 -67
  116. data/test/test_streams.rb +145 -143
  117. data/test/test_xrefs.rb +46 -45
  118. metadata +64 -8
@@ -1,444 +1,442 @@
1
- =begin
2
-
3
- This file is part of Origami, PDF manipulation framework for Ruby
4
- Copyright (C) 2016 Guillaume Delugré.
5
-
6
- Origami is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- Origami is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- =end
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This file is part of Origami, PDF manipulation framework for Ruby
5
+ # Copyright (C) 2016 Guillaume Delugré.
6
+ #
7
+ # Origami is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # Origami is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with Origami. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
20
 
21
21
  require 'date'
22
22
 
23
23
  module Origami
24
+ #
25
+ # Module common to String objects.
26
+ #
27
+ module String
28
+ module Encoding
29
+ class EncodingError < Error # :nodoc:
30
+ end
31
+
32
+ module PDFDocEncoding
33
+ CHARMAP =
34
+ [
35
+ "\x00\x00", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd",
36
+ "\xff\xfd", "\x00\x09", "\x00\x0a", "\xff\xfd", "\x00\x0c", "\x00\x0d", "\xff\xfd", "\xff\xfd",
37
+ "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd",
38
+ "\x02\xd8", "\x02\xc7", "\x02\xc6", "\x02\xd9", "\x02\xdd", "\x02\xdb", "\x02\xda", "\x02\xdc",
39
+ "\x00\x20", "\x00\x21", "\x00\x22", "\x00\x23", "\x00\x24", "\x00\x25", "\x00\x26", "\x00\x27",
40
+ "\x00\x28", "\x00\x29", "\x00\x2a", "\x00\x2b", "\x00\x2c", "\x00\x2d", "\x00\x2e", "\x00\x2f",
41
+ "\x00\x30", "\x00\x31", "\x00\x32", "\x00\x33", "\x00\x34", "\x00\x35", "\x00\x36", "\x00\x37",
42
+ "\x00\x38", "\x00\x39", "\x00\x3a", "\x00\x3b", "\x00\x3c", "\x00\x3d", "\x00\x3e", "\x00\x3f",
43
+ "\x00\x40", "\x00\x41", "\x00\x42", "\x00\x43", "\x00\x44", "\x00\x45", "\x00\x46", "\x00\x47",
44
+ "\x00\x48", "\x00\x49", "\x00\x4a", "\x00\x4b", "\x00\x4c", "\x00\x4d", "\x00\x4e", "\x00\x4f",
45
+ "\x00\x50", "\x00\x51", "\x00\x52", "\x00\x53", "\x00\x54", "\x00\x55", "\x00\x56", "\x00\x57",
46
+ "\x00\x58", "\x00\x59", "\x00\x5a", "\x00\x5b", "\x00\x5c", "\x00\x5d", "\x00\x5e", "\x00\x5f",
47
+ "\x00\x60", "\x00\x61", "\x00\x62", "\x00\x63", "\x00\x64", "\x00\x65", "\x00\x66", "\x00\x67",
48
+ "\x00\x68", "\x00\x69", "\x00\x6a", "\x00\x6b", "\x00\x6c", "\x00\x6d", "\x00\x6e", "\x00\x6f",
49
+ "\x00\x70", "\x00\x71", "\x00\x72", "\x00\x73", "\x00\x74", "\x00\x75", "\x00\x76", "\x00\x77",
50
+ "\x00\x78", "\x00\x79", "\x00\x7a", "\x00\x7b", "\x00\x7c", "\x00\x7d", "\x00\x7e", "\xff\xfd",
51
+ "\x20\x22", "\x20\x20", "\x20\x21", "\x20\x26", "\x20\x14", "\x20\x13", "\x01\x92", "\x20\x44",
52
+ "\x20\x39", "\x20\x3a", "\x22\x12", "\x20\x30", "\x20\x1e", "\x20\x1c", "\x20\x1d", "\x20\x18",
53
+ "\x20\x19", "\x20\x1a", "\x21\x22", "\xfb\x01", "\xfb\x02", "\x01\x41", "\x01\x52", "\x01\x60",
54
+ "\x01\x78", "\x01\x7d", "\x01\x31", "\x01\x42", "\x01\x53", "\x01\x61", "\x01\x7e", "\xff\xfd",
55
+ "\x20\xac", "\x00\xa1", "\x00\xa2", "\x00\xa3", "\x00\xa4", "\x00\xa5", "\x00\xa6", "\x00\xa7",
56
+ "\x00\xa8", "\x00\xa9", "\x00\xaa", "\x00\xab", "\x00\xac", "\xff\xfd", "\x00\xae", "\x00\xaf",
57
+ "\x00\xb0", "\x00\xb1", "\x00\xb2", "\x00\xb3", "\x00\xb4", "\x00\xb5", "\x00\xb6", "\x00\xb7",
58
+ "\x00\xb8", "\x00\xb9", "\x00\xba", "\x00\xbb", "\x00\xbc", "\x00\xbd", "\x00\xbe", "\x00\xbf",
59
+ "\x00\xc0", "\x00\xc1", "\x00\xc2", "\x00\xc3", "\x00\xc4", "\x00\xc5", "\x00\xc6", "\x00\xc7",
60
+ "\x00\xc8", "\x00\xc9", "\x00\xca", "\x00\xcb", "\x00\xcc", "\x00\xcd", "\x00\xce", "\x00\xcf",
61
+ "\x00\xd0", "\x00\xd1", "\x00\xd2", "\x00\xd3", "\x00\xd4", "\x00\xd5", "\x00\xd6", "\x00\xd7",
62
+ "\x00\xd8", "\x00\xd9", "\x00\xda", "\x00\xdb", "\x00\xdc", "\x00\xdd", "\x00\xde", "\x00\xdf",
63
+ "\x00\xe0", "\x00\xe1", "\x00\xe2", "\x00\xe3", "\x00\xe4", "\x00\xe5", "\x00\xe6", "\x00\xe7",
64
+ "\x00\xe8", "\x00\xe9", "\x00\xea", "\x00\xeb", "\x00\xec", "\x00\xed", "\x00\xee", "\x00\xef",
65
+ "\x00\xf0", "\x00\xf1", "\x00\xf2", "\x00\xf3", "\x00\xf4", "\x00\xf5", "\x00\xf6", "\x00\xf7",
66
+ "\x00\xf8", "\x00\xf9", "\x00\xfa", "\x00\xfb", "\x00\xfc", "\x00\xfd", "\x00\xfe", "\x00\xff"
67
+ ].map(&:b)
68
+
69
+ def self.to_utf16be(pdfdocstr)
70
+ utf16bestr = +UTF16BE::BOM.dup
71
+ pdfdocstr.each_byte do |byte|
72
+ utf16bestr << CHARMAP[byte]
73
+ end
74
+
75
+ utf16bestr.force_encoding('binary')
76
+ end
24
77
 
25
- #
26
- # Module common to String objects.
27
- #
28
- module String
29
-
30
- module Encoding
31
- class EncodingError < Error #:nodoc:
32
- end
33
-
34
- module PDFDocEncoding
35
- CHARMAP =
36
- [
37
- "\x00\x00", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd",
38
- "\xff\xfd", "\x00\x09", "\x00\x0a", "\xff\xfd", "\x00\x0c", "\x00\x0d", "\xff\xfd", "\xff\xfd",
39
- "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd", "\xff\xfd",
40
- "\x02\xd8", "\x02\xc7", "\x02\xc6", "\x02\xd9", "\x02\xdd", "\x02\xdb", "\x02\xda", "\x02\xdc",
41
- "\x00\x20", "\x00\x21", "\x00\x22", "\x00\x23", "\x00\x24", "\x00\x25", "\x00\x26", "\x00\x27",
42
- "\x00\x28", "\x00\x29", "\x00\x2a", "\x00\x2b", "\x00\x2c", "\x00\x2d", "\x00\x2e", "\x00\x2f",
43
- "\x00\x30", "\x00\x31", "\x00\x32", "\x00\x33", "\x00\x34", "\x00\x35", "\x00\x36", "\x00\x37",
44
- "\x00\x38", "\x00\x39", "\x00\x3a", "\x00\x3b", "\x00\x3c", "\x00\x3d", "\x00\x3e", "\x00\x3f",
45
- "\x00\x40", "\x00\x41", "\x00\x42", "\x00\x43", "\x00\x44", "\x00\x45", "\x00\x46", "\x00\x47",
46
- "\x00\x48", "\x00\x49", "\x00\x4a", "\x00\x4b", "\x00\x4c", "\x00\x4d", "\x00\x4e", "\x00\x4f",
47
- "\x00\x50", "\x00\x51", "\x00\x52", "\x00\x53", "\x00\x54", "\x00\x55", "\x00\x56", "\x00\x57",
48
- "\x00\x58", "\x00\x59", "\x00\x5a", "\x00\x5b", "\x00\x5c", "\x00\x5d", "\x00\x5e", "\x00\x5f",
49
- "\x00\x60", "\x00\x61", "\x00\x62", "\x00\x63", "\x00\x64", "\x00\x65", "\x00\x66", "\x00\x67",
50
- "\x00\x68", "\x00\x69", "\x00\x6a", "\x00\x6b", "\x00\x6c", "\x00\x6d", "\x00\x6e", "\x00\x6f",
51
- "\x00\x70", "\x00\x71", "\x00\x72", "\x00\x73", "\x00\x74", "\x00\x75", "\x00\x76", "\x00\x77",
52
- "\x00\x78", "\x00\x79", "\x00\x7a", "\x00\x7b", "\x00\x7c", "\x00\x7d", "\x00\x7e", "\xff\xfd",
53
- "\x20\x22", "\x20\x20", "\x20\x21", "\x20\x26", "\x20\x14", "\x20\x13", "\x01\x92", "\x20\x44",
54
- "\x20\x39", "\x20\x3a", "\x22\x12", "\x20\x30", "\x20\x1e", "\x20\x1c", "\x20\x1d", "\x20\x18",
55
- "\x20\x19", "\x20\x1a", "\x21\x22", "\xfb\x01", "\xfb\x02", "\x01\x41", "\x01\x52", "\x01\x60",
56
- "\x01\x78", "\x01\x7d", "\x01\x31", "\x01\x42", "\x01\x53", "\x01\x61", "\x01\x7e", "\xff\xfd",
57
- "\x20\xac", "\x00\xa1", "\x00\xa2", "\x00\xa3", "\x00\xa4", "\x00\xa5", "\x00\xa6", "\x00\xa7",
58
- "\x00\xa8", "\x00\xa9", "\x00\xaa", "\x00\xab", "\x00\xac", "\xff\xfd", "\x00\xae", "\x00\xaf",
59
- "\x00\xb0", "\x00\xb1", "\x00\xb2", "\x00\xb3", "\x00\xb4", "\x00\xb5", "\x00\xb6", "\x00\xb7",
60
- "\x00\xb8", "\x00\xb9", "\x00\xba", "\x00\xbb", "\x00\xbc", "\x00\xbd", "\x00\xbe", "\x00\xbf",
61
- "\x00\xc0", "\x00\xc1", "\x00\xc2", "\x00\xc3", "\x00\xc4", "\x00\xc5", "\x00\xc6", "\x00\xc7",
62
- "\x00\xc8", "\x00\xc9", "\x00\xca", "\x00\xcb", "\x00\xcc", "\x00\xcd", "\x00\xce", "\x00\xcf",
63
- "\x00\xd0", "\x00\xd1", "\x00\xd2", "\x00\xd3", "\x00\xd4", "\x00\xd5", "\x00\xd6", "\x00\xd7",
64
- "\x00\xd8", "\x00\xd9", "\x00\xda", "\x00\xdb", "\x00\xdc", "\x00\xdd", "\x00\xde", "\x00\xdf",
65
- "\x00\xe0", "\x00\xe1", "\x00\xe2", "\x00\xe3", "\x00\xe4", "\x00\xe5", "\x00\xe6", "\x00\xe7",
66
- "\x00\xe8", "\x00\xe9", "\x00\xea", "\x00\xeb", "\x00\xec", "\x00\xed", "\x00\xee", "\x00\xef",
67
- "\x00\xf0", "\x00\xf1", "\x00\xf2", "\x00\xf3", "\x00\xf4", "\x00\xf5", "\x00\xf6", "\x00\xf7",
68
- "\x00\xf8", "\x00\xf9", "\x00\xfa", "\x00\xfb", "\x00\xfc", "\x00\xfd", "\x00\xfe", "\x00\xff"
69
- ].map(&:b)
70
-
71
- def PDFDocEncoding.to_utf16be(pdfdocstr)
72
- utf16bestr = UTF16BE::BOM.dup
73
- pdfdocstr.each_byte do |byte|
74
- utf16bestr << CHARMAP[byte]
75
- end
76
-
77
- utf16bestr.force_encoding('binary')
78
- end
79
-
80
- def PDFDocEncoding.to_pdfdoc(str)
81
- str
82
- end
83
- end
84
-
85
- module UTF16BE
86
- BOM = "\xFE\xFF".b
87
-
88
- def UTF16BE.to_utf16be(str)
89
- str
90
- end
91
-
92
- def UTF16BE.to_pdfdoc(str)
93
- pdfdoc = []
94
- i = 2
78
+ def self.to_pdfdoc(str)
79
+ str
80
+ end
81
+ end
95
82
 
96
- while i < str.size
97
- char = PDFDocEncoding::CHARMAP.index(str[i,2])
98
- raise EncodingError, "Can't convert UTF16-BE character to PDFDocEncoding" if char.nil?
99
- pdfdoc << char
100
- i = i + 2
101
- end
83
+ module UTF16BE
84
+ BOM = "\xFE\xFF".b
102
85
 
103
- pdfdoc.pack("C*")
104
- end
105
- end
86
+ def self.to_utf16be(str)
87
+ str
106
88
  end
107
89
 
108
- include Origami::Object
109
-
110
- attr_accessor :encoding
90
+ def self.to_pdfdoc(str)
91
+ pdfdoc = []
92
+ i = 2
111
93
 
112
- def initialize(str) #:nodoc:
113
- super(str.force_encoding('binary'))
94
+ while i < str.size
95
+ char = PDFDocEncoding::CHARMAP.index(str[i, 2])
96
+ raise EncodingError, "Can't convert UTF16-BE character to PDFDocEncoding" if char.nil?
97
+ pdfdoc << char
98
+ i += 2
99
+ end
114
100
 
115
- detect_encoding
101
+ +pdfdoc.pack("C*")
116
102
  end
103
+ end
104
+ end
117
105
 
118
- #
119
- # Convert String object to an UTF8 encoded Ruby string.
120
- #
121
- def to_utf8
122
- detect_encoding
106
+ include Origami::Object
123
107
 
124
- utf16 = self.encoding.to_utf16be(self.value)
125
- utf16.slice!(0, Encoding::UTF16BE::BOM.size)
108
+ attr_accessor :encoding
126
109
 
127
- utf16.encode("utf-8", "utf-16be")
128
- end
110
+ def initialize(str) # :nodoc:
111
+ mutable_str = +str.dup # Create a mutable copy
112
+ super(mutable_str.force_encoding('binary'))
129
113
 
130
- #
131
- # Convert String object to an UTF16-BE encoded binary Ruby string.
132
- #
133
- def to_utf16be
134
- detect_encoding
135
- self.encoding.to_utf16be(self.value)
136
- end
114
+ detect_encoding
115
+ end
137
116
 
138
- #
139
- # Convert String object to a PDFDocEncoding encoded binary Ruby string.
140
- #
141
- def to_pdfdoc
142
- detect_encoding
143
- self.encoding.to_pdfdoc(self.value)
144
- end
117
+ #
118
+ # Convert String object to an UTF8 encoded Ruby string.
119
+ #
120
+ def to_utf8
121
+ detect_encoding
145
122
 
146
- def detect_encoding #:nodoc:
147
- if self.value[0,2] == Encoding::UTF16BE::BOM
148
- @encoding = Encoding::UTF16BE
149
- else
150
- @encoding = Encoding::PDFDocEncoding
151
- end
152
- end
153
- end
123
+ utf16 = encoding.to_utf16be(value)
124
+ utf16.slice!(0, Encoding::UTF16BE::BOM.size)
154
125
 
155
- class InvalidHexaStringObjectError < InvalidObjectError #:nodoc:
126
+ utf16.encode("utf-8", "utf-16be")
156
127
  end
157
128
 
158
129
  #
159
- # Class representing an hexadecimal-writen String Object.
130
+ # Convert String object to an UTF16-BE encoded binary Ruby string.
160
131
  #
161
- class HexaString < ::String
162
- include String
132
+ def to_utf16be
133
+ detect_encoding
134
+ encoding.to_utf16be(value)
135
+ end
163
136
 
164
- TOKENS = %w{ < > } #:nodoc:
137
+ #
138
+ # Convert String object to a PDFDocEncoding encoded binary Ruby string.
139
+ #
140
+ def to_pdfdoc
141
+ detect_encoding
142
+ encoding.to_pdfdoc(value)
143
+ end
165
144
 
166
- @@regexp_open = Regexp.new(WHITESPACES + TOKENS.first)
167
- @@regexp_close = Regexp.new(TOKENS.last)
145
+ def detect_encoding # :nodoc:
146
+ @encoding = if value[0, 2] == Encoding::UTF16BE::BOM
147
+ Encoding::UTF16BE
148
+ else
149
+ Encoding::PDFDocEncoding
150
+ end
151
+ end
152
+ end
168
153
 
169
- #
170
- # Creates a new PDF hexadecimal String.
171
- # _str_:: The string value.
172
- #
173
- def initialize(str = "")
174
- unless str.is_a?(::String)
175
- raise TypeError, "Expected type String, received #{str.class}."
176
- end
154
+ class InvalidHexaStringObjectError < InvalidObjectError # :nodoc:
155
+ end
177
156
 
178
- super(str)
179
- end
157
+ #
158
+ # Class representing an hexadecimal-writen String Object.
159
+ #
160
+ class HexaString < ::String
161
+ include String
180
162
 
181
- def self.parse(stream, _parser = nil) #:nodoc:
182
- scanner = Parser.init_scanner(stream)
183
- offset = scanner.pos
163
+ TOKENS = %w[< >] # :nodoc:
184
164
 
185
- if scanner.skip(@@regexp_open).nil?
186
- raise InvalidHexaStringObjectError, "Hexadecimal string shall start with a '#{TOKENS.first}' token"
187
- end
165
+ @@regexp_open = Regexp.new(WHITESPACES + TOKENS.first)
166
+ @@regexp_close = Regexp.new(TOKENS.last)
188
167
 
189
- hexa = scanner.scan_until(@@regexp_close)
190
- if hexa.nil?
191
- raise InvalidHexaStringObjectError, "Hexadecimal string shall end with a '#{TOKENS.last}' token"
192
- end
168
+ #
169
+ # Creates a new PDF hexadecimal String.
170
+ # _str_:: The string value.
171
+ #
172
+ def initialize(str = "")
173
+ unless str.is_a?(::String)
174
+ raise TypeError, "Expected type String, received #{str.class}."
175
+ end
193
176
 
194
- begin
195
- decoded = Filter::ASCIIHex.decode(hexa.chomp!(TOKENS.last))
196
- rescue Filter::InvalidASCIIHexStringError => e
197
- raise InvalidHexaStringObjectError, e.message
198
- end
177
+ super
178
+ end
199
179
 
200
- hexastr = HexaString.new(decoded)
201
- hexastr.file_offset = offset
180
+ def self.parse(stream, _parser = nil) # :nodoc:
181
+ scanner = Parser.init_scanner(stream)
182
+ offset = scanner.pos
202
183
 
203
- hexastr
204
- end
184
+ if scanner.skip(@@regexp_open).nil?
185
+ raise InvalidHexaStringObjectError, "Hexadecimal string shall start with a '#{TOKENS.first}' token"
186
+ end
205
187
 
206
- def to_s(eol: $/) #:nodoc:
207
- super(TOKENS.first + Filter::ASCIIHex.encode(to_str) + TOKENS.last, eol: eol)
208
- end
188
+ hexa = scanner.scan_until(@@regexp_close)
189
+ if hexa.nil?
190
+ raise InvalidHexaStringObjectError, "Hexadecimal string shall end with a '#{TOKENS.last}' token"
191
+ end
209
192
 
210
- #
211
- # Converts self to a literal String.
212
- #
213
- def to_literal
214
- LiteralString.new(self.value)
215
- end
193
+ begin
194
+ hexacopy = +hexa.dup # Create a mutable copy
195
+ decoded = Filter::ASCIIHex.decode(hexacopy.chomp!(TOKENS.last))
196
+ rescue Filter::InvalidASCIIHexStringError => e
197
+ raise InvalidHexaStringObjectError, e.message
198
+ end
216
199
 
217
- def value
218
- self.decrypt! if self.is_a?(Encryption::EncryptedString) and not @decrypted
200
+ hexastr = HexaString.new(decoded)
201
+ hexastr.file_offset = offset
219
202
 
220
- to_str
221
- end
203
+ hexastr
222
204
  end
223
205
 
224
- class InvalidLiteralStringObjectError < InvalidObjectError #:nodoc:
206
+ def to_s(eol: $/) # :nodoc:
207
+ super(TOKENS.first + Filter::ASCIIHex.encode(to_str) + TOKENS.last, eol: eol)
225
208
  end
226
209
 
227
210
  #
228
- # Class representing a literal String Object.
211
+ # Converts self to a literal String.
229
212
  #
230
- class LiteralString < ::String
231
- include String
213
+ def to_literal
214
+ LiteralString.new(value)
215
+ end
232
216
 
233
- TOKENS = %w{ ( ) } #:nodoc:
217
+ def value
218
+ decrypt! if is_a?(Encryption::EncryptedString) && !@decrypted
234
219
 
235
- @@regexp_open = Regexp.new(WHITESPACES + Regexp.escape(TOKENS.first))
236
- @@regexp_close = Regexp.new(Regexp.escape(TOKENS.last))
220
+ to_str
221
+ end
222
+ end
237
223
 
238
- #
239
- # Creates a new PDF String.
240
- # _str_:: The string value.
241
- #
242
- def initialize(str = "")
243
- unless str.is_a?(::String)
244
- raise TypeError, "Expected type String, received #{str.class}."
245
- end
224
+ class InvalidLiteralStringObjectError < InvalidObjectError # :nodoc:
225
+ end
246
226
 
247
- super(str)
248
- end
227
+ #
228
+ # Class representing a literal String Object.
229
+ #
230
+ class LiteralString < ::String
231
+ include String
249
232
 
250
- def self.parse(stream, _parser = nil) #:nodoc:
251
- scanner = Parser.init_scanner(stream)
252
- offset = scanner.pos
233
+ TOKENS = %w[( )] # :nodoc:
253
234
 
254
- unless scanner.skip(@@regexp_open)
255
- raise InvalidLiteralStringObjectError, "No literal string start token found"
256
- end
235
+ @@regexp_open = Regexp.new(WHITESPACES + Regexp.escape(TOKENS.first))
236
+ @@regexp_close = Regexp.new(Regexp.escape(TOKENS.last))
257
237
 
258
- result = ""
259
- depth = 0
260
- while depth != 0 or scanner.peek(1) != TOKENS.last do
261
- raise InvalidLiteralStringObjectError, "Non-terminated string" if scanner.eos?
262
-
263
- c = scanner.get_byte
264
- case c
265
- when "\\"
266
- if scanner.match?(/\d{1,3}/)
267
- oct = scanner.peek(3).oct.chr
268
- scanner.pos += 3
269
- result << oct
270
- elsif scanner.match?(/((\r?\n)|(\r\n?))/)
271
- scanner.skip(/((\r?\n)|(\r\n?))/)
272
- next
273
- else
274
- flag = scanner.get_byte
275
- case flag
276
- when "n" then result << "\n"
277
- when "r" then result << "\r"
278
- when "t" then result << "\t"
279
- when "b" then result << "\b"
280
- when "f" then result << "\f"
281
- else
282
- result << flag
283
- end
284
- end
285
-
286
- when "(" then
287
- depth = depth + 1
288
- result << c
289
- when ")" then
290
- depth = depth - 1
291
- result << c
292
- else
293
- result << c
294
- end
295
- end
238
+ #
239
+ # Creates a new PDF String.
240
+ # _str_:: The string value.
241
+ #
242
+ def initialize(str = "")
243
+ unless str.is_a?(::String)
244
+ raise TypeError, "Expected type String, received #{str.class}."
245
+ end
296
246
 
297
- unless scanner.skip(@@regexp_close)
298
- raise InvalidLiteralStringObjectError, "Byte string shall be terminated with '#{TOKENS.last}'"
299
- end
247
+ super
248
+ end
300
249
 
301
- # Try to cast as a Date object if possible.
302
- if result[0, 2] == 'D:'
303
- begin
304
- date = Date.parse(result)
305
- date.file_offset = offset
306
- return date
307
- rescue InvalidDateError
308
- end
250
+ def self.parse(stream, _parser = nil) # :nodoc:
251
+ scanner = Parser.init_scanner(stream)
252
+ offset = scanner.pos
253
+
254
+ unless scanner.skip(@@regexp_open)
255
+ raise InvalidLiteralStringObjectError, "No literal string start token found"
256
+ end
257
+
258
+ result = +""
259
+ depth = 0
260
+ while (depth != 0) || (scanner.peek(1) != TOKENS.last)
261
+ raise InvalidLiteralStringObjectError, "Non-terminated string" if scanner.eos?
262
+
263
+ c = scanner.get_byte
264
+ case c
265
+ when "\\"
266
+ if scanner.match?(/\d{1,3}/)
267
+ oct = scanner.peek(3).oct.chr
268
+ scanner.pos += 3
269
+ result << oct
270
+ elsif scanner.match?(/((\r?\n)|(\r\n?))/)
271
+ scanner.skip(/((\r?\n)|(\r\n?))/)
272
+ next
273
+ else
274
+ flag = scanner.get_byte
275
+ result << case flag
276
+ when "n" then "\n"
277
+ when "r" then "\r"
278
+ when "t" then "\t"
279
+ when "b" then "\b"
280
+ when "f" then "\f"
281
+ else
282
+ flag
309
283
  end
310
-
311
- bytestr = self.new(result)
312
- bytestr.file_offset = offset
313
-
314
- bytestr
315
- end
316
-
317
- def to_s(eol: $/) #:nodoc:
318
- super(TOKENS.first + expand + TOKENS.last, eol: eol)
284
+ end
285
+
286
+ when "("
287
+ depth += 1
288
+ result << c
289
+ when ")"
290
+ depth -= 1
291
+ result << c
292
+ else
293
+ result << c
319
294
  end
320
-
321
- #
322
- # Converts self to HexaString
323
- #
324
- def to_hex
325
- HexaString.new(self.value)
295
+ end
296
+
297
+ unless scanner.skip(@@regexp_close)
298
+ raise InvalidLiteralStringObjectError, "Byte string shall be terminated with '#{TOKENS.last}'"
299
+ end
300
+
301
+ # Try to cast as a Date object if possible.
302
+ if result[0, 2] == 'D:'
303
+ begin
304
+ date = Date.parse(result)
305
+ date.file_offset = offset
306
+ return date
307
+ rescue InvalidDateError
326
308
  end
309
+ end
327
310
 
328
- #
329
- # Returns a standard String representation.
330
- #
331
- def value
332
- self.decrypt! if self.is_a?(Encryption::EncryptedString) and not @decrypted
311
+ bytestr = new(result)
312
+ bytestr.file_offset = offset
333
313
 
334
- to_str
335
- end
314
+ bytestr
315
+ end
336
316
 
337
- private
338
-
339
- def expand #:nodoc:
340
- self.gsub(/[\n\r\t\b\f()\\]/,
341
- "\n" => "\\n",
342
- "\r" => "\\r",
343
- "\t" => "\\t",
344
- "\b" => "\\b",
345
- "\f" => "\\f",
346
- "\\" => "\\\\",
347
- "(" => "\\(",
348
- ")" => "\\)")
349
- end
317
+ def to_s(eol: $/) # :nodoc:
318
+ super(TOKENS.first + expand + TOKENS.last, eol: eol)
350
319
  end
351
320
 
352
- class InvalidDateError < Error #:nodoc:
321
+ #
322
+ # Converts self to HexaString
323
+ #
324
+ def to_hex
325
+ HexaString.new(value)
353
326
  end
354
327
 
355
328
  #
356
- # Class representing a Date string.
329
+ # Returns a standard String representation.
357
330
  #
358
- class Date < LiteralString #:nodoc:
359
-
360
- REGEXP_TOKEN =
361
- /D: # Date header
362
- (?<year>\d{4}) # Year
363
- (?<month>\d{2})? # Month
364
- (?<day>\d{2})? # Day
365
- (?<hour>\d{2})? # Hour
366
- (?<min>\d{2})? # Minute
367
- (?<sec>\d{2})? # Second
368
- (?:
369
- (?<ut>[\+\-Z]) # UT relationship
370
- (?<ut_hour_off>\d{2}) # UT hour offset
371
- ('(?<ut_min_off>\d{2}))? # UT minute offset
372
- )?
373
- /x
374
-
375
- attr_reader :year, :month, :day, :hour, :min, :sec, :utc_offset
376
-
377
- def initialize(year:, month: 1, day: 1, hour: 0, min: 0, sec: 0, utc_offset: 0)
378
- @year, @month, @day, @hour, @min, @sec = year, month, day, hour, min, sec
379
- @utc_offset = utc_offset
380
-
381
- date = "D:%04d%02d%02d%02d%02d%02d" % [year, month, day, hour, min, sec ]
382
-
383
- if utc_offset == 0
384
- date << "Z00'00"
385
- else
386
- date << (if utc_offset < 0 then '-' else '+' end)
387
- off_hours, off_secs = utc_offset.abs.divmod(3600)
388
- off_mins = off_secs / 60
389
- date << "%02d'%02d" % [ off_hours, off_mins ]
390
- end
331
+ def value
332
+ decrypt! if is_a?(Encryption::EncryptedString) && !@decrypted
391
333
 
392
- super(date)
393
- end
334
+ to_str
335
+ end
394
336
 
395
- def to_datetime
396
- ::DateTime.new(@year, @month, @day, @hour, @min, @sec, (@utc_offset / 3600).to_s)
397
- end
337
+ private
338
+
339
+ def expand # :nodoc:
340
+ gsub(/[\n\r\t\b\f()\\]/,
341
+ "\n" => "\\n",
342
+ "\r" => "\\r",
343
+ "\t" => "\\t",
344
+ "\b" => "\\b",
345
+ "\f" => "\\f",
346
+ "\\" => "\\\\",
347
+ "(" => "\\(",
348
+ ")" => "\\)")
349
+ end
350
+ end
351
+
352
+ class InvalidDateError < Error # :nodoc:
353
+ end
354
+
355
+ #
356
+ # Class representing a Date string.
357
+ #
358
+ class Date < LiteralString # :nodoc:
359
+ REGEXP_TOKEN =
360
+ /D: # Date header
361
+ (?<year>\d{4}) # Year
362
+ (?<month>\d{2})? # Month
363
+ (?<day>\d{2})? # Day
364
+ (?<hour>\d{2})? # Hour
365
+ (?<min>\d{2})? # Minute
366
+ (?<sec>\d{2})? # Second
367
+ (?:
368
+ (?<ut>[\+\-Z]) # UT relationship
369
+ (?<ut_hour_off>\d{2}) # UT hour offset
370
+ ('(?<ut_min_off>\d{2}))? # UT minute offset
371
+ )?
372
+ /x
373
+
374
+ attr_reader :year, :month, :day, :hour, :min, :sec, :utc_offset
375
+
376
+ def initialize(year:, month: 1, day: 1, hour: 0, min: 0, sec: 0, utc_offset: 0)
377
+ @year, @month, @day, @hour, @min, @sec = year, month, day, hour, min, sec
378
+ @utc_offset = utc_offset
379
+
380
+ date = "D:%04d%02d%02d%02d%02d%02d" % [year, month, day, hour, min, sec]
381
+
382
+ if utc_offset == 0
383
+ date << "Z00'00"
384
+ else
385
+ date << ((utc_offset < 0) ? '-' : '+')
386
+ off_hours, off_secs = utc_offset.abs.divmod(3600)
387
+ off_mins = off_secs / 60
388
+ date << "%02d'%02d" % [off_hours, off_mins]
389
+ end
390
+
391
+ super(date)
392
+ end
398
393
 
399
- def self.parse(str) #:nodoc:
400
- raise InvalidDateError, "Not a valid Date string" unless str =~ REGEXP_TOKEN
394
+ def to_datetime
395
+ ::DateTime.new(@year, @month, @day, @hour, @min, @sec, (@utc_offset / 3600).to_s)
396
+ end
401
397
 
402
- date =
403
- {
404
- year: $~['year'].to_i
405
- }
398
+ def self.parse(str) # :nodoc:
399
+ raise InvalidDateError, "Not a valid Date string" unless str =~ REGEXP_TOKEN
406
400
 
407
- date[:month] = $~['month'].to_i if $~['month']
408
- date[:day] = $~['day'].to_i if $~['day']
409
- date[:hour] = $~['hour'].to_i if $~['hour']
410
- date[:min] = $~['min'].to_i if $~['min']
411
- date[:sec] = $~['sec'].to_i if $~['sec']
401
+ date =
402
+ {
403
+ year: $~['year'].to_i
404
+ }
412
405
 
413
- if %w[+ -].include?($~['ut'])
414
- utc_offset = $~['ut_hour_off'].to_i * 3600 + $~['ut_min_off'].to_i * 60
415
- utc_offset = -utc_offset if $~['ut'] == '-'
406
+ date[:month] = $~['month'].to_i if $~['month']
407
+ date[:day] = $~['day'].to_i if $~['day']
408
+ date[:hour] = $~['hour'].to_i if $~['hour']
409
+ date[:min] = $~['min'].to_i if $~['min']
410
+ date[:sec] = $~['sec'].to_i if $~['sec']
416
411
 
417
- date[:utc_offset] = utc_offset
418
- end
412
+ if %w[+ -].include?($~['ut'])
413
+ utc_offset = $~['ut_hour_off'].to_i * 3600 + $~['ut_min_off'].to_i * 60
414
+ utc_offset = -utc_offset if $~['ut'] == '-'
419
415
 
420
- Origami::Date.new(**date)
421
- end
416
+ date[:utc_offset] = utc_offset
417
+ end
422
418
 
423
- #
424
- # Returns current Date String in UTC time.
425
- #
426
- def self.now
427
- now = Time.now.utc
428
-
429
- date =
430
- {
431
- year: now.strftime("%Y").to_i,
432
- month: now.strftime("%m").to_i,
433
- day: now.strftime("%d").to_i,
434
- hour: now.strftime("%H").to_i,
435
- min: now.strftime("%M").to_i,
436
- sec: now.strftime("%S").to_i,
437
- utc_offset: now.utc_offset
438
- }
439
-
440
- Origami::Date.new(**date)
441
- end
419
+ Origami::Date.new(**date)
442
420
  end
443
421
 
422
+ #
423
+ # Returns current Date String in UTC time.
424
+ #
425
+ def self.now
426
+ now = Time.now.utc
427
+
428
+ date =
429
+ {
430
+ year: now.strftime("%Y").to_i,
431
+ month: now.strftime("%m").to_i,
432
+ day: now.strftime("%d").to_i,
433
+ hour: now.strftime("%H").to_i,
434
+ min: now.strftime("%M").to_i,
435
+ sec: now.strftime("%S").to_i,
436
+ utc_offset: now.utc_offset
437
+ }
438
+
439
+ Origami::Date.new(**date)
440
+ end
441
+ end
444
442
  end