origami 2.0.4 → 2.1.0

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