origami 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/bin/gui/config.rb +2 -1
  4. data/bin/gui/file.rb +118 -240
  5. data/bin/gui/gtkhex.rb +5 -5
  6. data/bin/gui/hexview.rb +20 -16
  7. data/bin/gui/imgview.rb +1 -1
  8. data/bin/gui/menu.rb +138 -158
  9. data/bin/gui/properties.rb +46 -48
  10. data/bin/gui/signing.rb +183 -214
  11. data/bin/gui/textview.rb +1 -1
  12. data/bin/gui/treeview.rb +13 -7
  13. data/bin/gui/walker.rb +102 -71
  14. data/bin/gui/xrefs.rb +1 -1
  15. data/bin/pdf2ruby +3 -3
  16. data/bin/pdfcop +18 -11
  17. data/bin/pdfextract +14 -5
  18. data/bin/pdfmetadata +3 -3
  19. data/bin/shell/console.rb +8 -8
  20. data/bin/shell/hexdump.rb +4 -4
  21. data/examples/attachments/nested_document.rb +1 -1
  22. data/examples/javascript/hello_world.rb +3 -3
  23. data/lib/origami.rb +0 -1
  24. data/lib/origami/acroform.rb +3 -3
  25. data/lib/origami/array.rb +1 -3
  26. data/lib/origami/boolean.rb +1 -3
  27. data/lib/origami/catalog.rb +3 -9
  28. data/lib/origami/destinations.rb +2 -2
  29. data/lib/origami/dictionary.rb +15 -29
  30. data/lib/origami/encryption.rb +334 -692
  31. data/lib/origami/extensions/fdf.rb +3 -2
  32. data/lib/origami/extensions/ppklite.rb +5 -9
  33. data/lib/origami/filespec.rb +2 -2
  34. data/lib/origami/filters.rb +54 -36
  35. data/lib/origami/filters/ascii.rb +67 -49
  36. data/lib/origami/filters/ccitt.rb +4 -236
  37. data/lib/origami/filters/ccitt/tables.rb +267 -0
  38. data/lib/origami/filters/crypt.rb +1 -1
  39. data/lib/origami/filters/dct.rb +0 -1
  40. data/lib/origami/filters/flate.rb +3 -43
  41. data/lib/origami/filters/lzw.rb +62 -99
  42. data/lib/origami/filters/predictors.rb +135 -105
  43. data/lib/origami/filters/runlength.rb +34 -22
  44. data/lib/origami/graphics.rb +2 -2
  45. data/lib/origami/graphics/colors.rb +89 -63
  46. data/lib/origami/graphics/path.rb +14 -14
  47. data/lib/origami/graphics/patterns.rb +31 -33
  48. data/lib/origami/graphics/render.rb +0 -1
  49. data/lib/origami/graphics/state.rb +9 -9
  50. data/lib/origami/graphics/text.rb +17 -17
  51. data/lib/origami/graphics/xobject.rb +102 -92
  52. data/lib/origami/javascript.rb +91 -68
  53. data/lib/origami/linearization.rb +22 -20
  54. data/lib/origami/metadata.rb +1 -1
  55. data/lib/origami/name.rb +1 -3
  56. data/lib/origami/null.rb +1 -3
  57. data/lib/origami/numeric.rb +3 -13
  58. data/lib/origami/object.rb +100 -72
  59. data/lib/origami/page.rb +24 -28
  60. data/lib/origami/parser.rb +34 -51
  61. data/lib/origami/parsers/fdf.rb +2 -2
  62. data/lib/origami/parsers/pdf.rb +41 -18
  63. data/lib/origami/parsers/pdf/lazy.rb +83 -46
  64. data/lib/origami/parsers/pdf/linear.rb +19 -10
  65. data/lib/origami/parsers/ppklite.rb +1 -1
  66. data/lib/origami/pdf.rb +150 -206
  67. data/lib/origami/reference.rb +4 -6
  68. data/lib/origami/signature.rb +76 -48
  69. data/lib/origami/stream.rb +69 -63
  70. data/lib/origami/string.rb +2 -19
  71. data/lib/origami/trailer.rb +25 -22
  72. data/lib/origami/version.rb +1 -1
  73. data/lib/origami/xfa.rb +6 -4
  74. data/lib/origami/xreftable.rb +29 -29
  75. data/test/test_annotations.rb +16 -38
  76. data/test/test_pdf_attachment.rb +1 -1
  77. data/test/test_pdf_parse.rb +1 -1
  78. data/test/test_xrefs.rb +2 -2
  79. metadata +4 -4
  80. data/lib/origami/export.rb +0 -247
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce1a44a58ce5b5e21a3279fda0f8195b10820eb7
4
- data.tar.gz: d47ccde08ad05ece6b5008fcbbf19de9916709d9
3
+ metadata.gz: 5d1ff84fe2a78a359e39368afcefca18d5538136
4
+ data.tar.gz: 4b471c0175c77ec5189c2579496e552a3c416f30
5
5
  SHA512:
6
- metadata.gz: 064c8a4052fb0a0b471bccb62351be31f00bd6362ed615affb31b0230c0d05b3c35819d7c69576b4c5ccfb203d3eab4187f4aad4b490003a88193c22f7ba377d
7
- data.tar.gz: 8e6ee0137acfd94f3bb569f0dc6614c59e5aba05ef80a815f241a3b0309b5f8d200a7ffbe40955ac805ad4c7143c1f6709d4f014e3e8ad3afbd60fb6ab51526e
6
+ metadata.gz: 4f5d904ad0125e4f78efc68d0d0fd1115d19d9fd3221162c2d95e27084bebc88bd221167ffe10f9396cf7abf67cf66d1983e8be625bd089ba0d5b9093220dc44
7
+ data.tar.gz: 22a28b2c789e1614d757b8c1eb7fd39a10bb0f69ff3fba10aad1103dcbb25aebe2e5c1bab1b986e271e4041add4e653077a1801e2146623bf2488f1fba3c6275
data/README.md CHANGED
@@ -45,6 +45,7 @@ Then import Origami with:
45
45
 
46
46
  ```ruby
47
47
  require 'origami'
48
+ include Origami
48
49
  ```
49
50
 
50
51
  To process a PDF document, you can use the ``PDF.read`` method:
@@ -46,8 +46,9 @@ module PDFWalker
46
46
 
47
47
  def initialize(configfile = DEFAULT_CONFIG_FILE)
48
48
  begin
49
- @conf = YAML.load(File.open(configfile)) or DEFAULT_CONFIG
49
+ @conf = YAML.load(File.open(configfile))
50
50
  rescue
51
+ @conf = DEFAULT_CONFIG
51
52
  ensure
52
53
  @filename = configfile
53
54
  set_missing_values
@@ -37,7 +37,7 @@ module PDFWalker
37
37
 
38
38
  # disable all menus.
39
39
  [
40
- @file_menu_close, @file_menu_saveas, @file_menu_serialize, @file_menu_refresh,
40
+ @file_menu_close, @file_menu_saveas, @file_menu_refresh,
41
41
  @document_menu_search,
42
42
  @document_menu_gotocatalog, @document_menu_gotodocinfo, @document_menu_gotometadata,
43
43
  @document_menu_gotopage, @document_menu_gotofield, @document_menu_gotorev, @document_menu_gotoobj,
@@ -78,174 +78,18 @@ module PDFWalker
78
78
  dialog.destroy
79
79
 
80
80
  begin
81
- if @help_menu_profile.active?
82
- require 'ruby-prof'
83
- RubyProf.start
81
+ document = start_profiling do
82
+ parse_file(filename)
84
83
  end
85
84
 
86
- target = parse_file(filename)
87
-
88
- if @help_menu_profile.active?
89
- result = RubyProf.stop
90
- multiprinter = RubyProf::MultiPrinter.new(result)
91
-
92
- Dir.mkdir(@config.profile_output_dir) unless Dir.exists?(@config.profile_output_dir)
93
-
94
- multiprinter.print(path: @config.profile_output_dir, profile: File.basename(filename))
95
- end
96
-
97
- if target
98
- close if @opened
99
- @opened = target
100
- @filename = filename
101
-
102
- @config.last_opened_file(filename)
103
- @config.save
104
- update_recent_menu
105
-
106
- @last_search_result = []
107
- @last_search =
108
- {
109
- :expr => "",
110
- :regexp => false,
111
- :type => :body
112
- }
113
-
114
- self.reload
115
-
116
- # Enable basic file menus.
117
- [
118
- @file_menu_close, @file_menu_refresh,
119
- ].each do |menu|
120
- menu.sensitive = true
121
- end
122
-
123
- @explorer_history.clear
124
-
125
- @statusbar.push(@main_context, "Viewing #{filename}")
126
-
127
- if @opened.is_a?(Origami::PDF)
128
-
129
- # Enable save and document menu.
130
- [
131
- @file_menu_saveas, @file_menu_serialize,
132
- @document_menu_search,
133
- @document_menu_gotocatalog, @document_menu_gotopage, @document_menu_gotorev, @document_menu_gotoobj,
134
- @document_menu_properties, @document_menu_sign, @document_menu_ur
135
- ].each do |menu|
136
- menu.sensitive = true
137
- end
138
-
139
- @document_menu_gotodocinfo.sensitive = true if @opened.document_info?
140
- @document_menu_gotometadata.sensitive = true if @opened.metadata?
141
- @document_menu_gotofield.sensitive = true if @opened.form?
142
-
143
- page_menu = Menu.new
144
- @document_menu_gotopage.remove_submenu
145
- @opened.each_page.with_index(1) do |page, index|
146
- page_menu.append(item = MenuItem.new(index.to_s).show)
147
- item.signal_connect("activate") do @treeview.goto(page) end
148
- end
149
- @document_menu_gotopage.set_submenu(page_menu)
150
-
151
- field_menu = Menu.new
152
- @document_menu_gotofield.remove_submenu
153
- @opened.each_field do |field|
154
- field_name = field.T || "<unnamed field>"
155
- field_menu.append(item = MenuItem.new(field_name).show)
156
- item.signal_connect("activate") do @treeview.goto(field) end
157
- end
158
- @document_menu_gotofield.set_submenu(field_menu)
159
-
160
- rev_menu = Menu.new
161
- @document_menu_gotorev.remove_submenu
162
- rev_index = 1
163
- @opened.revisions.each do |rev|
164
- rev_menu.append(item = MenuItem.new(rev_index.to_s).show)
165
- item.signal_connect("activate") do @treeview.goto(rev) end
166
- rev_index = rev_index + 1
167
- end
168
- @document_menu_gotorev.set_submenu(rev_menu)
169
-
170
- goto_catalog
171
- end
172
- end
85
+ set_active_document(filename, document)
173
86
 
174
87
  rescue
175
88
  error("Error while parsing file.\n#{$!} (#{$!.class})\n" + $!.backtrace.join("\n"))
89
+ ensure
90
+ close_progressbar
91
+ self.activate_focus
176
92
  end
177
-
178
- close_progressbar
179
- self.activate_focus
180
- end
181
-
182
- def deserialize
183
- dialog = Gtk::FileChooserDialog.new("Open dump file",
184
- self,
185
- FileChooser::ACTION_OPEN,
186
- nil,
187
- [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
188
- [Stock::OPEN, Dialog::RESPONSE_ACCEPT]
189
- )
190
-
191
- dialog.current_folder = File.join(Dir.pwd, "dumps")
192
- dialog.filter = FileFilter.new.add_pattern("*.gz")
193
-
194
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
195
- close if @opened
196
- filename = dialog.filename
197
-
198
- begin
199
- @opened = Origami::PDF.deserialize(filename)
200
- self.reload
201
-
202
- [
203
- @file_menu_close, @file_menu_saveas, @file_menu_serialize, @file_menu_refresh,
204
- @document_menu_search,
205
- @document_menu_gotocatalog, @document_menu_gotopage, @document_menu_gotorev, @document_menu_gotoobj,
206
- @document_menu_properties, @document_menu_sign, @document_menu_ur
207
- ].each do |menu|
208
- menu.sensitive = true
209
- end
210
-
211
- @document_menu_gotodocinfo.sensitive = true if @opened.document_info?
212
- @document_menu_gotometadata.sensitive = true if @opened.metadata?
213
- @document_menu_gotofield.sensitive = true if @opened.form?
214
-
215
- @explorer_history.clear
216
-
217
- @statusbar.push(@main_context, "Viewing dump of #{filename}")
218
- rescue
219
- error("This file cannot be loaded.\n#{$!} (#{$!.class})")
220
- end
221
- end
222
-
223
- dialog.destroy
224
- end
225
-
226
- def serialize
227
- dialog = Gtk::FileChooserDialog.new("Save dump file",
228
- self,
229
- Gtk::FileChooser::ACTION_SAVE,
230
- nil,
231
- [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
232
- [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
233
- )
234
-
235
- dialog.do_overwrite_confirmation = true
236
- dialog.current_folder = File.join(Dir.pwd, "dumps")
237
- dialog.current_name = "#{File.basename(@filename)}.dmp.gz"
238
- dialog.filter = FileFilter.new.add_pattern("*.gz")
239
-
240
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
241
- begin
242
- @opened.serialize(dialog.filename)
243
- rescue
244
- error("Error: #{$!.message}")
245
- end
246
- end
247
-
248
- dialog.destroy
249
93
  end
250
94
 
251
95
  def save_data(caption, data, filename = "")
@@ -297,97 +141,95 @@ module PDFWalker
297
141
  dialog.destroy
298
142
  end
299
143
 
300
- def save_dot
301
- dialog = Gtk::FileChooserDialog.new("Save dot file",
302
- self,
303
- Gtk::FileChooser::ACTION_SAVE,
304
- nil,
305
- [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
306
- [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
307
- )
144
+ private
308
145
 
309
- dialog.filter = FileFilter.new.add_pattern("*.dot")
146
+ def set_active_document(filename, document)
147
+ close if @opened
148
+ @opened = document
149
+ @filename = filename
150
+
151
+ @config.last_opened_file(filename)
152
+ @config.save
153
+ update_recent_menu
154
+
155
+ @last_search_result = []
156
+ @last_search =
157
+ {
158
+ :expr => "",
159
+ :regexp => false,
160
+ :type => :body
161
+ }
310
162
 
311
- folder = File.dirname(@filename)
312
- dialog.set_current_folder(folder)
163
+ self.reload
313
164
 
314
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
315
- begin
316
- @opened.export_to_graph(dialog.filename)
317
- rescue
318
- error("Error: #{$!.message}")
319
- end
165
+ # Enable basic file menus.
166
+ [
167
+ @file_menu_close, @file_menu_refresh,
168
+ ].each do |menu|
169
+ menu.sensitive = true
320
170
  end
321
171
 
322
- dialog.destroy
172
+ @explorer_history.clear
173
+
174
+ @statusbar.push(@main_context, "Viewing #{filename}")
175
+
176
+ setup_pdf_interface if @opened.is_a?(Origami::PDF)
323
177
  end
324
178
 
325
- def save_graphml
326
- dialog = Gtk::FileChooserDialog.new("Save GraphML file",
327
- self,
328
- Gtk::FileChooser::ACTION_SAVE,
329
- nil,
330
- [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
331
- [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
332
- )
179
+ def setup_pdf_interface
180
+ # Enable save and document menu.
181
+ [
182
+ @file_menu_saveas,
183
+ @document_menu_search,
184
+ @document_menu_gotocatalog, @document_menu_gotopage, @document_menu_gotorev, @document_menu_gotoobj,
185
+ @document_menu_properties, @document_menu_sign, @document_menu_ur
186
+ ].each do |menu|
187
+ menu.sensitive = true
188
+ end
333
189
 
334
- dialog.filter = FileFilter.new.add_pattern("*.graphml")
190
+ @document_menu_gotodocinfo.sensitive = true if @opened.document_info?
191
+ @document_menu_gotometadata.sensitive = true if @opened.metadata?
192
+ @document_menu_gotofield.sensitive = true if @opened.form?
335
193
 
336
- folder = File.dirname(@filename)
337
- dialog.set_current_folder(folder)
194
+ setup_page_menu
195
+ setup_field_menu
196
+ setup_revision_menu
338
197
 
339
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
340
- begin
341
- @opened.export_to_graphml(dialog.filename)
342
- rescue
343
- error("Error: #{$!.message}")
344
- end
198
+ goto_catalog
199
+ end
200
+
201
+ def setup_page_menu
202
+ page_menu = Menu.new
203
+ @document_menu_gotopage.remove_submenu
204
+ @opened.each_page.with_index(1) do |page, index|
205
+ page_menu.append(item = MenuItem.new(index.to_s).show)
206
+ item.signal_connect("activate") { @treeview.goto(page) }
345
207
  end
208
+ @document_menu_gotopage.set_submenu(page_menu)
209
+ end
346
210
 
347
- dialog.destroy
211
+ def setup_field_menu
212
+ field_menu = Menu.new
213
+ @document_menu_gotofield.remove_submenu
214
+ @opened.each_field do |field|
215
+ field_name = field.T || "<unnamed field>"
216
+ field_menu.append(item = MenuItem.new(field_name).show)
217
+ item.signal_connect("activate") { @treeview.goto(field) }
218
+ end
219
+ @document_menu_gotofield.set_submenu(field_menu)
348
220
  end
349
221
 
350
- private
222
+ def setup_revision_menu
223
+ rev_menu = Menu.new
224
+ @document_menu_gotorev.remove_submenu
225
+ @opened.revisions.each.with_index(1) do |rev, index|
226
+ rev_menu.append(item = MenuItem.new(index.to_s).show)
227
+ item.signal_connect("activate") { @treeview.goto(rev) }
228
+ end
229
+ @document_menu_gotorev.set_submenu(rev_menu)
230
+ end
351
231
 
352
232
  def parse_file(path)
353
- update_bar = lambda { |obj|
354
- @progressbar.pulse if @progressbar
355
- Gtk.main_iteration while Gtk.events_pending?
356
- }
357
-
358
- prompt_passwd = lambda {
359
- passwd = ""
360
-
361
- dialog = Gtk::Dialog.new(
362
- "This document is encrypted",
363
- nil,
364
- Gtk::Dialog::MODAL,
365
- [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ],
366
- [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ]
367
- )
368
-
369
- dialog.set_default_response(Gtk::Dialog::RESPONSE_OK)
370
-
371
- label = Gtk::Label.new("Please enter password:")
372
- entry = Gtk::Entry.new
373
- entry.signal_connect('activate') {
374
- dialog.response(Gtk::Dialog::RESPONSE_OK)
375
- }
376
-
377
- dialog.vbox.add(label)
378
- dialog.vbox.add(entry)
379
- dialog.show_all
380
-
381
- dialog.run do |response|
382
- if response == Gtk::Dialog::RESPONSE_OK
383
- passwd = entry.text
384
- end
385
- end
386
-
387
- dialog.destroy
388
- return passwd
389
- }
390
-
391
233
  #
392
234
  # Try to detect the file type of the document.
393
235
  # Fallback to PDF if none is found.
@@ -403,12 +245,48 @@ module PDFWalker
403
245
  file_type.read(path,
404
246
  verbosity: Origami::Parser::VERBOSE_TRACE,
405
247
  ignore_errors: false,
406
- callback: update_bar,
407
- prompt_password: prompt_passwd,
248
+ callback: method(:update_progressbar),
249
+ prompt_password: method(:prompt_password),
408
250
  force: force_mode
409
251
  )
410
252
  end
411
253
 
254
+ def update_progressbar(_obj)
255
+ @progressbar.pulse if @progressbar
256
+ Gtk.main_iteration while Gtk.events_pending?
257
+ end
258
+
259
+ def prompt_password
260
+ passwd = ""
261
+
262
+ dialog = Gtk::Dialog.new(
263
+ "This document is encrypted",
264
+ nil,
265
+ Gtk::Dialog::MODAL,
266
+ [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ],
267
+ [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ]
268
+ )
269
+
270
+ dialog.set_default_response(Gtk::Dialog::RESPONSE_OK)
271
+
272
+ label = Gtk::Label.new("Please enter password:")
273
+ entry = Gtk::Entry.new
274
+ entry.signal_connect('activate') {
275
+ dialog.response(Gtk::Dialog::RESPONSE_OK)
276
+ }
277
+
278
+ dialog.vbox.add(label)
279
+ dialog.vbox.add(entry)
280
+ dialog.show_all
281
+
282
+ dialog.run do |response|
283
+ passwd = entry.text if response == Gtk::Dialog::RESPONSE_OK
284
+ end
285
+
286
+ dialog.destroy
287
+ passwd
288
+ end
289
+
412
290
  def detect_file_type(path)
413
291
  supported_types = [ Origami::PDF, Origami::FDF, Origami::PPKLite ]
414
292
 
@@ -169,7 +169,7 @@ module Gtk
169
169
  @xdisp_gc.set_exposures(true)
170
170
  end
171
171
 
172
- @xdisp.signal_connect 'expose_event' do |xdisp, event|
172
+ @xdisp.signal_connect 'expose_event' do |_xdisp, event|
173
173
  imin = (event.area.y / @char_height).to_i
174
174
  imax = ((event.area.y + event.area.height) / @char_height).to_i
175
175
  imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
@@ -179,7 +179,7 @@ module Gtk
179
179
  render_hex_lines(imin, imax)
180
180
  end
181
181
 
182
- @xdisp.signal_connect 'scroll_event' do |xdisp, event|
182
+ @xdisp.signal_connect 'scroll_event' do |_xdisp, event|
183
183
  @scrollbar.event(event)
184
184
  end
185
185
 
@@ -245,7 +245,7 @@ module Gtk
245
245
  @adisp_gc.set_exposures(true)
246
246
  end
247
247
 
248
- @adisp.signal_connect 'expose_event' do |adisp, event|
248
+ @adisp.signal_connect 'expose_event' do |_adisp, event|
249
249
  imin = (event.area.y / @char_height).to_i
250
250
  imax = ((event.area.y + event.area.height) / @char_height).to_i
251
251
  imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0
@@ -254,7 +254,7 @@ module Gtk
254
254
  render_ascii_lines(imin, imax)
255
255
  end
256
256
 
257
- @adisp.signal_connect 'scroll_event' do |adisp, event|
257
+ @adisp.signal_connect 'scroll_event' do |_adisp, event|
258
258
  @scrollbar.event(event)
259
259
  end
260
260
 
@@ -910,7 +910,7 @@ module Gtk
910
910
  @olayout = @offsets.create_pango_layout('')
911
911
 
912
912
  @offsets.events = Gdk::Event::EXPOSURE_MASK
913
- @offsets.signal_connect 'expose_event' do |offsets, event|
913
+ @offsets.signal_connect 'expose_event' do |_offsets, event|
914
914
  imin = (event.area.y / @char_height).to_i
915
915
  imax = ((event.area.y + event.area.height) / @char_height).to_i
916
916
  imax += 1 if (event.area.y + event.area.height).to_i % @char_height != 0