origami 1.0.2

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 (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,447 @@
1
+ =begin
2
+
3
+ = File
4
+ xreftable.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
+ module Origami
23
+
24
+ class PDF
25
+
26
+ #
27
+ # Tries to strip any xrefs information off the document.
28
+ #
29
+ def remove_xrefs
30
+ def delete_xrefstm(xrefstm)
31
+ prev = xrefstm.Prev
32
+ delete_object(xrefstm.reference)
33
+
34
+ if prev.is_a?(Integer) and (prev_stm = get_object_by_offset(prev)).is_a?(XRefStream)
35
+ delete_xrefstm(prev_stm)
36
+ end
37
+ end
38
+
39
+ @revisions.reverse_each do |rev|
40
+ if rev.has_xrefstm?
41
+ delete_xrefstm(rev.xrefstm)
42
+ end
43
+
44
+ if rev.trailer.has_dictionary? and rev.trailer.XRefStm.is_a?(Integer)
45
+ xrefstm = get_object_by_offset(rev.trailer.XRefStm)
46
+
47
+ delete_xrefstm(xrefstm) if xrefstm.is_a?(XRefStream)
48
+ end
49
+
50
+ rev.xrefstm = rev.xreftable = nil
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ class InvalidXRefError < Exception #:nodoc:
57
+ end
58
+
59
+ #
60
+ # Class representing a Cross-reference information.
61
+ #
62
+ class XRef
63
+
64
+ FREE = "f"
65
+ USED = "n"
66
+ FIRSTFREE = 65535
67
+
68
+ @@regexp = /(\d{10}) (\d{5}) (n|f)(\r| )\n/
69
+
70
+ attr_accessor :offset, :generation, :state
71
+
72
+ #
73
+ # Creates a new XRef.
74
+ # _offset_:: The file _offset_ of the referenced Object.
75
+ # _generation_:: The generation number of the referenced Object.
76
+ # _state_:: The state of the referenced Object (FREE or USED).
77
+ #
78
+ def initialize(offset, generation, state)
79
+
80
+ @offset, @generation, @state = offset, generation, state
81
+
82
+ end
83
+
84
+ def self.parse(stream) #:nodoc:
85
+
86
+ if stream.scan(@@regexp).nil?
87
+ raise InvalidXRefError, "Invalid XRef format"
88
+ end
89
+
90
+ offset = stream[1].to_i
91
+ generation = stream[2].to_i
92
+ state = stream[3]
93
+
94
+ XRef.new(offset, generation, state)
95
+ end
96
+
97
+ #
98
+ # Outputs self into PDF code.
99
+ #
100
+ def to_s
101
+ off = ("0" * (10 - @offset.to_s.length)) + @offset.to_s
102
+ gen = ("0" * (5 - @generation.to_s.length)) + @generation.to_s
103
+
104
+ "#{off} #{gen} #{@state}" + EOL
105
+ end
106
+
107
+ def to_xrefstm_data(type_w, field1_w, field2_w)
108
+ type_w <<= 3
109
+ field1_w <<= 3
110
+ field2_w <<= 3
111
+
112
+ type = ((@state == FREE) ? "\000" : "\001").unpack("B#{type_w}")[0]
113
+
114
+ offset = @offset.to_s(2)
115
+ offset = '0' * (field1_w - offset.size) + offset
116
+ generation = @generation.to_s(2)
117
+
118
+ generation = '0' * (field2_w - generation.size) + generation
119
+
120
+ [ type , offset, generation ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
121
+ end
122
+
123
+ class InvalidXRefSubsectionError < Exception #:nodoc:
124
+ end
125
+
126
+ #
127
+ # Class representing a cross-reference subsection.
128
+ # A subsection contains a continute set of XRef.
129
+ #
130
+ class Subsection
131
+
132
+ @@regexp = Regexp.new("(\\d+) (\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
133
+
134
+ attr_reader :range
135
+
136
+ #
137
+ # Creates a new XRef subsection.
138
+ # _start_:: The number of the first object referenced in the subsection.
139
+ # _entries_:: An array of XRef.
140
+ #
141
+ def initialize(start, entries = [])
142
+
143
+ @entries = entries.dup
144
+ @range = Range.new(start, start + entries.size - 1)
145
+
146
+ end
147
+
148
+ def self.parse(stream) #:nodoc:
149
+
150
+ if stream.scan(@@regexp).nil?
151
+ raise InvalidXRefSubsectionError, "Bad subsection format"
152
+ end
153
+
154
+ start = stream[1].to_i
155
+ size = stream[2].to_i
156
+
157
+ xrefs = []
158
+ size.times {
159
+ xrefs << XRef.parse(stream)
160
+ }
161
+
162
+ XRef::Subsection.new(start, xrefs)
163
+ end
164
+
165
+ #
166
+ # Returns whether this subsection contains information about a particular object.
167
+ # _no_:: The Object number.
168
+ #
169
+ def has_object?(no)
170
+ @range.include?(no)
171
+ end
172
+
173
+ #
174
+ # Returns XRef associated with a given object.
175
+ # _no_:: The Object number.
176
+ #
177
+ def [](no)
178
+ @entries[no - @range.begin]
179
+ end
180
+
181
+ #
182
+ # Processes each XRef in the subsection.
183
+ #
184
+ def each(&b)
185
+ @entries.each(&b)
186
+ end
187
+
188
+ #
189
+ # Outputs self into PDF code.
190
+ #
191
+ def to_s
192
+ section = "#{@range.begin} #{@range.end - @range.begin + 1}" + EOL
193
+ @entries.each { |xref|
194
+ section << xref.to_s
195
+ }
196
+
197
+ section
198
+ end
199
+
200
+ end
201
+
202
+ class InvalidXRefSectionError < Exception #:nodoc:
203
+ end
204
+
205
+ #
206
+ # Class representing a Cross-reference table.
207
+ # A section contains a set of XRefSubsection.
208
+ #
209
+ class Section
210
+
211
+ @@regexp_open = Regexp.new(WHITESPACES + "xref" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
212
+ @@regexp_sub = Regexp.new("(\\d+) (\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
213
+
214
+ #
215
+ # Creates a new XRef section.
216
+ # _subsections_:: An array of XRefSubsection.
217
+ #
218
+ def initialize(subsections = [])
219
+ @subsections = subsections
220
+ end
221
+
222
+ def self.parse(stream) #:nodoc:
223
+
224
+ if stream.skip(@@regexp_open).nil?
225
+ raise InvalidXRefSectionError, "No xref token found"
226
+ end
227
+
228
+ subsections = []
229
+ while stream.match?(@@regexp_sub) do
230
+ subsections << XRef::Subsection.parse(stream)
231
+ end
232
+
233
+ XRef::Section.new(subsections)
234
+ end
235
+
236
+ #
237
+ # Appends a new subsection.
238
+ # _subsection_:: A XRefSubsection.
239
+ #
240
+ def <<(subsection)
241
+ @subsections << subsection
242
+ end
243
+
244
+ #
245
+ # Returns a XRef associated with a given object.
246
+ # _no_:: The Object number.
247
+ #
248
+ def [](no)
249
+ @subsections.each { |s|
250
+ return s[no] if s.has_object?(no)
251
+ }
252
+ nil
253
+ end
254
+
255
+ alias :find :[]
256
+
257
+ #
258
+ # Processes each XRefSubsection.
259
+ #
260
+ def each(&b)
261
+ @subsections.each(&b)
262
+ end
263
+
264
+ #
265
+ # Outputs self into PDF code.
266
+ #
267
+ def to_s
268
+ "xref" << EOL << @subsections.join
269
+ end
270
+
271
+ end
272
+
273
+ end
274
+
275
+ #
276
+ # An xref poiting to an Object embedded in an ObjectStream.
277
+ #
278
+ class XRefToCompressedObj
279
+
280
+ attr_accessor :objstmno, :index
281
+
282
+ def initialize(objstmno, index)
283
+ @objstmno = objstmno
284
+ @index = index
285
+ end
286
+
287
+ def to_xrefstm_data(type_w, field1_w, field2_w)
288
+
289
+ type_w <<= 3
290
+ field1_w <<= 3
291
+ field2_w <<= 3
292
+
293
+ type = "\002".unpack("B#{type_w}")[0]
294
+ objstmno = @objstmno.to_s(2)
295
+ objstmno = '0' * (field1_w - objstmno.size) + objstmno
296
+ index = @index.to_s(2)
297
+ index = '0' * (field2_w - index.size) + index
298
+
299
+ [ type , objstmno, index ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
300
+ end
301
+
302
+ end
303
+
304
+ class InvalidXRefStreamObjectError < InvalidStreamObjectError ; end
305
+
306
+ #
307
+ # Class representing a XRef Stream.
308
+ #
309
+ class XRefStream < Stream
310
+
311
+ XREF_FREE = 0
312
+ XREF_USED = 1
313
+ XREF_COMPRESSED = 2
314
+
315
+ include Enumerable
316
+ include StandardObject
317
+
318
+ attr_reader :xrefs
319
+
320
+ #
321
+ # Xref fields
322
+ #
323
+ field :Type, :Type => Name, :Default => :XRef, :Required => true, :Version => "1.5"
324
+ field :Size, :Type => Integer, :Required => true
325
+ field :Index, :Type => Array
326
+ field :Prev, :Type => Integer
327
+ field :W, :Type => Array, :Required => true
328
+
329
+ #
330
+ # Trailer fields
331
+ #
332
+ field :Root, :Type => Dictionary, :Required => true
333
+ field :Encrypt, :Type => Dictionary
334
+ field :Info, :Type => Dictionary
335
+ field :ID, :Type => Array
336
+
337
+ def initialize(data = "", dictionary = {})
338
+ super(data, dictionary)
339
+
340
+ @xrefs = nil
341
+ end
342
+
343
+ def pre_build #:nodoc:
344
+ load! if @xrefs.nil?
345
+
346
+ self.W = [ 1, 2, 2 ] unless has_field?(:W)
347
+ self.Size = @xrefs.length + 1
348
+
349
+ save!
350
+
351
+ super
352
+ end
353
+
354
+ #
355
+ # Adds an XRef to this Stream.
356
+ #
357
+ def <<(xref)
358
+ load! if @xrefs.nil?
359
+
360
+ @xrefs << xref
361
+ end
362
+
363
+ #
364
+ # Iterates over each XRef present in the stream.
365
+ #
366
+ def each(&b)
367
+ load! if @xrefs.nil?
368
+
369
+ @xrefs.each(&b)
370
+ end
371
+
372
+ #
373
+ # Returns an XRef matching this object number.
374
+ #
375
+ def find(no)
376
+ load! if @xrefs.nil?
377
+
378
+ ranges = self.Index || [ 0, @xrefs.length ]
379
+
380
+ index = 0
381
+ (ranges.size / 2).times do |i|
382
+ brange = ranges[i*2].to_i
383
+ size = ranges[i*2+1].to_i
384
+ return @xrefs[index + no - brange] if Range.new(brange, brange + size - 1) === no
385
+
386
+ index += size
387
+ end
388
+
389
+ nil
390
+ end
391
+
392
+ def clear
393
+ @rawdata, @data = nil, ''
394
+ @xrefs = []
395
+ self.Index = []
396
+ end
397
+
398
+ private
399
+
400
+ def load! #:nodoc:
401
+ if @xrefs.nil? and has_field?(:W)
402
+ widths = self.W
403
+
404
+ if not widths.is_a?(Array) or widths.length != 3 or widths.any?{|width| not width.is_a?(Integer) }
405
+ raise InvalidXRefStreamObjectError, "W field must be an array of 3 integers"
406
+ end
407
+
408
+ decode!
409
+
410
+ type_w = self.W[0]
411
+ field1_w = self.W[1]
412
+ field2_w = self.W[2]
413
+
414
+ entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
415
+ size = @data.size / (type_w + field1_w + field2_w)
416
+
417
+ entries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
418
+
419
+ @xrefs = []
420
+ size.times do |i|
421
+ type,field1,field2 = entries[i*3],entries[i*3+1],entries[i*3+2]
422
+ case type
423
+ when XREF_FREE
424
+ @xrefs << XRef.new(field1, field2, XRef::FREE)
425
+ when XREF_USED
426
+ @xrefs << XRef.new(field1, field2, XRef::USED)
427
+ when XREF_COMPRESSED
428
+ @xrefs << XRefToCompressedObj.new(field1, field2)
429
+ end
430
+ end
431
+ else
432
+ @xrefs = []
433
+ end
434
+ end
435
+
436
+ def save! #:nodoc:
437
+ @data = ""
438
+
439
+ type_w, field1_w, field2_w = self.W
440
+ @xrefs.each do |xref| @data << xref.to_xrefstm_data(type_w, field1_w, field2_w) end
441
+
442
+ encode!
443
+ end
444
+
445
+ end
446
+
447
+ end
@@ -0,0 +1,66 @@
1
+ =begin
2
+
3
+ = File
4
+ patterns.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ module Template
29
+
30
+ class AxialGradient < Graphics::Pattern::Shading::Axial
31
+
32
+ def initialize(from, to, color0, color1, coeff = 1)
33
+ super()
34
+
35
+ set_indirect(true)
36
+
37
+ x, y = from
38
+ tx, ty = to
39
+
40
+ c0 = Graphics::Color.to_a(color0)
41
+ c1 = Graphics::Color.to_a(color1)
42
+
43
+ space =
44
+ case c0.size
45
+ when 1 then Graphics::Color::Space::DEVICE_GRAY
46
+ when 3 then Graphics::Color::Space::DEVICE_RGB
47
+ when 4 then Graphics::Color::Space::DEVICE_CMYK
48
+ end
49
+
50
+ f = Function::Exponential.new
51
+ f.Domain = [ 0.0, 1.0 ]
52
+ f.N = coeff
53
+ f.C0, f.C1 = c0, c1
54
+
55
+ self.ColorSpace = space
56
+ self.Coords = [ x, y, tx, ty ]
57
+ self.Function = f
58
+ self.Extend = [ true, true ]
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end