origami 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/COPYING.LESSER +165 -0
  2. data/README +77 -0
  3. data/VERSION +1 -0
  4. data/bin/config/pdfcop.conf.yml +237 -0
  5. data/bin/gui/about.rb +46 -0
  6. data/bin/gui/config.rb +132 -0
  7. data/bin/gui/file.rb +385 -0
  8. data/bin/gui/hexdump.rb +74 -0
  9. data/bin/gui/hexview.rb +91 -0
  10. data/bin/gui/imgview.rb +72 -0
  11. data/bin/gui/menu.rb +392 -0
  12. data/bin/gui/properties.rb +132 -0
  13. data/bin/gui/signing.rb +635 -0
  14. data/bin/gui/textview.rb +107 -0
  15. data/bin/gui/treeview.rb +409 -0
  16. data/bin/gui/walker.rb +282 -0
  17. data/bin/gui/xrefs.rb +79 -0
  18. data/bin/pdf2graph +121 -0
  19. data/bin/pdf2ruby +353 -0
  20. data/bin/pdfcocoon +104 -0
  21. data/bin/pdfcop +455 -0
  22. data/bin/pdfdecompress +104 -0
  23. data/bin/pdfdecrypt +95 -0
  24. data/bin/pdfencrypt +112 -0
  25. data/bin/pdfextract +221 -0
  26. data/bin/pdfmetadata +123 -0
  27. data/bin/pdfsh +13 -0
  28. data/bin/pdfwalker +7 -0
  29. data/bin/shell/.irbrc +104 -0
  30. data/bin/shell/console.rb +136 -0
  31. data/bin/shell/hexdump.rb +83 -0
  32. data/origami.rb +36 -0
  33. data/origami/3d.rb +239 -0
  34. data/origami/acroform.rb +321 -0
  35. data/origami/actions.rb +299 -0
  36. data/origami/adobe/fdf.rb +259 -0
  37. data/origami/adobe/ppklite.rb +489 -0
  38. data/origami/annotations.rb +775 -0
  39. data/origami/array.rb +187 -0
  40. data/origami/boolean.rb +101 -0
  41. data/origami/catalog.rb +486 -0
  42. data/origami/destinations.rb +213 -0
  43. data/origami/dictionary.rb +188 -0
  44. data/origami/docmdp.rb +96 -0
  45. data/origami/encryption.rb +1293 -0
  46. data/origami/export.rb +283 -0
  47. data/origami/file.rb +222 -0
  48. data/origami/filters.rb +250 -0
  49. data/origami/filters/ascii.rb +189 -0
  50. data/origami/filters/ccitt.rb +515 -0
  51. data/origami/filters/crypt.rb +47 -0
  52. data/origami/filters/dct.rb +61 -0
  53. data/origami/filters/flate.rb +112 -0
  54. data/origami/filters/jbig2.rb +63 -0
  55. data/origami/filters/jpx.rb +53 -0
  56. data/origami/filters/lzw.rb +195 -0
  57. data/origami/filters/predictors.rb +276 -0
  58. data/origami/filters/runlength.rb +117 -0
  59. data/origami/font.rb +209 -0
  60. data/origami/functions.rb +93 -0
  61. data/origami/graphics.rb +33 -0
  62. data/origami/graphics/colors.rb +191 -0
  63. data/origami/graphics/instruction.rb +126 -0
  64. data/origami/graphics/path.rb +154 -0
  65. data/origami/graphics/patterns.rb +180 -0
  66. data/origami/graphics/state.rb +164 -0
  67. data/origami/graphics/text.rb +224 -0
  68. data/origami/graphics/xobject.rb +493 -0
  69. data/origami/header.rb +90 -0
  70. data/origami/linearization.rb +318 -0
  71. data/origami/metadata.rb +114 -0
  72. data/origami/name.rb +170 -0
  73. data/origami/null.rb +75 -0
  74. data/origami/numeric.rb +188 -0
  75. data/origami/obfuscation.rb +233 -0
  76. data/origami/object.rb +527 -0
  77. data/origami/outline.rb +59 -0
  78. data/origami/page.rb +559 -0
  79. data/origami/parser.rb +268 -0
  80. data/origami/parsers/fdf.rb +45 -0
  81. data/origami/parsers/pdf.rb +27 -0
  82. data/origami/parsers/pdf/linear.rb +113 -0
  83. data/origami/parsers/ppklite.rb +86 -0
  84. data/origami/pdf.rb +1144 -0
  85. data/origami/reference.rb +113 -0
  86. data/origami/signature.rb +474 -0
  87. data/origami/stream.rb +575 -0
  88. data/origami/string.rb +416 -0
  89. data/origami/trailer.rb +173 -0
  90. data/origami/webcapture.rb +87 -0
  91. data/origami/xfa.rb +3027 -0
  92. data/origami/xreftable.rb +447 -0
  93. data/templates/patterns.rb +66 -0
  94. data/templates/widgets.rb +173 -0
  95. data/templates/xdp.rb +92 -0
  96. data/tests/dataset/test.dummycrt +28 -0
  97. data/tests/dataset/test.dummykey +27 -0
  98. data/tests/tc_actions.rb +32 -0
  99. data/tests/tc_annotations.rb +85 -0
  100. data/tests/tc_pages.rb +37 -0
  101. data/tests/tc_pdfattach.rb +24 -0
  102. data/tests/tc_pdfencrypt.rb +110 -0
  103. data/tests/tc_pdfnew.rb +32 -0
  104. data/tests/tc_pdfparse.rb +98 -0
  105. data/tests/tc_pdfsig.rb +37 -0
  106. data/tests/tc_streams.rb +129 -0
  107. data/tests/ts_pdf.rb +45 -0
  108. metadata +193 -0
@@ -0,0 +1,527 @@
1
+ =begin
2
+
3
+ = File
4
+ object.rb
5
+
6
+ = Info
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
+ =end
21
+
22
+ class Bignum #:nodoc:
23
+ def to_o
24
+ Origami::Integer.new(self)
25
+ end
26
+ end
27
+
28
+ class Fixnum #:nodoc:
29
+ def to_o
30
+ Origami::Integer.new(self)
31
+ end
32
+ end
33
+
34
+ class Array #:nodoc:
35
+ def to_o
36
+ Origami::Array.new(self)
37
+ end
38
+
39
+ def shuffle
40
+ sort_by { rand }
41
+ end
42
+
43
+ def shuffle!
44
+ self.replace shuffle
45
+ end
46
+ end
47
+
48
+ class Float #:nodoc:
49
+ def to_o
50
+ Origami::Real.new(self)
51
+ end
52
+ end
53
+
54
+ class Hash #:nodoc:
55
+ def to_o
56
+ Origami::Dictionary.new(self)
57
+ end
58
+ end
59
+
60
+ class TrueClass #:nodoc:
61
+ def to_o
62
+ Origami::Boolean.new(true)
63
+ end
64
+ end
65
+
66
+ class FalseClass #:nodoc:
67
+ def to_o
68
+ Origami::Boolean.new(false)
69
+ end
70
+ end
71
+
72
+ class NilClass #:nodoc:
73
+ def to_o
74
+ Origami::Null.new
75
+ end
76
+ end
77
+
78
+ class Symbol #:nodoc:
79
+ def to_o
80
+ Origami::Name.new(self)
81
+ end
82
+
83
+ def value
84
+ self
85
+ end
86
+
87
+ end
88
+
89
+ class String #:nodoc:
90
+ def to_o
91
+ Origami::ByteString.new(self)
92
+ end
93
+
94
+ def is_binary_data?
95
+ ( self.count( "\x00" ) > 0 ) unless empty?
96
+ end
97
+ end
98
+
99
+ #
100
+ # Module for parsing/generating PDF files.
101
+ #
102
+ module Origami
103
+
104
+ #
105
+ # Mixin' module for objects which can store their options into an inner Dictionary.
106
+ #
107
+ module StandardObject #:nodoc:
108
+
109
+ DEFAULT_ATTRIBUTES = { :Type => Object, :Version => "1.1" } #:nodoc:
110
+
111
+ def self.included(receiver) #:nodoc:
112
+ receiver.instance_variable_set(:@fields, Hash.new(DEFAULT_ATTRIBUTES))
113
+ receiver.extend(ClassMethods)
114
+ end
115
+
116
+ module ClassMethods #:nodoc:all
117
+
118
+ def inherited(subclass)
119
+ subclass.instance_variable_set(:@fields, Marshal.load(Marshal.dump(@fields)))
120
+ end
121
+
122
+ def fields
123
+ @fields
124
+ end
125
+
126
+ def field(name, attributes)
127
+
128
+ if not @fields.has_key?(name)
129
+ @fields[name] = attributes
130
+ else
131
+ @fields[name].merge! attributes
132
+ end
133
+
134
+ define_field_methods(name)
135
+ end
136
+
137
+ def define_field_methods(field)
138
+ reader = lambda { obj = self[field]; obj.is_a?(Reference) ? obj.solve : obj }
139
+ writer = lambda { |value| self[field] = value }
140
+ set = lambda { |value| self[field] = value; self }
141
+
142
+ send(:define_method, field.id2name, reader)
143
+ send(:define_method, field.id2name + "=", writer)
144
+ send(:define_method, "set" + field.id2name, set)
145
+ end
146
+
147
+ #
148
+ # Returns an array of required fields for the current Object.
149
+ #
150
+ def required_fields
151
+ fields = []
152
+ @fields.each_pair { |name, attributes|
153
+ fields << name if attributes[:Required] == true
154
+ }
155
+
156
+ fields
157
+ end
158
+
159
+ end
160
+
161
+ def pre_build #:nodoc:
162
+
163
+ set_default_values
164
+ do_type_check if Origami::OPTIONS[:enable_type_checking] == true
165
+
166
+ super
167
+ end
168
+
169
+ #
170
+ # Check if an attribute is set in the current Object.
171
+ # _attr_:: The attribute name.
172
+ #
173
+ def has_field? (field)
174
+ not self[field].nil?
175
+ end
176
+
177
+ #
178
+ # Returns the version and level required by the current Object.
179
+ #
180
+ def pdf_version_required #:nodoc:
181
+ max = [ 1.0, 0 ]
182
+
183
+ self.each_key do |field|
184
+ attributes = self.class.fields[field.value]
185
+
186
+ current_version = attributes.has_key?(:Version) ? attributes[:Version].to_f : 0
187
+ current_level = attributes[:ExtensionLevel] || 0
188
+ current = [ current_version, current_level ]
189
+
190
+ max = current if (current <=> max) > 0
191
+
192
+ sub = self[field.value].pdf_version_required
193
+ max = sub if (sub <=> max) > 0
194
+ end
195
+
196
+ max
197
+ end
198
+
199
+ def set_default_value(field) #:nodoc:
200
+ if self.class.fields[field][:Default]
201
+ self[field] = self.class.fields[field][:Default]
202
+ self[field].pre_build
203
+ end
204
+ end
205
+
206
+ def set_default_values #:nodoc:
207
+ self.class.required_fields.each do |field|
208
+ set_default_value(field) unless has_field?(field)
209
+ end
210
+ end
211
+
212
+ def do_type_check #:nodoc:
213
+ self.class.fields.each_pair do |field, attributes|
214
+
215
+ if not self[field].nil? and not attributes[:Type].nil?
216
+ types = attributes[:Type].is_a?(::Array) ? attributes[:Type] : [ attributes[:Type] ]
217
+ if not self[field].is_a?(Reference) and types.all? {|type| not self[field].is_a?(type)}
218
+ puts "Warning: in object #{self.class}, field `#{field.to_s}' has unexpected type #{self[field].class}"
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ end
225
+
226
+ class InvalidObjectError < Exception #:nodoc:
227
+ end
228
+
229
+ class UnterminatedObjectError < Exception #:nodoc:
230
+ attr_reader :obj
231
+ def initialize(msg,obj)
232
+ super(msg)
233
+ @obj = obj
234
+ end
235
+ end
236
+
237
+ #
238
+ # Parent module representing a PDF Object.
239
+ # PDF specification declares a set of primitive object types :
240
+ # * Null
241
+ # * Boolean
242
+ # * Integer
243
+ # * Real
244
+ # * Name
245
+ # * String
246
+ # * Array
247
+ # * Dictionary
248
+ # * Stream
249
+ #
250
+ module Object
251
+
252
+ TOKENS = %w{ obj endobj } #:nodoc:
253
+
254
+ @@regexp_obj = Regexp.new(WHITESPACES + "(\\d+)" + WHITESPACES + "(\\d+)" + WHITESPACES + TOKENS.first + WHITESPACES)
255
+ @@regexp_endobj = Regexp.new(WHITESPACES + TOKENS.last + WHITESPACES)
256
+
257
+ attr_accessor :no, :generation, :file_offset, :objstm_offset
258
+ attr_accessor :parent
259
+
260
+ #
261
+ # Creates a new PDF Object.
262
+ #
263
+ def initialize(*cons)
264
+ @indirect = false
265
+ @no, @generation = 0, 0
266
+
267
+ super(*cons) unless cons.empty?
268
+ end
269
+
270
+ #
271
+ # Sets whether the object is indirect or not.
272
+ # Indirect objects are allocated numbers at build time.
273
+ #
274
+ def set_indirect(dir)
275
+ unless dir == true or dir == false
276
+ raise TypeError, "The argument must be boolean"
277
+ end
278
+
279
+ @indirect = dir
280
+ self
281
+ end
282
+
283
+ #
284
+ # Generic method called just before the object is finalized.
285
+ # At this time, no number nor generation allocation has yet been done.
286
+ #
287
+ def pre_build
288
+ self
289
+ end
290
+
291
+ #
292
+ # Generic method called just after the object is finalized.
293
+ # At this time, any indirect object has its own number and generation identifier.
294
+ #
295
+ def post_build
296
+ self
297
+ end
298
+
299
+ #
300
+ # Compare two objects from their respective numbers.
301
+ #
302
+ def <=>(obj)
303
+ [@no, @generation] <=> [obj.no, obj.generation]
304
+ end
305
+
306
+ #
307
+ # Returns whether the objects is indirect, which means that it is not embedded into another object.
308
+ #
309
+ def is_indirect?
310
+ @indirect
311
+ end
312
+
313
+ #
314
+ # Deep copy of an object.
315
+ #
316
+ def copy
317
+ Marshal.load(Marshal.dump(self))
318
+ end
319
+
320
+ #
321
+ # Returns an indirect reference to this object, or a Null object is this object is not indirect.
322
+ #
323
+ def reference
324
+ unless self.is_indirect?
325
+ raise InvalidObjectError, "Cannot reference a direct object"
326
+ end
327
+
328
+ ref = Reference.new(@no, @generation)
329
+ ref.parent = self
330
+
331
+ ref
332
+ end
333
+
334
+ #
335
+ # Returns an array of references pointing to the current object.
336
+ #
337
+ def xrefs
338
+ unless self.is_indirect?
339
+ raise InvalidObjectError, "Cannot find xrefs to a direct object"
340
+ end
341
+
342
+ if self.pdf.nil?
343
+ raise InvalidObjectError, "Not attached to any PDF"
344
+ end
345
+
346
+ xref_cache = Hash.new([])
347
+ @pdf.root_objects.each do |obj|
348
+ case obj
349
+ when Dictionary,Array then
350
+ xref_cache.update(obj.xref_cache) do |ref, cache1, cache2|
351
+ cache1.concat(cache2)
352
+ end
353
+
354
+ when Stream then
355
+ obj.dictionary.xref_cache.each do |ref, cache|
356
+ cache.map!{obj}
357
+ end
358
+
359
+ xref_cache.update(obj.dictionary.xref_cache) do |ref, cache1, cache2|
360
+ cache1.concat(cache2)
361
+ end
362
+ end
363
+ end
364
+
365
+ xref_cache[self.reference]
366
+ end
367
+
368
+ #
369
+ # Returns the indirect object which contains this object.
370
+ # If the current object is already indirect, returns self.
371
+ #
372
+ def indirect_parent
373
+ obj = self
374
+ obj = obj.parent until obj.is_indirect?
375
+
376
+ obj
377
+ end
378
+
379
+ #
380
+ # Returns self.
381
+ #
382
+ def to_o
383
+ self
384
+ end
385
+
386
+ #
387
+ # Returns self.
388
+ #
389
+ def solve
390
+ self
391
+ end
392
+
393
+ #
394
+ # Returns the size of this object once converted to PDF code.
395
+ #
396
+ def size
397
+ to_s.size
398
+ end
399
+
400
+ #
401
+ # Returns the PDF which the object belongs to.
402
+ #
403
+ def pdf
404
+ if self.is_indirect? then @pdf
405
+ else
406
+ @parent.pdf
407
+ end
408
+ end
409
+
410
+ def set_pdf(pdf)
411
+ if self.is_indirect? then @pdf = pdf
412
+ else
413
+ raise InvalidObjectError, "You cannot set the PDF parent of a direct object"
414
+ end
415
+ end
416
+
417
+ class << self
418
+
419
+ def typeof(stream, noref = false) #:nodoc:
420
+ stream.skip(REGEXP_WHITESPACES)
421
+
422
+ case stream.peek(1)
423
+ when '/' then return Name
424
+ when '<'
425
+ return (stream.peek(2) == '<<') ? Stream : HexaString
426
+ when '(' then return ByteString
427
+ when '[' then return Origami::Array
428
+ when 'n' then
429
+ return Null if stream.peek(4) == 'null'
430
+ when 't' then
431
+ return Boolean if stream.peek(4) == 'true'
432
+ when 'f' then
433
+ return Boolean if stream.peek(5) == 'false'
434
+ else
435
+ if not noref and stream.check(Reference::REGEXP_TOKEN) then return Reference
436
+ elsif stream.check(Real::REGEXP_TOKEN) then return Real
437
+ elsif stream.check(Integer::REGEXP_TOKEN) then return Integer
438
+ else
439
+ nil
440
+ end
441
+ end
442
+
443
+ nil
444
+ end
445
+
446
+ def parse(stream) #:nodoc:
447
+ offset = stream.pos
448
+
449
+ #
450
+ # End of body ?
451
+ #
452
+ return nil if stream.match?(/xref/) or stream.match?(/trailer/) or stream.match?(/startxref/)
453
+
454
+ if stream.scan(@@regexp_obj).nil?
455
+ raise InvalidObjectError,
456
+ "Object shall begin with '%d %d obj' statement"
457
+ end
458
+
459
+ no = stream[2].to_i
460
+ gen = stream[4].to_i
461
+
462
+ type = typeof(stream)
463
+ if type.nil?
464
+ raise InvalidObjectError,
465
+ "Cannot determine object (no:#{no},gen:#{gen}) type"
466
+ end
467
+
468
+ begin
469
+ newObj = type.parse(stream)
470
+ rescue Exception => e
471
+ raise InvalidObjectError,
472
+ "Failed to parse object (no:#{no},gen:#{gen})\n\t -> [#{e.class}] #{e.message}"
473
+ end
474
+
475
+ newObj.set_indirect(true)
476
+ newObj.no = no
477
+ newObj.generation = gen
478
+ newObj.file_offset = offset
479
+
480
+ if stream.skip(@@regexp_endobj).nil?
481
+ raise UnterminatedObjectError.new("Object shall end with 'endobj' statement", newObj)
482
+ end
483
+
484
+ newObj
485
+ end
486
+
487
+ def skip_until_next_obj(stream) #:nodoc:
488
+ stream.pos += 1 until stream.match?(@@regexp_obj) or
489
+ stream.match?(/xref/) or stream.match?(/trailer/) or stream.match?(/startxref/) or
490
+ stream.eos?
491
+
492
+ not stream.eos?
493
+ end
494
+
495
+ end
496
+
497
+ def pdf_version_required #:nodoc:
498
+ [ 1.0, 0 ]
499
+ end
500
+
501
+ #
502
+ # Returns the symbol type of this Object.
503
+ #
504
+ def type
505
+ self.class.to_s.split("::").last.to_sym
506
+ end
507
+ alias real_type type
508
+
509
+ #
510
+ # Outputs this object into PDF code.
511
+ # _data_:: The object data.
512
+ #
513
+ def to_s(data)
514
+
515
+ content = ""
516
+ content << "#{no} #{generation} obj" << EOL if self.is_indirect?
517
+ content << data
518
+ content << EOL << "endobj" << EOL if self.is_indirect?
519
+
520
+ content
521
+ end
522
+
523
+ alias output to_s
524
+
525
+ end
526
+
527
+ end