origamindee 3.0.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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +89 -0
  3. data/COPYING.LESSER +165 -0
  4. data/README.md +131 -0
  5. data/bin/config/pdfcop.conf.yml +236 -0
  6. data/bin/pdf2pdfa +87 -0
  7. data/bin/pdf2ruby +333 -0
  8. data/bin/pdfcop +476 -0
  9. data/bin/pdfdecompress +97 -0
  10. data/bin/pdfdecrypt +91 -0
  11. data/bin/pdfencrypt +113 -0
  12. data/bin/pdfexplode +223 -0
  13. data/bin/pdfextract +277 -0
  14. data/bin/pdfmetadata +143 -0
  15. data/bin/pdfsh +12 -0
  16. data/bin/shell/console.rb +128 -0
  17. data/bin/shell/hexdump.rb +59 -0
  18. data/bin/shell/irbrc +69 -0
  19. data/examples/README.md +34 -0
  20. data/examples/attachments/attachment.rb +38 -0
  21. data/examples/attachments/nested_document.rb +51 -0
  22. data/examples/encryption/encryption.rb +28 -0
  23. data/examples/events/events.rb +72 -0
  24. data/examples/flash/flash.rb +37 -0
  25. data/examples/flash/helloworld.swf +0 -0
  26. data/examples/forms/javascript.rb +54 -0
  27. data/examples/forms/xfa.rb +115 -0
  28. data/examples/javascript/hello_world.rb +22 -0
  29. data/examples/javascript/js_emulation.rb +54 -0
  30. data/examples/loop/goto.rb +32 -0
  31. data/examples/loop/named.rb +33 -0
  32. data/examples/signature/signature.rb +65 -0
  33. data/examples/uri/javascript.rb +56 -0
  34. data/examples/uri/open-uri.rb +21 -0
  35. data/examples/uri/submitform.rb +47 -0
  36. data/lib/origami/3d.rb +364 -0
  37. data/lib/origami/acroform.rb +321 -0
  38. data/lib/origami/actions.rb +318 -0
  39. data/lib/origami/annotations.rb +711 -0
  40. data/lib/origami/array.rb +242 -0
  41. data/lib/origami/boolean.rb +90 -0
  42. data/lib/origami/catalog.rb +418 -0
  43. data/lib/origami/collections.rb +144 -0
  44. data/lib/origami/compound.rb +161 -0
  45. data/lib/origami/destinations.rb +252 -0
  46. data/lib/origami/dictionary.rb +192 -0
  47. data/lib/origami/encryption.rb +1084 -0
  48. data/lib/origami/extensions/fdf.rb +347 -0
  49. data/lib/origami/extensions/ppklite.rb +422 -0
  50. data/lib/origami/filespec.rb +197 -0
  51. data/lib/origami/filters/ascii.rb +211 -0
  52. data/lib/origami/filters/ccitt/tables.rb +267 -0
  53. data/lib/origami/filters/ccitt.rb +357 -0
  54. data/lib/origami/filters/crypt.rb +38 -0
  55. data/lib/origami/filters/dct.rb +54 -0
  56. data/lib/origami/filters/flate.rb +69 -0
  57. data/lib/origami/filters/jbig2.rb +57 -0
  58. data/lib/origami/filters/jpx.rb +47 -0
  59. data/lib/origami/filters/lzw.rb +170 -0
  60. data/lib/origami/filters/predictors.rb +292 -0
  61. data/lib/origami/filters/runlength.rb +129 -0
  62. data/lib/origami/filters.rb +364 -0
  63. data/lib/origami/font.rb +196 -0
  64. data/lib/origami/functions.rb +79 -0
  65. data/lib/origami/graphics/colors.rb +230 -0
  66. data/lib/origami/graphics/instruction.rb +98 -0
  67. data/lib/origami/graphics/path.rb +182 -0
  68. data/lib/origami/graphics/patterns.rb +174 -0
  69. data/lib/origami/graphics/render.rb +62 -0
  70. data/lib/origami/graphics/state.rb +149 -0
  71. data/lib/origami/graphics/text.rb +225 -0
  72. data/lib/origami/graphics/xobject.rb +918 -0
  73. data/lib/origami/graphics.rb +38 -0
  74. data/lib/origami/header.rb +75 -0
  75. data/lib/origami/javascript.rb +713 -0
  76. data/lib/origami/linearization.rb +330 -0
  77. data/lib/origami/metadata.rb +172 -0
  78. data/lib/origami/name.rb +135 -0
  79. data/lib/origami/null.rb +65 -0
  80. data/lib/origami/numeric.rb +181 -0
  81. data/lib/origami/obfuscation.rb +245 -0
  82. data/lib/origami/object.rb +760 -0
  83. data/lib/origami/optionalcontent.rb +183 -0
  84. data/lib/origami/outline.rb +54 -0
  85. data/lib/origami/outputintents.rb +85 -0
  86. data/lib/origami/page.rb +722 -0
  87. data/lib/origami/parser.rb +269 -0
  88. data/lib/origami/parsers/fdf.rb +56 -0
  89. data/lib/origami/parsers/pdf/lazy.rb +176 -0
  90. data/lib/origami/parsers/pdf/linear.rb +122 -0
  91. data/lib/origami/parsers/pdf.rb +118 -0
  92. data/lib/origami/parsers/ppklite.rb +57 -0
  93. data/lib/origami/pdf.rb +1108 -0
  94. data/lib/origami/reference.rb +134 -0
  95. data/lib/origami/signature.rb +702 -0
  96. data/lib/origami/stream.rb +705 -0
  97. data/lib/origami/string.rb +444 -0
  98. data/lib/origami/template/patterns.rb +56 -0
  99. data/lib/origami/template/widgets.rb +151 -0
  100. data/lib/origami/trailer.rb +190 -0
  101. data/lib/origami/tree.rb +62 -0
  102. data/lib/origami/version.rb +23 -0
  103. data/lib/origami/webcapture.rb +100 -0
  104. data/lib/origami/xfa/config.rb +453 -0
  105. data/lib/origami/xfa/connectionset.rb +146 -0
  106. data/lib/origami/xfa/datasets.rb +49 -0
  107. data/lib/origami/xfa/localeset.rb +42 -0
  108. data/lib/origami/xfa/package.rb +59 -0
  109. data/lib/origami/xfa/pdf.rb +73 -0
  110. data/lib/origami/xfa/signature.rb +42 -0
  111. data/lib/origami/xfa/sourceset.rb +43 -0
  112. data/lib/origami/xfa/stylesheet.rb +44 -0
  113. data/lib/origami/xfa/template.rb +1691 -0
  114. data/lib/origami/xfa/xdc.rb +42 -0
  115. data/lib/origami/xfa/xfa.rb +146 -0
  116. data/lib/origami/xfa/xfdf.rb +43 -0
  117. data/lib/origami/xfa/xmpmeta.rb +43 -0
  118. data/lib/origami/xfa.rb +62 -0
  119. data/lib/origami/xreftable.rb +557 -0
  120. data/lib/origami.rb +47 -0
  121. data/test/dataset/calc.pdf +85 -0
  122. data/test/dataset/crypto.pdf +36 -0
  123. data/test/dataset/empty.pdf +49 -0
  124. data/test/test_actions.rb +27 -0
  125. data/test/test_annotations.rb +68 -0
  126. data/test/test_forms.rb +30 -0
  127. data/test/test_native_types.rb +83 -0
  128. data/test/test_object_tree.rb +33 -0
  129. data/test/test_pages.rb +60 -0
  130. data/test/test_pdf.rb +20 -0
  131. data/test/test_pdf_attachment.rb +34 -0
  132. data/test/test_pdf_create.rb +24 -0
  133. data/test/test_pdf_encrypt.rb +102 -0
  134. data/test/test_pdf_parse.rb +134 -0
  135. data/test/test_pdf_parse_lazy.rb +69 -0
  136. data/test/test_pdf_sign.rb +97 -0
  137. data/test/test_streams.rb +184 -0
  138. data/test/test_xrefs.rb +67 -0
  139. metadata +280 -0
@@ -0,0 +1,422 @@
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
20
+
21
+ require 'origami/object'
22
+ require 'origami/name'
23
+ require 'origami/dictionary'
24
+ require 'origami/reference'
25
+ require 'origami/boolean'
26
+ require 'origami/numeric'
27
+ require 'origami/string'
28
+ require 'origami/array'
29
+ require 'origami/trailer'
30
+ require 'origami/xreftable'
31
+
32
+ require 'origami/parsers/ppklite'
33
+
34
+ require 'openssl'
35
+
36
+ module Origami
37
+
38
+ #
39
+ # Class representing an Adobe Reader certificate store.
40
+ #
41
+ class PPKLite
42
+
43
+ class Error < Origami::Error; end
44
+
45
+ def self.read(path, options = {})
46
+ path = File.expand_path(path) if path.is_a?(::String)
47
+
48
+ PPKLite::Parser.new(options).parse(path)
49
+ end
50
+
51
+ #
52
+ # Class representing a certificate store header.
53
+ #
54
+ class Header
55
+ MAGIC = /%PPKLITE-(?<major>\d)\.(?<minor>\d)/
56
+
57
+ attr_accessor :major_version, :minor_version
58
+
59
+ #
60
+ # Creates a file header, with the given major and minor versions.
61
+ # _major_version_:: Major version.
62
+ # _minor_version_:: Minor version.
63
+ #
64
+ def initialize(major_version = 2, minor_version = 1)
65
+ @major_version, @minor_version = major_version, minor_version
66
+ end
67
+
68
+ def self.parse(stream) #:nodoc:
69
+ scanner = Parser.init_scanner(stream)
70
+
71
+ if not scanner.scan(MAGIC).nil?
72
+ maj = scanner['major'].to_i
73
+ min = scanner['minor'].to_i
74
+ else
75
+ raise InvalidHeader, "Invalid header format"
76
+ end
77
+
78
+ scanner.skip(REGEXP_WHITESPACES)
79
+
80
+ PPKLite::Header.new(maj, min)
81
+ end
82
+
83
+ #
84
+ # Outputs self into PDF code.
85
+ #
86
+ def to_s(eol: $/)
87
+ "%PPKLITE-#{@major_version}.#{@minor_version}".b + eol
88
+ end
89
+
90
+ def to_sym #:nodoc:
91
+ "#{@major_version}.#{@minor_version}".to_sym
92
+ end
93
+
94
+ def to_f #:nodoc:
95
+ to_sym.to_s.to_f
96
+ end
97
+ end
98
+
99
+ class Revision #:nodoc;
100
+ attr_accessor :document
101
+ attr_accessor :body, :xreftable
102
+ attr_reader :trailer
103
+
104
+ def initialize(adbk)
105
+ @document = adbk
106
+ @body = {}
107
+ @xreftable = nil
108
+ @trailer = nil
109
+ end
110
+
111
+ def trailer=(trl)
112
+ trl.document = @document
113
+ @trailer = trl
114
+ end
115
+
116
+ def each_object(&b)
117
+ @body.each_value(&b)
118
+ end
119
+
120
+ def objects
121
+ @body.values
122
+ end
123
+ end
124
+
125
+ module Descriptor
126
+ CERTIFICATE = 1
127
+ USER = 2
128
+
129
+ def self.included(receiver) #:nodoc:
130
+ receiver.field :ID, :Type => Integer, :Required => true
131
+ receiver.field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
132
+ end
133
+ end
134
+
135
+ class Certificate < Dictionary
136
+ include StandardObject
137
+ include Descriptor
138
+
139
+ add_type_signature :ABEType => Descriptor::CERTIFICATE
140
+
141
+ module Flags
142
+ CAN_CERTIFY = 1 << 1
143
+ ALLOW_DYNAMIC_CONTENT = 1 << 2
144
+ UNKNOWN_1 = 1 << 3
145
+ ALLOW_HIGH_PRIV_JS = 1 << 4
146
+ UNKNOWN_2 = 1 << 5
147
+ IS_ROOT_CA = 1 << 6
148
+
149
+ #FULL_TRUST = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6
150
+ FULL_TRUST = 8190
151
+ end
152
+
153
+ field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
154
+ field :Usage, :Type => Integer, :Default => 1, :Required => true
155
+ field :Viewable, :Type => Boolean, :Default => true
156
+ field :Editable, :Type => Boolean, :Default => true
157
+ field :Cert, :Type => String, :Required => true
158
+ field :Trust, :Type => Integer, :Default => Flags::UNKNOWN_2, :Required => true
159
+ end
160
+
161
+ class User < Dictionary
162
+ include StandardObject
163
+ include Descriptor
164
+
165
+ add_type_signature :ABEType => Descriptor::USER
166
+
167
+ field :ABEType, :Type => Integer, :Default => Descriptor::USER, :Required => true
168
+ field :Name, :Type => String, :Required => true
169
+ field :Encrypt, :Type => Integer
170
+ field :Certs, :Type => Array.of(Certificate), :Default => [], :Required => true
171
+ end
172
+
173
+ class AddressList < Dictionary
174
+ include StandardObject
175
+
176
+ field :Type, :Type => Name, :Default => :AddressBook, :Required => true
177
+ field :NextID, :Type => Integer
178
+ field :Entries, :Type => Array.of(Descriptor), :Default => [], :Required => true
179
+ end
180
+
181
+ class UserList < Dictionary
182
+ include StandardObject
183
+
184
+ field :Type, :Type => Name, :Default => :User, :Required => true
185
+ end
186
+
187
+ class PPK < Dictionary
188
+ include StandardObject
189
+
190
+ field :Type, :Type => Name, :Default => :PPK, :Required => true
191
+ field :User, :Type => UserList, :Required => true
192
+ field :AddressBook, :Type => AddressList, :Required => true
193
+ field :V, :Type => Integer, :Default => 0x10001, :Required => true
194
+ end
195
+
196
+ class Catalog < Dictionary
197
+ include StandardObject
198
+
199
+ field :Type, :Type => Name, :Default => :Catalog, :Required => true
200
+ field :PPK, :Type => PPK, :Required => true
201
+ end
202
+
203
+ attr_accessor :header, :revisions
204
+
205
+ def initialize(parser = nil) #:nodoc:
206
+ @header = PPKLite::Header.new
207
+ @revisions = [ Revision.new(self) ]
208
+ @revisions.first.trailer = Trailer.new
209
+ @parser = parser
210
+
211
+ init if parser.nil?
212
+ end
213
+
214
+ def indirect_objects
215
+ @revisions.inject([]) do |set, rev| set.concat(rev.objects) end
216
+ end
217
+ alias root_objects indirect_objects
218
+
219
+ def cast_object(reference, type) #:nodoc:
220
+ @revisions.each do |rev|
221
+ if rev.body.include?(reference) and type < rev.body[reference].class
222
+ rev.body[reference] = rev.body[reference].cast_to(type, @parser)
223
+
224
+ rev.body[reference]
225
+ else
226
+ nil
227
+ end
228
+ end
229
+ end
230
+
231
+ def get_object(no, generation = 0) #:nodoc:
232
+ case no
233
+ when Reference
234
+ target = no
235
+ when ::Integer
236
+ target = Reference.new(no, generation)
237
+ when Origami::Object
238
+ return no
239
+ end
240
+
241
+ @revisions.first.body[target]
242
+ end
243
+
244
+ def <<(object)
245
+ object.set_indirect(true)
246
+ object.set_document(self)
247
+
248
+ if object.no.zero?
249
+ maxno = 1
250
+ maxno = maxno.succ while get_object(maxno)
251
+
252
+ object.generation = 0
253
+ object.no = maxno
254
+ end
255
+
256
+ @revisions.first.body[object.reference] = object
257
+
258
+ object.reference
259
+ end
260
+ alias insert <<
261
+
262
+ def Catalog
263
+ get_object(@revisions.first.trailer.Root)
264
+ end
265
+
266
+ def save(path)
267
+ bin = "".b
268
+ bin << @header.to_s
269
+
270
+ lastno, brange = 0, 0
271
+
272
+ xrefs = [ XRef.new(0, XRef::FIRSTFREE, XRef::FREE) ]
273
+ xrefsection = XRef::Section.new
274
+
275
+ @revisions.first.body.values.sort.each { |obj|
276
+ if (obj.no - lastno).abs > 1
277
+ xrefsection << XRef::Subsection.new(brange, xrefs)
278
+ brange = obj.no
279
+ xrefs.clear
280
+ end
281
+
282
+ xrefs << XRef.new(bin.size, obj.generation, XRef::USED)
283
+ lastno = obj.no
284
+
285
+ obj.pre_build
286
+
287
+ bin << obj.to_s
288
+
289
+ obj.post_build
290
+ }
291
+
292
+ xrefsection << XRef::Subsection.new(brange, xrefs)
293
+
294
+ @xreftable = xrefsection
295
+ @trailer ||= Trailer.new
296
+ @trailer.Size = @revisions.first.body.size + 1
297
+ @trailer.startxref = bin.size
298
+
299
+ bin << @xreftable.to_s
300
+ bin << @trailer.to_s
301
+
302
+ if path.respond_to?(:write)
303
+ io = path
304
+ else
305
+ path = File.expand_path(path)
306
+ io = File.open(path, "wb", encoding: 'binary')
307
+ close = true
308
+ end
309
+
310
+ begin
311
+ io.write(bin)
312
+ ensure
313
+ io.close if close
314
+ end
315
+
316
+ self
317
+ end
318
+
319
+ def each_user(&b)
320
+ each_entry(Descriptor::USER, &b)
321
+ end
322
+
323
+ def get_user(id)
324
+ self.each_user.find {|user| user.ID == id }
325
+ end
326
+
327
+ def users
328
+ self.each_user.to_a
329
+ end
330
+
331
+ def each_certificate(&b)
332
+ each_entry(Descriptor::CERTIFICATE, &b)
333
+ end
334
+
335
+ def get_certificate(id)
336
+ self.each_certificate.find {|cert| cert.ID == id }
337
+ end
338
+
339
+ def certificates
340
+ self.each_certificate.to_a
341
+ end
342
+
343
+ #
344
+ # Add a certificate into the address book
345
+ #
346
+ def add_certificate(certfile, attributes, viewable: false, editable: false)
347
+ if certfile.is_a?(OpenSSL::X509::Certificate)
348
+ x509 = certfile
349
+ else
350
+ x509 = OpenSSL::X509::Certificate.new(certfile)
351
+ end
352
+
353
+ address_book = get_address_book
354
+
355
+ cert = Certificate.new
356
+ cert.Cert = x509.to_der
357
+ cert.ID = address_book.NextID
358
+ address_book.NextID += 1
359
+
360
+ cert.Trust = attributes
361
+ cert.Viewable = viewable
362
+ cert.Editable = editable
363
+
364
+ address_book.Entries.push(self << cert)
365
+ end
366
+
367
+ private
368
+
369
+ def init
370
+ catalog = Catalog.new(
371
+ PPK: PPK.new(
372
+ User: UserList.new,
373
+ AddressBook: AddressList.new(
374
+ Entries: [],
375
+ NextID: 1
376
+ )
377
+ )
378
+ )
379
+
380
+ @revisions.first.trailer.Root = self.insert(catalog)
381
+ end
382
+
383
+ def each_entry(type)
384
+ return enum_for(__method__, type) unless block_given?
385
+
386
+ address_book = get_address_book
387
+
388
+ address_book.Entries.each do |entry|
389
+ entry = entry.solve
390
+
391
+ yield(entry) if entry.is_a?(Dictionary) and entry.ABEType == type
392
+ end
393
+ end
394
+
395
+ def get_address_book
396
+ raise Error, "Broken catalog" unless self.Catalog.is_a?(Dictionary) and self.Catalog.PPK.is_a?(Dictionary)
397
+
398
+ ppk = self.Catalog.PPK
399
+ raise Error, "Broken PPK" unless ppk.AddressBook.is_a?(Dictionary)
400
+
401
+ address_book = ppk.AddressBook
402
+ raise Error, "Broken address book" unless address_book.Entries.is_a?(Array)
403
+
404
+ address_book
405
+ end
406
+
407
+ def get_object_offset(no,generation) #:nodoc:
408
+ bodyoffset = @header.to_s.size
409
+ objectoffset = bodyoffset
410
+
411
+ @revisions.first.body.values.each { |object|
412
+ if object.no == no and object.generation == generation then return objectoffset
413
+ else
414
+ objectoffset += object.to_s.size
415
+ end
416
+ }
417
+
418
+ nil
419
+ end
420
+
421
+ end
422
+ end
@@ -0,0 +1,197 @@
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
20
+
21
+ module Origami
22
+
23
+ class PDF
24
+
25
+ #
26
+ # Attachs an embedded file to the PDF.
27
+ # _path_:: The path to the file to attach.
28
+ # _register_:: Whether the file shall be registered in the name directory.
29
+ # _name_:: The embedded file name of the attachment.
30
+ # _filter_:: The stream filter used to store the file contents.
31
+ #
32
+ def attach_file(path, register: true, name: nil, filter: :FlateDecode)
33
+
34
+ if path.is_a? FileSpec
35
+ filespec = path
36
+ name ||= ''
37
+ else
38
+ if path.respond_to?(:read)
39
+ data = path.read.force_encoding('binary')
40
+ name ||= ''
41
+ else
42
+ data = File.binread(File.expand_path(path))
43
+ name ||= File.basename(path)
44
+ end
45
+
46
+ fstream = EmbeddedFileStream.new
47
+ fstream.data = data
48
+
49
+ fstream.Filter = filter
50
+ filespec = FileSpec.new(:F => fstream)
51
+ end
52
+
53
+ fspec = FileSpec.new.setType(:Filespec).setF(name.dup).setEF(filespec)
54
+
55
+ self.register(
56
+ Names::EMBEDDED_FILES,
57
+ name.dup,
58
+ fspec
59
+ ) if register
60
+
61
+ fspec
62
+ end
63
+
64
+ #
65
+ # Lookup embedded file in the embedded files name directory.
66
+ #
67
+ def get_embedded_file_by_name(name)
68
+ resolve_name Names::EMBEDDED_FILES, name
69
+ end
70
+
71
+ #
72
+ # Calls block for each named embedded file.
73
+ #
74
+ def each_named_embedded_file(&b)
75
+ each_name(Names::EMBEDDED_FILES, &b)
76
+ end
77
+ alias each_attachment each_named_embedded_file
78
+ end
79
+
80
+ #
81
+ # Class used to convert system-dependent pathes into PDF pathes.
82
+ # PDF path specification offers a single form for representing file pathes over operating systems.
83
+ #
84
+ class Filename
85
+
86
+ class << self
87
+ #
88
+ # Converts UNIX file path into PDF file path.
89
+ #
90
+ def Unix(file)
91
+ LiteralString.new(file)
92
+ end
93
+
94
+ #
95
+ # Converts MacOS file path into PDF file path.
96
+ #
97
+ def Mac(file)
98
+ LiteralString.new("/" + file.tr(":", "/"))
99
+ end
100
+
101
+ #
102
+ # Converts Windows file path into PDF file path.
103
+ #
104
+ def DOS(file)
105
+ path = ""
106
+ # Absolute vs relative path
107
+ if file.include? ":"
108
+ path << "/"
109
+ file.sub!(":","")
110
+ end
111
+
112
+ file.tr!("\\", "/")
113
+ LiteralString.new(path + file)
114
+ end
115
+ end
116
+ end
117
+
118
+ #
119
+ # Class representing a file specification.
120
+ # File specifications can be used to reference external files, as well as embedded files and URIs.
121
+ #
122
+ class FileSpec < Dictionary
123
+ include StandardObject
124
+
125
+ field :Type, :Type => Name, :Default => :FileSpec
126
+ field :FS, :Type => Name, :Default => :URL
127
+ field :F, :Type => [ String, Stream ]
128
+ field :UF, :Type => String
129
+ field :DOS, :Type => String
130
+ field :Mac, :Type => String
131
+ field :Unix, :Type => String
132
+ field :ID, :Type => Array
133
+ field :V, :Type => Boolean, :Default => false, :Version => "1.2"
134
+ field :EF, :Type => Dictionary, :Version => "1.3"
135
+ field :RF, :Type => Dictionary, :Version => "1.3"
136
+ field :Desc, :Type => String, :Version => "1.6"
137
+ field :CI, :Type => Dictionary, :Version => "1.7"
138
+ field :Thumb, :Type => Stream, :Version => "1.7", :ExtensionLevel => 3
139
+ end
140
+
141
+ #
142
+ # Class representing a Uniform Resource Locator (URL)
143
+ #
144
+ class URL < FileSpec
145
+ field :Type, :Type => Name, :Default => :URL, :Required => true
146
+
147
+ def initialize(url)
148
+ super(:F => url)
149
+ end
150
+ end
151
+
152
+ #
153
+ # A class representing a file outside the current PDF file.
154
+ #
155
+ class ExternalFile < FileSpec
156
+ field :Type, :Type => Name, :Default => :FileSpec #, :Required => true
157
+
158
+ #
159
+ # Creates a new external file specification.
160
+ # _dos_:: The Windows path to this file.
161
+ # _mac_:: The MacOS path to this file.
162
+ # _unix_:: The UNIX path to this file.
163
+ #
164
+ def initialize(dos, mac: "", unix: "")
165
+ if not mac.empty? or not unix.empty?
166
+ super(:DOS => Filename.DOS(dos), :Mac => Filename.Mac(mac), :Unix => Filename.Unix(unix))
167
+ else
168
+ super(:F => dos)
169
+ end
170
+ end
171
+ end
172
+
173
+ #
174
+ # Class representing parameters for a EmbeddedFileStream.
175
+ #
176
+ class EmbeddedFileParameters < Dictionary
177
+ include StandardObject
178
+
179
+ field :Size, :Type => Integer
180
+ field :CreationDate, :Type => String
181
+ field :ModDate, :Type => String
182
+ field :Mac, :Type => Dictionary
183
+ field :Checksum, :Type => String
184
+ end
185
+
186
+ #
187
+ # Class representing the data of an embedded file.
188
+ #
189
+ class EmbeddedFileStream < Stream
190
+ include StandardObject
191
+
192
+ field :Type, :Type => Name, :Default => :EmbeddedFile
193
+ field :Subtype, :Type => Name
194
+ field :Params, :Type => EmbeddedFileParameters
195
+ end
196
+
197
+ end