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,107 @@
1
+ =begin
2
+
3
+ = File
4
+ textview.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
+ require 'kconv'
27
+ require 'gui/hexdump'
28
+
29
+ module PDFWalker
30
+
31
+ class Walker < Window
32
+
33
+ private
34
+
35
+ def create_objectview
36
+
37
+ @objectview = ObjectView.new(self)
38
+
39
+ end
40
+
41
+ class ObjectView < Notebook
42
+
43
+ attr_reader :parent
44
+ attr_reader :pdfpanel, :valuepanel
45
+
46
+ def initialize(parent)
47
+
48
+ @parent = parent
49
+
50
+ super()
51
+
52
+ @pdfbuffer = TextBuffer.new
53
+ @pdfview = TextView.new(@pdfbuffer).set_editable(false).set_cursor_visible(false).set_left_margin(5)
54
+
55
+ @pdfpanel = ScrolledWindow.new.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
56
+ @pdfpanel.add_with_viewport @pdfview
57
+ append_page(@pdfpanel, Label.new("PDF Code"))
58
+
59
+ @pdfbuffer.create_tag("Object", { :weight => Pango::WEIGHT_BOLD, :foreground => "darkblue", :family => "Courier", :scale => Pango::AttrScale::LARGE })
60
+
61
+ end
62
+
63
+ def load(object)
64
+
65
+ begin
66
+
67
+ self.clear
68
+
69
+ pdftag = "Object"
70
+
71
+ if object.is_a?(Stream)
72
+ stm = "#{object.no} #{object.generation} obj\n"
73
+ stm << object.dictionary.to_s
74
+
75
+ if object.rawdata.is_binary_data?
76
+ stm << "stream\n[Binary data]\nendstream"
77
+ else
78
+ stm << "stream\n#{object.rawdata}endstream"
79
+ end
80
+
81
+ @pdfbuffer.set_text(stm)
82
+
83
+ elsif (not object.is_a?(::Array) or object.is_a?(Array)) and
84
+ not object.is_a?(PDF) and not object.is_a?(Adobe::PPKLite) and
85
+ not object.is_a?(PDF::Revision) and not object.is_a?(Adobe::PPKLite::Revision) and
86
+ not object.is_a?(XRefToCompressedObj)
87
+
88
+ @pdfbuffer.set_text(object.to_s)
89
+ end
90
+
91
+ @pdfbuffer.apply_tag(pdftag, @pdfbuffer.start_iter, @pdfbuffer.end_iter)
92
+
93
+ rescue Exception => e
94
+ @parent.error("An error occured while loading this object.\n#{e} (#{e.class})")
95
+ end
96
+
97
+ end
98
+
99
+ def clear
100
+ @pdfbuffer.set_text("")
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,409 @@
1
+ =begin
2
+
3
+ = File
4
+ treeview.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 PDFWalker
27
+
28
+ class Walker < Window
29
+
30
+ private
31
+
32
+ def create_treeview
33
+
34
+ @treeview = PDFTree.new(self).set_headers_visible(false)
35
+
36
+ colcontent = Gtk::TreeViewColumn.new("Names",
37
+ Gtk::CellRendererText.new.set_foreground_set(true).set_background_set(true),
38
+ :text => PDFTree::TEXTCOL,
39
+ :weight => PDFTree::WEIGHTCOL,
40
+ :style => PDFTree::STYLECOL,
41
+ :foreground => PDFTree::FGCOL,
42
+ :background => PDFTree::BGCOL
43
+ )
44
+
45
+ @treeview.append_column(colcontent)
46
+
47
+ end
48
+
49
+ end
50
+
51
+ class PDFTree < TreeView
52
+
53
+ include Popable
54
+
55
+ OBJCOL = 0
56
+ TEXTCOL = 1
57
+ WEIGHTCOL = 2
58
+ STYLECOL = 3
59
+ FGCOL = 4
60
+ BGCOL = 5
61
+
62
+ @@appearance = Hash.new({ :Color => "black", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_NORMAL })
63
+
64
+ attr_reader :parent
65
+
66
+ def initialize(parent)
67
+
68
+ @parent = parent
69
+
70
+ reset_appearance
71
+
72
+ @treestore = TreeStore.new(Object::Object, String, Pango::FontDescription::Weight, Pango::FontDescription::Style, String, String)
73
+ super(@treestore)
74
+
75
+ signal_connect('cursor-changed') {
76
+ iter = selection.selected
77
+ if iter
78
+ obj = @treestore.get_value(iter, OBJCOL)
79
+
80
+ if obj.is_a?(Stream) and iter.n_children == 1
81
+
82
+ # Processing with an XRef or Object Stream
83
+ if obj.is_a?(ObjectStream)
84
+ obj.each { |embeddedobj|
85
+ load_object(iter, embeddedobj)
86
+ }
87
+
88
+ elsif obj.is_a?(XRefStream)
89
+ obj.each { |xref|
90
+ load_xrefstm(iter, xref)
91
+ }
92
+ end
93
+ end
94
+
95
+ parent.hexview.load(obj)
96
+ parent.objectview.load(obj)
97
+ end
98
+ }
99
+
100
+ signal_connect('row-activated') { |tree, path, column|
101
+ if selection.selected
102
+ obj = @treestore.get_value(selection.selected, OBJCOL)
103
+
104
+ if row_expanded?(path)
105
+ collapse_row(path)
106
+ else
107
+ expand_row(path, false)
108
+ end
109
+
110
+ goto(obj.solve) if obj.is_a?(Origami::Reference)
111
+ end
112
+ }
113
+
114
+ add_events(Gdk::Event::BUTTON_PRESS_MASK)
115
+ signal_connect('button_press_event') { |widget, event|
116
+ if event.button == 3 && parent.opened
117
+ path = get_path(event.x,event.y).first
118
+ set_cursor(path, nil, false)
119
+
120
+ obj = @treestore.get_value(@treestore.get_iter(path), OBJCOL)
121
+ popup_menu(obj, event, path)
122
+ end
123
+ }
124
+
125
+ end
126
+
127
+ def clear
128
+ @treestore.clear
129
+ end
130
+
131
+ def goto(obj)
132
+
133
+ if obj.is_a?(TreePath)
134
+ set_cursor(obj, nil, false)
135
+ else
136
+ if obj.is_a?(Name) and obj.parent.is_a?(Dictionary) and obj.parent.has_key?(obj)
137
+ obj = obj.parent[obj]
138
+ elsif obj.is_a?(Reference)
139
+ obj = obj.solve
140
+ end
141
+
142
+ @treestore.each { |model, path, iter|
143
+ current_obj = @treestore.get_value(iter, OBJCOL)
144
+
145
+ if current_obj.is_a?(ObjectStream) and obj.parent.equal?(current_obj)
146
+ current_obj.each { |embeddedobj|
147
+ load_object(iter, embeddedobj)
148
+ }
149
+ next
150
+ end
151
+
152
+ if obj.equal?(current_obj)
153
+ expand_to_path(path) unless row_expanded?(path)
154
+
155
+ if cursor.first then @parent.explorer_history << cursor.first end
156
+ set_cursor(path, nil, false)
157
+
158
+ return
159
+ end
160
+ }
161
+
162
+ @parent.error("Object not found : #{obj}")
163
+ end
164
+
165
+ end
166
+
167
+ def highlight(obj, color)
168
+ if obj.is_a?(Name) and obj.parent.is_a?(Dictionary) and obj.parent.has_key?(obj)
169
+ obj = obj.parent[obj]
170
+ end
171
+
172
+ @treestore.each { |model, path, iter|
173
+ current_obj = @treestore.get_value(iter, OBJCOL)
174
+
175
+ if obj.equal?(current_obj)
176
+ @treestore.set_value(iter, BGCOL, color)
177
+ expand_to_path(path) unless row_expanded?(path)
178
+ return
179
+ end
180
+ }
181
+
182
+ @parent.error("Object not found : #{obj}")
183
+ end
184
+
185
+ def load(pdf)
186
+
187
+ if pdf
188
+ self.clear
189
+
190
+ begin
191
+ #
192
+ # Create root entry
193
+ #
194
+ root = @treestore.append(nil)
195
+ @treestore.set_value(root, OBJCOL, pdf)
196
+
197
+ set_node(root, :Filename, @parent.filename)
198
+
199
+ #
200
+ # Create header entry
201
+ #
202
+ header = @treestore.append(root)
203
+ @treestore.set_value(header, OBJCOL, pdf.header)
204
+
205
+ set_node(header, :Header, "Header (version #{pdf.header.majorversion}.#{pdf.header.minorversion})")
206
+
207
+ no = 1
208
+ pdf.revisions.each { |revision|
209
+
210
+ load_revision(root, no, revision)
211
+ no = no + 1
212
+
213
+ }
214
+
215
+ set_model(@treestore)
216
+
217
+ ensure
218
+ expand(@treestore.iter_first, 3)
219
+ set_cursor(@treestore.iter_first.path, nil, false)
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ private
226
+
227
+ def expand(row, depth)
228
+
229
+ if row and depth != 0
230
+
231
+ loop do
232
+ expand_row(row.path, false)
233
+ expand(row.first_child, depth - 1)
234
+
235
+ break if not row.next!
236
+ end
237
+
238
+ end
239
+
240
+ end
241
+
242
+ def load_revision(root, no, revision)
243
+
244
+ revroot = @treestore.append(root)
245
+ @treestore.set_value(revroot, OBJCOL, revision)
246
+
247
+ set_node(revroot, :Revision, "Revision #{no}")
248
+
249
+ load_body(revroot, revision.body.values)
250
+
251
+ load_xrefs(revroot, revision.xreftable)
252
+
253
+ load_trailer(revroot, revision.trailer)
254
+
255
+ end
256
+
257
+ def load_body(rev, body)
258
+
259
+ bodyroot = @treestore.append(rev)
260
+ @treestore.set_value(bodyroot, OBJCOL, body)
261
+
262
+ set_node(bodyroot, :Body, "Body")
263
+
264
+ body.sort_by{|obj| obj.file_offset}.each { |object|
265
+ begin
266
+ load_object(bodyroot, object)
267
+ rescue Exception => e
268
+ msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
269
+
270
+ #@parent.error(msg)
271
+ next
272
+ end
273
+ }
274
+
275
+ end
276
+
277
+ def load_object(container, object, name = nil)
278
+
279
+ obj = @treestore.append(container)
280
+ @treestore.set_value(obj, OBJCOL, object)
281
+
282
+ type = object.real_type.to_s.split('::').last.to_sym
283
+
284
+ if name.nil?
285
+ name =
286
+ case object
287
+ when Origami::String
288
+ '"' + object.value + '"'
289
+ when Origami::Number, Name
290
+ object.value.to_s
291
+ else
292
+ object.type.to_s
293
+ end
294
+ end
295
+
296
+ set_node(obj, type, name)
297
+
298
+ if object.is_a? Origami::Array
299
+ object.each { |subobject|
300
+ load_object(obj, subobject)
301
+ }
302
+ elsif object.is_a? Origami::Dictionary
303
+ object.each_key { |subkey|
304
+ load_object(obj, object[subkey.value], subkey.value.to_s)
305
+ }
306
+ elsif object.is_a? Origami::Stream
307
+ load_object(obj, object.dictionary, "Stream Dictionary")
308
+ end
309
+
310
+ end
311
+
312
+ def load_xrefstm(stm, embxref)
313
+
314
+ xref = @treestore.append(stm)
315
+ @treestore.set_value(xref, OBJCOL, embxref)
316
+
317
+ if embxref.is_a?(XRef)
318
+ set_node(xref, :XRef, embxref.to_s.chomp)
319
+ else
320
+ set_node(xref, :XRef, "xref to ObjectStream #{embxref.objstmno}, object index #{embxref.index}")
321
+ end
322
+
323
+ end
324
+
325
+ def load_xrefs(rev, table)
326
+
327
+ if table
328
+
329
+ section = @treestore.append(rev)
330
+ @treestore.set_value(section, OBJCOL, table)
331
+
332
+ set_node(section, :XRefSection, "XRef section")
333
+
334
+ table.each { |subtable|
335
+
336
+ subsection = @treestore.append(section)
337
+ @treestore.set_value(subsection, OBJCOL, subtable)
338
+
339
+ set_node(subsection, :XRefSubSection, "#{subtable.range.begin} #{subtable.range.end - subtable.range.begin + 1}")
340
+
341
+ subtable.each { |entry|
342
+
343
+ xref = @treestore.append(subsection)
344
+ @treestore.set_value(xref, OBJCOL, entry)
345
+
346
+ set_node(xref, :XRef, entry.to_s.chomp)
347
+
348
+ }
349
+
350
+ }
351
+
352
+ end
353
+
354
+ end
355
+
356
+ def load_trailer(rev, trailer)
357
+
358
+ trailerroot = @treestore.append(rev)
359
+ @treestore.set_value(trailerroot, OBJCOL, trailer)
360
+
361
+ set_node(trailerroot, :Trailer, "Trailer")
362
+
363
+ unless trailer.dictionary.nil?
364
+ load_object(trailerroot, trailer.dictionary)
365
+ end
366
+
367
+ end
368
+
369
+ def reset_appearance
370
+
371
+ @@appearance[:Filename] = {:Color => "black", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
372
+ @@appearance[:Header] = {:Color => "darkgreen", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
373
+ @@appearance[:Revision] = {:Color => "blue", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
374
+ @@appearance[:Body] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
375
+ @@appearance[:XRefSection] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
376
+ @@appearance[:XRefSubSection] = {:Color => "brown", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
377
+ @@appearance[:XRef] = {:Color => "gray20", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
378
+ @@appearance[:Trailer] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
379
+ @@appearance[:StartXref] = {:Color => "black", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
380
+ @@appearance[:String] = {:Color => "red", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_ITALIC}
381
+ @@appearance[:Name] = {:Color => "gray", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_ITALIC}
382
+ @@appearance[:Number] = {:Color => "orange", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_NORMAL}
383
+ @@appearance[:Dictionary] = {:Color => "brown", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
384
+ @@appearance[:Stream] = {:Color => "darkcyan", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
385
+ @@appearance[:StreamData] = {:Color => "darkcyan", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_OBLIQUE}
386
+ @@appearance[:Array] = {:Color => "darkgreen", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
387
+ @@appearance[:Reference] = {:Color => "black", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_OBLIQUE}
388
+ @@appearance[:Boolean] = {:Color => "deeppink", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_NORMAL}
389
+
390
+ end
391
+
392
+ def get_object_appearance(type)
393
+ @@appearance[type]
394
+ end
395
+
396
+ def set_node(node, type, text)
397
+
398
+ @treestore.set_value(node, TEXTCOL, text)
399
+
400
+ app = get_object_appearance(type)
401
+ @treestore.set_value(node, WEIGHTCOL, app[:Weight])
402
+ @treestore.set_value(node, STYLECOL, app[:Style])
403
+ @treestore.set_value(node, FGCOL, app[:Color])
404
+
405
+ end
406
+
407
+ end
408
+
409
+ end