origami 1.2.7 → 2.0.0

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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,106 +1,88 @@
1
1
  =begin
2
2
 
3
- = File
4
- textview.rb
5
-
6
- = Info
7
- This file is part of PDF Walker, a graphical PDF file browser
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- PDF Walker is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU 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
- PDF Walker 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 General Public License for more details.
20
-
21
- You should have received a copy of the GNU General Public License
22
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
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/>.
23
18
 
24
19
  =end
25
20
 
26
21
  module PDFWalker
27
22
 
28
- class Walker < Window
29
-
30
- private
31
-
32
- def create_objectview
33
- @objectview = ObjectView.new(self)
34
- end
35
-
36
- class ObjectView < Notebook
37
-
38
- attr_reader :parent
39
- attr_reader :pdfpanel, :valuepanel
40
-
41
- def initialize(parent)
42
-
43
- @parent = parent
44
-
45
- super()
46
-
47
- @pdfbuffer = TextBuffer.new
48
- @pdfview = TextView.new(@pdfbuffer).set_editable(false).set_cursor_visible(false).set_left_margin(5)
49
-
50
- @pdfpanel = ScrolledWindow.new.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
51
- @pdfpanel.add_with_viewport @pdfview
52
- append_page(@pdfpanel, Label.new("PDF Code"))
53
-
54
- @pdfbuffer.create_tag("Object",
55
- :weight => Pango::WEIGHT_BOLD,
56
- #:foreground => "darkblue",
57
- :family => "Courier",
58
- :scale => Pango::AttrScale::LARGE
59
- )
60
-
61
- end
62
-
63
- def load(object)
64
-
65
- begin
66
- self.clear
67
-
68
- pdftag = "Object"
69
-
70
- if object.is_a?(Stream)
71
- stm = "#{object.no} #{object.generation} obj\n"
72
- stm << object.dictionary.to_s
73
-
74
- #if object.rawdata.is_binary_data?
75
- # stm << "stream\n[Binary data]\nendstream"
76
- #else
77
- # stm << "stream\n#{object.rawdata}endstream"
78
- #end
79
-
80
- @pdfbuffer.set_text(stm)
81
-
82
- elsif not (object.is_a?(::Array) or object.is_a?(Array)) and
83
- not object.is_a?(PDF) and not object.is_a?(Adobe::PPKLite) and
84
- not object.is_a?(PDF::Revision) and not object.is_a?(Adobe::PPKLite::Revision) and
85
- not object.is_a?(XRefToCompressedObj)
86
-
87
- @pdfbuffer.set_text(object.to_s)
88
- end
89
-
90
- @pdfbuffer.apply_tag(pdftag, @pdfbuffer.start_iter, @pdfbuffer.end_iter)
91
-
92
- rescue Exception => e
93
- @parent.error("An error occured while loading this object.\n#{e} (#{e.class})")
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
+ .gsub!("\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
94
85
  end
95
-
96
- end
97
-
98
- def clear
99
- @pdfbuffer.set_text("")
100
- end
101
-
102
86
  end
103
-
104
- end
105
87
 
106
88
  end
@@ -1,415 +1,410 @@
1
1
  =begin
2
2
 
3
- = File
4
- treeview.rb
5
-
6
- = Info
7
- This file is part of PDF Walker, a graphical PDF file browser
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- PDF Walker is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU 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
- PDF Walker 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 General Public License for more details.
20
-
21
- You should have received a copy of the GNU General Public License
22
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
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/>.
23
18
 
24
19
  =end
25
20
 
26
21
  module PDFWalker
27
22
 
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
-
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
47
41
  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(: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
- }
42
+
43
+ class PDFTree < TreeView
44
+ include Popable
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]
92
163
  end
93
- end
94
164
 
95
- parent.hexview.load(obj)
96
- parent.objectview.load(obj)
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)
97
173
  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) if obj.is_a?(Origami::Reference)
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
111
210
  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)
211
+
212
+ private
213
+
214
+ def object_to_tree_pos(obj)
215
+
216
+ # Locate the indirect object.
217
+ root_obj = obj
218
+ object_path = [ root_obj ]
219
+ while root_obj.parent
220
+ root_obj = root_obj.parent
221
+ object_path.push(root_obj)
222
+ end
223
+
224
+ @treestore.each do |model, path, iter|
225
+ current_obj = @treestore.get_value(iter, OBJCOL)
226
+
227
+ # Load the intermediate nodes if necessary.
228
+ if object_path.any?{|object| object.equal?(current_obj)}
229
+ load_sub_objects(iter, current_obj)
230
+ end
231
+
232
+ # Unfold the object stream if it's in the object path.
233
+ if obj.is_a?(Origami::Object) and current_obj.is_a?(Origami::ObjectStream) and
234
+ root_obj.equal?(current_obj) and iter.n_children == 1
235
+
236
+ current_obj.each { |embeddedobj|
237
+ load_object(iter, embeddedobj)
238
+ }
239
+ end
240
+
241
+ return [ iter, path ] if obj.equal?(current_obj)
242
+ end
243
+
244
+ nil
122
245
  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 =
140
- begin
141
- obj.solve
142
- rescue InvalidReferenceError
143
- @parent.error("Object not found : #{obj}")
144
- return
246
+
247
+ def expand(row, depth)
248
+ if row and depth != 0
249
+ loop do
250
+ expand_row(row.path, false)
251
+ expand(row.first_child, depth - 1)
252
+
253
+ break if not row.next!
254
+ end
145
255
  end
146
256
  end
147
257
 
148
- @treestore.each { |model, path, iter|
149
- current_obj = @treestore.get_value(iter, OBJCOL)
150
-
151
- if current_obj.is_a?(ObjectStream) and obj.parent.equal?(current_obj)
152
- current_obj.each { |embeddedobj|
153
- load_object(iter, embeddedobj)
154
- }
155
- next
156
- end
157
-
158
- if obj.equal?(current_obj)
159
- expand_to_path(path) unless row_expanded?(path)
160
-
161
- if cursor.first then @parent.explorer_history << cursor.first end
162
- set_cursor(path, nil, false)
163
-
164
- return
165
- end
166
- }
167
-
168
- @parent.error("Object not found : #{obj}")
169
- end
170
-
171
- end
258
+ def load_revision(root, no, revision)
259
+ revroot = @treestore.append(root)
260
+ @treestore.set_value(revroot, OBJCOL, revision)
261
+
262
+ set_node(revroot, :Revision, "Revision #{no}")
172
263
 
173
- def highlight(obj, color)
174
- if obj.is_a?(Name) and obj.parent.is_a?(Dictionary) and obj.parent.has_key?(obj)
175
- obj = obj.parent[obj]
176
- end
177
-
178
- @treestore.each { |model, path, iter|
179
- current_obj = @treestore.get_value(iter, OBJCOL)
180
-
181
- if obj.equal?(current_obj)
182
- @treestore.set_value(iter, BGCOL, color)
183
- expand_to_path(path) unless row_expanded?(path)
184
- return
264
+ load_body(revroot, revision.body.values)
265
+ load_xrefs(revroot, revision.xreftable)
266
+ load_trailer(revroot, revision.trailer)
185
267
  end
186
- }
187
-
188
- @parent.error("Object not found : #{obj}")
189
- end
190
-
191
- def load(pdf)
192
-
193
- if pdf
194
- self.clear
195
-
196
- begin
197
- #
198
- # Create root entry
199
- #
200
- root = @treestore.append(nil)
201
- @treestore.set_value(root, OBJCOL, pdf)
202
-
203
- set_node(root, :Filename, @parent.filename)
204
-
205
- #
206
- # Create header entry
207
- #
208
- header = @treestore.append(root)
209
- @treestore.set_value(header, OBJCOL, pdf.header)
210
-
211
- set_node(header, :Header, "Header (version #{pdf.header.majorversion}.#{pdf.header.minorversion})")
212
-
213
- no = 1
214
- pdf.revisions.each { |revision|
215
-
216
- load_revision(root, no, revision)
217
- no = no + 1
218
-
219
- }
220
-
221
- set_model(@treestore)
222
-
223
- ensure
224
- expand(@treestore.iter_first, 3)
225
- set_cursor(@treestore.iter_first.path, nil, false)
268
+
269
+ def load_body(rev, body)
270
+ bodyroot = @treestore.append(rev)
271
+ @treestore.set_value(bodyroot, OBJCOL, body)
272
+
273
+ set_node(bodyroot, :Body, "Body")
274
+
275
+ body.sort_by{|obj| obj.file_offset.to_i }.each { |object|
276
+ begin
277
+ load_object(bodyroot, object)
278
+ rescue
279
+ msg = "#{$!.class}: #{$!.message}\n#{$!.backtrace.join($/)}"
280
+ STDERR.puts(msg)
281
+
282
+ #@parent.error(msg)
283
+ next
284
+ end
285
+ }
226
286
  end
227
- end
228
-
229
- end
230
-
231
- private
232
-
233
- def expand(row, depth)
234
-
235
- if row and depth != 0
236
-
237
- loop do
238
- expand_row(row.path, false)
239
- expand(row.first_child, depth - 1)
240
-
241
- break if not row.next!
287
+
288
+ def load_object(container, object, depth = 1, name = nil)
289
+ iter = @treestore.append(container)
290
+ @treestore.set_value(iter, OBJCOL, object)
291
+
292
+ type = object.native_type.to_s.split('::').last.to_sym
293
+
294
+ if name.nil?
295
+ name =
296
+ case object
297
+ when Origami::String
298
+ '"' + object.to_utf8.gsub("\x00", ".") + '"'
299
+ when Origami::Number, Origami::Name
300
+ object.value.to_s
301
+ else
302
+ object.type.to_s
303
+ end
304
+ end
305
+
306
+ set_node(iter, type, name)
307
+ return unless depth > 0
308
+
309
+ load_sub_objects(iter, object, depth)
242
310
  end
243
-
244
- end
245
-
246
- end
247
-
248
- def load_revision(root, no, revision)
249
-
250
- revroot = @treestore.append(root)
251
- @treestore.set_value(revroot, OBJCOL, revision)
252
-
253
- set_node(revroot, :Revision, "Revision #{no}")
254
-
255
- load_body(revroot, revision.body.values)
256
-
257
- load_xrefs(revroot, revision.xreftable)
258
-
259
- load_trailer(revroot, revision.trailer)
260
-
261
- end
262
-
263
- def load_body(rev, body)
264
-
265
- bodyroot = @treestore.append(rev)
266
- @treestore.set_value(bodyroot, OBJCOL, body)
267
-
268
- set_node(bodyroot, :Body, "Body")
269
-
270
- body.sort_by{|obj| obj.file_offset}.each { |object|
271
- begin
272
- load_object(bodyroot, object)
273
- rescue Exception => e
274
- msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
275
-
276
- #@parent.error(msg)
277
- next
311
+
312
+ def load_sub_objects(container, object, depth = 1)
313
+ return unless depth > 0 and @treestore.get_value(container, LOADCOL) != 1
314
+
315
+ case object
316
+ when Origami::Array
317
+ object.each do |subobject|
318
+ load_object(container, subobject, depth - 1)
319
+ end
320
+
321
+ when Origami::Dictionary
322
+ object.each_key do |subkey|
323
+ load_object(container, object[subkey.value], depth - 1, subkey.value.to_s)
324
+ end
325
+
326
+ when Origami::Stream
327
+ load_object(container, object.dictionary, depth - 1, "Stream Dictionary")
328
+ end
329
+
330
+ @treestore.set_value(container, LOADCOL, 1)
278
331
  end
279
- }
280
-
281
- end
282
-
283
- def load_object(container, object, name = nil)
284
-
285
- obj = @treestore.append(container)
286
- @treestore.set_value(obj, OBJCOL, object)
287
-
288
- type = object.native_type.to_s.split('::').last.to_sym
289
-
290
- if name.nil?
291
- name =
292
- case object
293
- when Origami::String
294
- '"' + object.to_utf8 + '"'
295
- when Origami::Number, Name
296
- object.value.to_s
332
+
333
+ def load_xrefstm(stm, embxref)
334
+ xref = @treestore.append(stm)
335
+ @treestore.set_value(xref, OBJCOL, embxref)
336
+
337
+ if embxref.is_a?(Origami::XRef)
338
+ set_node(xref, :XRef, embxref.to_s.chomp)
297
339
  else
298
- object.type.to_s
299
- end
300
- end
301
-
302
- set_node(obj, type, name)
303
-
304
- if object.is_a? Origami::Array
305
- object.each { |subobject|
306
- load_object(obj, subobject)
307
- }
308
- elsif object.is_a? Origami::Dictionary
309
- object.each_key { |subkey|
310
- load_object(obj, object[subkey.value], subkey.value.to_s)
311
- }
312
- elsif object.is_a? Origami::Stream
313
- load_object(obj, object.dictionary, "Stream Dictionary")
314
- end
315
-
316
- end
340
+ set_node(xref, :XRef, "xref to ObjectStream #{embxref.objstmno}, object index #{embxref.index}")
341
+ end
342
+ end
317
343
 
318
- def load_xrefstm(stm, embxref)
319
-
320
- xref = @treestore.append(stm)
321
- @treestore.set_value(xref, OBJCOL, embxref)
344
+ def load_xrefs(rev, table)
345
+ return unless table
322
346
 
323
- if embxref.is_a?(XRef)
324
- set_node(xref, :XRef, embxref.to_s.chomp)
325
- else
326
- set_node(xref, :XRef, "xref to ObjectStream #{embxref.objstmno}, object index #{embxref.index}")
327
- end
347
+ section = @treestore.append(rev)
348
+ @treestore.set_value(section, OBJCOL, table)
328
349
 
350
+ set_node(section, :XRefSection, "XRef section")
351
+
352
+ table.each_subsection { |subtable|
353
+ subsection = @treestore.append(section)
354
+ @treestore.set_value(subsection, OBJCOL, subtable)
355
+
356
+ set_node(subsection, :XRefSubSection, "#{subtable.range.begin} #{subtable.range.end - subtable.range.begin + 1}")
357
+
358
+ subtable.each { |entry|
359
+ xref = @treestore.append(subsection)
360
+ @treestore.set_value(xref, OBJCOL, entry)
361
+
362
+ set_node(xref, :XRef, entry.to_s.chomp)
363
+ }
364
+ }
365
+ end
366
+
367
+ def load_trailer(rev, trailer)
368
+ trailer_root = @treestore.append(rev)
369
+ @treestore.set_value(trailer_root, OBJCOL, trailer)
370
+
371
+ set_node(trailer_root, :Trailer, "Trailer")
372
+ load_object(trailer_root, trailer.dictionary) unless trailer.dictionary.nil?
373
+ end
374
+
375
+ def reset_appearance
376
+ @@appearance[:Filename] = {Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
377
+ @@appearance[:Header] = {Color: "darkgreen", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
378
+ @@appearance[:Revision] = {Color: "blue", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
379
+ @@appearance[:Body] = {Color: "purple", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
380
+ @@appearance[:XRefSection] = {Color: "purple", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
381
+ @@appearance[:XRefSubSection] = {Color: "brown", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
382
+ @@appearance[:XRef] = {Color: "gray20", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
383
+ @@appearance[:Trailer] = {Color: "purple", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
384
+ @@appearance[:StartXref] = {Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
385
+ @@appearance[:String] = {Color: "red", Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_ITALIC}
386
+ @@appearance[:Name] = {Color: "gray", Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_ITALIC}
387
+ @@appearance[:Number] = {Color: "orange", Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_NORMAL}
388
+ @@appearance[:Dictionary] = {Color: "brown", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
389
+ @@appearance[:Stream] = {Color: "darkcyan", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
390
+ @@appearance[:StreamData] = {Color: "darkcyan", Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_OBLIQUE}
391
+ @@appearance[:Array] = {Color: "darkgreen", Weight: Pango::WEIGHT_BOLD, Style: Pango::STYLE_NORMAL}
392
+ @@appearance[:Reference] = {Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_OBLIQUE}
393
+ @@appearance[:Boolean] = {Color: "deeppink", Weight: Pango::WEIGHT_NORMAL, Style: Pango::STYLE_NORMAL}
394
+ end
395
+
396
+ def get_object_appearance(type)
397
+ @@appearance[type]
398
+ end
399
+
400
+ def set_node(node, type, text)
401
+ @treestore.set_value(node, TEXTCOL, text)
402
+
403
+ app = get_object_appearance(type)
404
+ @treestore.set_value(node, WEIGHTCOL, app[:Weight])
405
+ @treestore.set_value(node, STYLECOL, app[:Style])
406
+ @treestore.set_value(node, FGCOL, app[:Color])
407
+ end
329
408
  end
330
-
331
- def load_xrefs(rev, table)
332
-
333
- if table
334
-
335
- section = @treestore.append(rev)
336
- @treestore.set_value(section, OBJCOL, table)
337
-
338
- set_node(section, :XRefSection, "XRef section")
339
-
340
- table.each { |subtable|
341
-
342
- subsection = @treestore.append(section)
343
- @treestore.set_value(subsection, OBJCOL, subtable)
344
-
345
- set_node(subsection, :XRefSubSection, "#{subtable.range.begin} #{subtable.range.end - subtable.range.begin + 1}")
346
-
347
- subtable.each { |entry|
348
-
349
- xref = @treestore.append(subsection)
350
- @treestore.set_value(xref, OBJCOL, entry)
351
-
352
- set_node(xref, :XRef, entry.to_s.chomp)
353
-
354
- }
355
-
356
- }
357
-
358
- end
359
-
360
- end
361
-
362
- def load_trailer(rev, trailer)
363
-
364
- trailerroot = @treestore.append(rev)
365
- @treestore.set_value(trailerroot, OBJCOL, trailer)
366
-
367
- set_node(trailerroot, :Trailer, "Trailer")
368
-
369
- unless trailer.dictionary.nil?
370
- load_object(trailerroot, trailer.dictionary)
371
- end
372
-
373
- end
374
-
375
- def reset_appearance
376
-
377
- @@appearance[:Filename] = {:Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
378
- @@appearance[:Header] = {:Color => "darkgreen", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
379
- @@appearance[:Revision] = {:Color => "blue", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
380
- @@appearance[:Body] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
381
- @@appearance[:XRefSection] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
382
- @@appearance[:XRefSubSection] = {:Color => "brown", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
383
- @@appearance[:XRef] = {:Color => "gray20", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
384
- @@appearance[:Trailer] = {:Color => "purple", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
385
- @@appearance[:StartXref] = {:Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
386
- @@appearance[:String] = {:Color => "red", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_ITALIC}
387
- @@appearance[:Name] = {:Color => "gray", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_ITALIC}
388
- @@appearance[:Number] = {:Color => "orange", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_NORMAL}
389
- @@appearance[:Dictionary] = {:Color => "brown", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
390
- @@appearance[:Stream] = {:Color => "darkcyan", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
391
- @@appearance[:StreamData] = {:Color => "darkcyan", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_OBLIQUE}
392
- @@appearance[:Array] = {:Color => "darkgreen", :Weight => Pango::WEIGHT_BOLD, :Style => Pango::STYLE_NORMAL}
393
- @@appearance[:Reference] = {:Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_OBLIQUE}
394
- @@appearance[:Boolean] = {:Color => "deeppink", :Weight => Pango::WEIGHT_NORMAL, :Style => Pango::STYLE_NORMAL}
395
-
396
- end
397
-
398
- def get_object_appearance(type)
399
- @@appearance[type]
400
- end
401
-
402
- def set_node(node, type, text)
403
-
404
- @treestore.set_value(node, TEXTCOL, text)
405
-
406
- app = get_object_appearance(type)
407
- @treestore.set_value(node, WEIGHTCOL, app[:Weight])
408
- @treestore.set_value(node, STYLECOL, app[:Style])
409
- @treestore.set_value(node, FGCOL, app[:Color])
410
-
411
- end
412
-
413
- end
414
409
 
415
410
  end