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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/README.md +112 -0
- data/bin/config/pdfcop.conf.yml +232 -233
- data/bin/gui/about.rb +27 -37
- data/bin/gui/config.rb +108 -117
- data/bin/gui/file.rb +416 -365
- data/bin/gui/gtkhex.rb +1138 -1153
- data/bin/gui/hexview.rb +55 -57
- data/bin/gui/imgview.rb +48 -51
- data/bin/gui/menu.rb +388 -386
- data/bin/gui/properties.rb +114 -130
- data/bin/gui/signing.rb +571 -617
- data/bin/gui/textview.rb +77 -95
- data/bin/gui/treeview.rb +382 -387
- data/bin/gui/walker.rb +227 -232
- data/bin/gui/xrefs.rb +56 -60
- data/bin/pdf2pdfa +53 -57
- data/bin/pdf2ruby +212 -228
- data/bin/pdfcop +338 -348
- data/bin/pdfdecompress +58 -65
- data/bin/pdfdecrypt +56 -60
- data/bin/pdfencrypt +75 -80
- data/bin/pdfexplode +185 -182
- data/bin/pdfextract +201 -218
- data/bin/pdfmetadata +83 -82
- data/bin/pdfsh +4 -5
- data/bin/pdfwalker +1 -2
- data/bin/shell/.irbrc +45 -82
- data/bin/shell/console.rb +105 -130
- data/bin/shell/hexdump.rb +40 -64
- data/examples/README.md +34 -0
- data/examples/attachments/attachment.rb +38 -0
- data/examples/attachments/nested_document.rb +51 -0
- data/examples/encryption/encryption.rb +28 -0
- data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
- data/examples/flash/flash.rb +37 -0
- data/{samples → examples}/flash/helloworld.swf +0 -0
- data/examples/forms/javascript.rb +54 -0
- data/examples/forms/xfa.rb +115 -0
- data/examples/javascript/hello_world.rb +22 -0
- data/examples/javascript/js_emulation.rb +54 -0
- data/examples/loop/goto.rb +32 -0
- data/examples/loop/named.rb +33 -0
- data/examples/signature/signature.rb +65 -0
- data/examples/uri/javascript.rb +56 -0
- data/examples/uri/open-uri.rb +21 -0
- data/examples/uri/submitform.rb +47 -0
- data/lib/origami.rb +29 -42
- data/lib/origami/3d.rb +350 -225
- data/lib/origami/acroform.rb +262 -288
- data/lib/origami/actions.rb +268 -288
- data/lib/origami/annotations.rb +697 -722
- data/lib/origami/array.rb +258 -184
- data/lib/origami/boolean.rb +74 -84
- data/lib/origami/catalog.rb +397 -434
- data/lib/origami/collections.rb +144 -0
- data/lib/origami/destinations.rb +233 -194
- data/lib/origami/dictionary.rb +253 -232
- data/lib/origami/encryption.rb +1274 -1243
- data/lib/origami/export.rb +232 -268
- data/lib/origami/extensions/fdf.rb +307 -220
- data/lib/origami/extensions/ppklite.rb +368 -435
- data/lib/origami/filespec.rb +197 -0
- data/lib/origami/filters.rb +301 -295
- data/lib/origami/filters/ascii.rb +177 -180
- data/lib/origami/filters/ccitt.rb +528 -535
- data/lib/origami/filters/crypt.rb +26 -35
- data/lib/origami/filters/dct.rb +46 -52
- data/lib/origami/filters/flate.rb +95 -94
- data/lib/origami/filters/jbig2.rb +49 -55
- data/lib/origami/filters/jpx.rb +38 -44
- data/lib/origami/filters/lzw.rb +189 -183
- data/lib/origami/filters/predictors.rb +221 -235
- data/lib/origami/filters/runlength.rb +103 -104
- data/lib/origami/font.rb +173 -186
- data/lib/origami/functions.rb +67 -81
- data/lib/origami/graphics.rb +25 -21
- data/lib/origami/graphics/colors.rb +178 -187
- data/lib/origami/graphics/instruction.rb +79 -85
- data/lib/origami/graphics/path.rb +142 -148
- data/lib/origami/graphics/patterns.rb +160 -167
- data/lib/origami/graphics/render.rb +43 -50
- data/lib/origami/graphics/state.rb +138 -153
- data/lib/origami/graphics/text.rb +188 -205
- data/lib/origami/graphics/xobject.rb +819 -815
- data/lib/origami/header.rb +63 -78
- data/lib/origami/javascript.rb +596 -597
- data/lib/origami/linearization.rb +285 -290
- data/lib/origami/metadata.rb +139 -148
- data/lib/origami/name.rb +112 -148
- data/lib/origami/null.rb +53 -62
- data/lib/origami/numeric.rb +162 -175
- data/lib/origami/obfuscation.rb +186 -174
- data/lib/origami/object.rb +593 -573
- data/lib/origami/outline.rb +42 -47
- data/lib/origami/outputintents.rb +73 -82
- data/lib/origami/page.rb +703 -592
- data/lib/origami/parser.rb +238 -290
- data/lib/origami/parsers/fdf.rb +41 -33
- data/lib/origami/parsers/pdf.rb +75 -95
- data/lib/origami/parsers/pdf/lazy.rb +137 -0
- data/lib/origami/parsers/pdf/linear.rb +64 -66
- data/lib/origami/parsers/ppklite.rb +34 -70
- data/lib/origami/pdf.rb +1030 -1005
- data/lib/origami/reference.rb +102 -102
- data/lib/origami/signature.rb +591 -609
- data/lib/origami/stream.rb +668 -551
- data/lib/origami/string.rb +397 -373
- data/lib/origami/template/patterns.rb +56 -0
- data/lib/origami/template/widgets.rb +151 -0
- data/lib/origami/trailer.rb +144 -158
- data/lib/origami/tree.rb +62 -0
- data/lib/origami/version.rb +23 -0
- data/lib/origami/webcapture.rb +88 -79
- data/lib/origami/xfa.rb +2863 -2882
- data/lib/origami/xreftable.rb +472 -384
- data/test/dataset/calc.pdf +85 -0
- data/test/dataset/crypto.pdf +82 -0
- data/test/dataset/empty.pdf +49 -0
- data/test/test_actions.rb +27 -0
- data/test/test_annotations.rb +90 -0
- data/test/test_pages.rb +31 -0
- data/test/test_pdf.rb +16 -0
- data/test/test_pdf_attachment.rb +34 -0
- data/test/test_pdf_create.rb +24 -0
- data/test/test_pdf_encrypt.rb +95 -0
- data/test/test_pdf_parse.rb +96 -0
- data/test/test_pdf_sign.rb +58 -0
- data/test/test_streams.rb +182 -0
- data/test/test_xrefs.rb +67 -0
- metadata +88 -58
- data/README +0 -67
- data/bin/pdf2graph +0 -121
- data/bin/pdfcocoon +0 -104
- data/lib/origami/file.rb +0 -233
- data/samples/README.txt +0 -45
- data/samples/actions/launch/calc.rb +0 -87
- data/samples/actions/launch/winparams.rb +0 -22
- data/samples/actions/loop/loopgoto.rb +0 -24
- data/samples/actions/loop/loopnamed.rb +0 -21
- data/samples/actions/named/named.rb +0 -31
- data/samples/actions/samba/smbrelay.rb +0 -26
- data/samples/actions/webbug/submitform.js +0 -26
- data/samples/actions/webbug/webbug-browser.rb +0 -68
- data/samples/actions/webbug/webbug-js.rb +0 -67
- data/samples/actions/webbug/webbug-reader.rb +0 -90
- data/samples/attachments/attach.rb +0 -40
- data/samples/attachments/attached.txt +0 -1
- data/samples/crypto/crypto.rb +0 -28
- data/samples/digsig/signed.rb +0 -46
- data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
- data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
- data/samples/exploits/exploit_customdictopen.rb +0 -55
- data/samples/exploits/getannots.rb +0 -69
- data/samples/flash/flash.rb +0 -31
- data/samples/javascript/attached.txt +0 -1
- data/samples/javascript/js.rb +0 -52
- data/templates/patterns.rb +0 -66
- data/templates/widgets.rb +0 -173
- data/templates/xdp.rb +0 -92
- data/test/ts_pdf.rb +0 -50
data/bin/gui/xrefs.rb
CHANGED
|
@@ -1,79 +1,75 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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é.
|
|
23
5
|
|
|
24
|
-
|
|
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/>.
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
include Origami
|
|
19
|
+
=end
|
|
28
20
|
|
|
29
21
|
module PDFWalker
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
class Walker < Window
|
|
24
|
+
def show_xrefs(target)
|
|
25
|
+
XrefsDialog.new(self, target)
|
|
26
|
+
end
|
|
35
27
|
end
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
class XrefsDialog < Dialog
|
|
30
|
+
OBJCOL = 0
|
|
31
|
+
REFCOL = 1
|
|
32
|
+
NAMECOL = 2
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
TEXTCOL = 1
|
|
34
|
+
def initialize(parent, target)
|
|
35
|
+
super("Xrefs to #{target.reference}", parent, Dialog::MODAL, [Stock::CLOSE, Dialog::RESPONSE_NONE])
|
|
36
|
+
@parent = parent
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
super("Xrefs to #{target.reference}", parent, Dialog::MODAL, [Stock::CLOSE, Dialog::RESPONSE_NONE])
|
|
47
|
-
@parent = parent
|
|
38
|
+
@list = ListStore.new(Object, String, String)
|
|
39
|
+
@view = TreeView.new(@list)
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
column = Gtk::TreeViewColumn.new("Origin", Gtk::CellRendererText.new, text: REFCOL)
|
|
42
|
+
@view.append_column(column)
|
|
51
43
|
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
column = Gtk::TreeViewColumn.new("Objects", Gtk::CellRendererText.new, text: NAMECOL)
|
|
45
|
+
@view.append_column(column)
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@list.set_value(iter, TEXTCOL, str)
|
|
60
|
-
}
|
|
47
|
+
target.xrefs.each { |obj|
|
|
48
|
+
str = obj.type.to_s
|
|
49
|
+
iter = @list.append
|
|
50
|
+
@list.set_value(iter, OBJCOL, obj)
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
from = @list.get_value(@view.selection.selected, OBJCOL)
|
|
65
|
-
@parent.treeview.goto(from)
|
|
66
|
-
end
|
|
67
|
-
}
|
|
52
|
+
obj = obj.parent until obj.indirect?
|
|
53
|
+
@list.set_value(iter, REFCOL, obj.reference.to_s)
|
|
68
54
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
vbox.add(scroll)
|
|
55
|
+
@list.set_value(iter, NAMECOL, str)
|
|
56
|
+
}
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
58
|
+
@view.signal_connect("row_activated") { |tree, path, _column|
|
|
59
|
+
if @view.selection.selected
|
|
60
|
+
from = @list.get_value(@view.selection.selected, OBJCOL)
|
|
61
|
+
@parent.treeview.goto(from)
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
scroll = ScrolledWindow.new.set_policy(POLICY_NEVER, POLICY_AUTOMATIC)
|
|
66
|
+
scroll.add(@view)
|
|
67
|
+
vbox.add(scroll)
|
|
68
|
+
|
|
69
|
+
set_default_size(200, 200)
|
|
78
70
|
|
|
71
|
+
signal_connect('response') { destroy }
|
|
72
|
+
show_all
|
|
73
|
+
end
|
|
74
|
+
end
|
|
79
75
|
end
|
data/bin/pdf2pdfa
CHANGED
|
@@ -1,91 +1,87 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
=begin
|
|
4
4
|
|
|
5
|
-
=
|
|
6
|
-
|
|
5
|
+
= Info
|
|
6
|
+
Enforces a document to be rendered as PDF/A.
|
|
7
|
+
This will disable multimedia features and JavaScript execution in Adobe Reader.
|
|
7
8
|
|
|
8
|
-
=
|
|
9
|
-
|
|
10
|
-
This will disable multimedia features and JavaScript execution in Adobe Reader.
|
|
9
|
+
= License
|
|
10
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
(at your option) any later version.
|
|
12
|
+
Origami is free software: you can redistribute it and/or modify
|
|
13
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
14
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
15
|
+
(at your option) any later version.
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
Origami is distributed in the hope that it will be useful,
|
|
18
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20
|
+
GNU Lesser General Public License for more details.
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
23
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
25
24
|
|
|
26
25
|
=end
|
|
27
26
|
|
|
28
27
|
begin
|
|
29
|
-
|
|
28
|
+
require 'origami'
|
|
30
29
|
rescue LoadError
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
require 'origami'
|
|
30
|
+
$: << File.join(__dir__, '../lib')
|
|
31
|
+
require 'origami'
|
|
34
32
|
end
|
|
35
33
|
include Origami
|
|
36
34
|
|
|
37
35
|
require 'optparse'
|
|
38
36
|
|
|
39
37
|
class OptParser
|
|
40
|
-
|
|
38
|
+
BANNER = <<USAGE
|
|
41
39
|
Usage: #{$0} [<PDF-file>] [-o <output-file>]
|
|
42
|
-
Enforces a document to be rendered as PDF/A.
|
|
40
|
+
Enforces a document to be rendered as PDF/A.
|
|
43
41
|
This will disable multimedia features and JavaScript execution in Adobe Reader.
|
|
44
|
-
Bug reports or feature requests at: http://
|
|
42
|
+
Bug reports or feature requests at: http://github.com/gdelugre/origami
|
|
45
43
|
|
|
46
44
|
Options:
|
|
47
45
|
USAGE
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
def self.parser(options)
|
|
48
|
+
OptionParser.new do |opts|
|
|
49
|
+
opts.banner = BANNER
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
|
|
52
|
+
options[:output] = o
|
|
53
|
+
end
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
56
|
+
puts opts
|
|
57
|
+
exit
|
|
58
|
+
end
|
|
59
|
+
end
|
|
61
60
|
end
|
|
62
|
-
end
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
def self.parse(args)
|
|
63
|
+
options =
|
|
64
|
+
{
|
|
65
|
+
output: STDOUT,
|
|
66
|
+
}
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
self.parser(options).parse!(args)
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
options
|
|
71
|
+
end
|
|
74
72
|
end
|
|
75
73
|
|
|
76
74
|
begin
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
target = (ARGV.empty?) ? STDIN : ARGV.shift
|
|
80
|
-
params =
|
|
81
|
-
{
|
|
82
|
-
:verbosity => Parser::VERBOSE_QUIET,
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
PDF.read(target, params).save(@options[:output], :intent => 'PDF/A', :noindent => true)
|
|
86
|
-
rescue SystemExit
|
|
87
|
-
rescue Exception => e
|
|
88
|
-
STDERR.puts "#{e.class}: #{e.message}"
|
|
89
|
-
exit 1
|
|
90
|
-
end
|
|
75
|
+
@options = OptParser.parse(ARGV)
|
|
91
76
|
|
|
77
|
+
target = (ARGV.empty?) ? STDIN : ARGV.shift
|
|
78
|
+
params =
|
|
79
|
+
{
|
|
80
|
+
verbosity: Parser::VERBOSE_QUIET,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
PDF.read(target, params).save(@options[:output], intent: 'PDF/A', noindent: true)
|
|
84
|
+
|
|
85
|
+
rescue
|
|
86
|
+
abort"#{$!.class}: #{$!.message}"
|
|
87
|
+
end
|
data/bin/pdf2ruby
CHANGED
|
@@ -2,37 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
=begin
|
|
4
4
|
|
|
5
|
-
= Info
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
= Info
|
|
6
|
+
Convert a PDF document to an Origami script.
|
|
7
|
+
Experimental.
|
|
8
8
|
|
|
9
9
|
= License:
|
|
10
|
-
|
|
11
|
-
it under the terms of the GNU Lesser General Public License as published by
|
|
12
|
-
the Free Software Foundation, either version 3 of the License, or
|
|
13
|
-
(at your option) any later version.
|
|
10
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
Origami is free software: you can redistribute it and/or modify
|
|
13
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
14
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
15
|
+
(at your option) any later version.
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
Origami is distributed in the hope that it will be useful,
|
|
18
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20
|
+
GNU Lesser General Public License for more details.
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
23
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
25
24
|
|
|
26
25
|
=end
|
|
27
26
|
|
|
28
27
|
require 'optparse'
|
|
29
28
|
require 'fileutils'
|
|
29
|
+
require 'colorize'
|
|
30
|
+
|
|
30
31
|
begin
|
|
31
|
-
|
|
32
|
-
require 'origami'
|
|
32
|
+
require 'origami'
|
|
33
33
|
rescue LoadError
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
$: << File.join(__dir__, '../lib')
|
|
35
|
+
require 'origami'
|
|
36
36
|
end
|
|
37
37
|
include Origami
|
|
38
38
|
|
|
@@ -42,252 +42,247 @@ include Origami
|
|
|
42
42
|
@current_idx = nil
|
|
43
43
|
|
|
44
44
|
class OptParser
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
def self.parse(args)
|
|
46
|
+
options = {}
|
|
47
|
+
options[:verbose] =
|
|
48
|
+
options[:xstreams] = false
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
opts = OptionParser.new do |opts|
|
|
51
|
+
opts.banner = <<BANNER
|
|
52
52
|
Usage: #{$0} [-v] [-x] <PDF-file>
|
|
53
53
|
Convert a PDF document to an Origami script (experimental).
|
|
54
54
|
|
|
55
55
|
Options:
|
|
56
56
|
BANNER
|
|
57
|
-
|
|
58
|
-
opts.on("-v", "--verbose", "Verbose mode") do
|
|
59
|
-
options[:verbose] = true
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
opts.on("-x", "--extract-streams", "Extract PDF streams to separate files") do
|
|
63
|
-
options[:xstreams] = true
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
|
67
|
-
puts opts
|
|
68
|
-
exit
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
opts.parse!(args)
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
|
|
58
|
+
opts.on("-v", "--verbose", "Verbose mode") do
|
|
59
|
+
options[:verbose] = true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
opts.on("-x", "--extract-streams", "Extract PDF streams to separate files") do
|
|
63
|
+
options[:xstreams] = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
67
|
+
puts opts
|
|
68
|
+
exit
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
opts.parse!(args)
|
|
73
|
+
|
|
74
|
+
options
|
|
75
|
+
end
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
@options = OptParser.parse(ARGV)
|
|
78
79
|
|
|
79
80
|
if ARGV.empty?
|
|
80
|
-
|
|
81
|
-
exit 1
|
|
81
|
+
abort "Error: No filename was specified. #{$0} --help for details."
|
|
82
82
|
else
|
|
83
83
|
TARGET = ARGV.shift
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
Origami::OPTIONS[:enable_type_guessing] = Origami::OPTIONS[:enable_type_propagation] = true
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
TARGET_DIR = File.basename(TARGET, '.pdf')
|
|
89
|
-
TARGET_FILE = "#{TARGET_DIR}
|
|
89
|
+
TARGET_FILE = File.join(TARGET_DIR, "#{TARGET_DIR}.rb")
|
|
90
90
|
STREAM_DIR = "streams"
|
|
91
91
|
|
|
92
92
|
def objectToRuby(obj, inclevel = 0, internalname = nil, do_convert = false)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
93
|
+
code = ""
|
|
94
|
+
|
|
95
|
+
code <<
|
|
96
|
+
case obj
|
|
97
|
+
when Origami::Null
|
|
98
|
+
"Null.new"
|
|
99
|
+
when Origami::Boolean, Origami::Number
|
|
100
|
+
obj.value.to_s
|
|
101
|
+
when Origami::String
|
|
102
|
+
obj.inspect
|
|
103
|
+
when Origami::Dictionary
|
|
104
|
+
customclass = nil
|
|
105
|
+
if obj.class != Origami::Dictionary
|
|
106
|
+
p = (obj.class == Origami::Encoding) ? 0 : 1
|
|
107
|
+
customclass = obj.class.to_s.split('::')[p..-1].join('::') # strip Origami prefix if there is no collision
|
|
108
|
+
end
|
|
109
|
+
dictionaryToRuby(obj, inclevel, internalname, customclass)
|
|
110
|
+
when Origami::Array
|
|
111
|
+
arrayToRuby(obj, inclevel, internalname)
|
|
112
|
+
when Origami::Stream
|
|
113
|
+
streamToRuby(obj, internalname) unless obj.is_a?(ObjectStream) or obj.is_a?(XRefStream)
|
|
114
|
+
when Origami::Name
|
|
115
|
+
nameToRuby(obj)
|
|
116
|
+
when Origami::Reference
|
|
117
|
+
referenceToRuby(obj, internalname)
|
|
118
|
+
else
|
|
119
|
+
raise RuntimeError, "Unknown object type: #{obj.class}"
|
|
120
|
+
end
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
case obj
|
|
123
123
|
when Origami::String, Origami::Dictionary, Origami::Array, Origami::Name
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
code << ".to_o" if do_convert
|
|
125
|
+
end
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
code
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def referenceToRuby(ref, internalname)
|
|
131
|
-
|
|
131
|
+
varname = @var_hash[ref]
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
if varname.nil?
|
|
134
|
+
"nil"
|
|
135
|
+
elsif @obj_route[0..@current_idx].include?(varname)
|
|
136
|
+
@code_hash[varname] ||= {}
|
|
137
|
+
@code_hash[varname][:afterDecl] ||= []
|
|
138
|
+
@code_hash[varname][:afterDecl] << "#{internalname} = #{varname}"#.to_o.set_indirect(true)"
|
|
139
|
+
|
|
140
|
+
"nil"
|
|
141
|
+
else
|
|
142
|
+
@obj_route.push(varname) unless @obj_route.include?(varname)
|
|
143
|
+
varname
|
|
144
|
+
end
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
def nameToRuby(name)
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
code = ':'
|
|
149
|
+
valid = (name.value.to_s =~ /[+.:-]/).nil?
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
code << '"' unless valid
|
|
152
|
+
code << name.value.to_s
|
|
153
|
+
code << '"' unless valid
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
code
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
def arrayToRuby(arr, inclevel, internalname)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
159
|
+
i = 0
|
|
160
|
+
code = "\n" + " " * inclevel + "["
|
|
161
|
+
arr.each do |obj|
|
|
162
|
+
subintname = "#{internalname}[#{i}]"
|
|
163
|
+
|
|
164
|
+
code << "#{objectToRuby(obj, inclevel + 1, subintname)}"
|
|
165
|
+
code << ", " unless i == arr.length - 1
|
|
166
|
+
i = i + 1
|
|
167
|
+
end
|
|
168
|
+
code << "]"
|
|
169
|
+
|
|
170
|
+
code
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
def dictionaryToRuby(dict, inclevel, internalname, customtype = nil)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if customtype
|
|
178
|
-
code << "#{customtype}.new(#{dictionaryToHashMap(dict, inclevel, internalname)}"
|
|
179
|
-
code << " " * inclevel + ")"
|
|
180
|
-
else
|
|
181
|
-
code << "{\n"
|
|
182
|
-
dict.each_pair do |key, val|
|
|
183
|
-
rubyname = nameToRuby(key)
|
|
184
|
-
subintname = "#{internalname}[#{rubyname}]"
|
|
185
|
-
|
|
186
|
-
if val.is_a?(Origami::Reference) and @var_hash[val] and @var_hash[val][0,3] == "obj"
|
|
187
|
-
oldname = @var_hash[val]
|
|
188
|
-
newname = (key.value.to_s.downcase + "_" + @var_hash[val][4..-1]).gsub('.','_')
|
|
174
|
+
i = 0
|
|
175
|
+
code = "\n" + " " * inclevel
|
|
189
176
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
177
|
+
if customtype
|
|
178
|
+
code << "#{customtype}.new(#{dictionaryToHashMap(dict, inclevel, internalname)}"
|
|
179
|
+
code << " " * inclevel + ")"
|
|
180
|
+
else
|
|
181
|
+
code << "{\n"
|
|
182
|
+
dict.each_pair do |key, val|
|
|
183
|
+
rubyname = nameToRuby(key)
|
|
184
|
+
subintname = "#{internalname}[#{rubyname}]"
|
|
185
|
+
|
|
186
|
+
if val.is_a?(Origami::Reference) and @var_hash[val] and @var_hash[val][0,3] == "obj"
|
|
187
|
+
oldname = @var_hash[val]
|
|
188
|
+
newname = (key.value.to_s.downcase.gsub(/[^[[:alnum:]]]/,'_') + "_" + @var_hash[val][4..-1]).gsub('.','_')
|
|
189
|
+
|
|
190
|
+
if not @obj_route.include?(oldname)
|
|
191
|
+
@var_hash[val] = newname
|
|
192
|
+
@code_hash[newname] = @code_hash[oldname]
|
|
193
|
+
@code_hash.delete(oldname)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
code << " " * (inclevel + 1) +
|
|
198
|
+
"#{rubyname} => #{objectToRuby(val, inclevel + 2, subintname)}"
|
|
199
|
+
code << ", " unless i == dict.length - 1
|
|
200
|
+
|
|
201
|
+
i = i + 1
|
|
202
|
+
code << "\n"
|
|
194
203
|
end
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
code << " " * (inclevel + 1) +
|
|
198
|
-
"#{rubyname} => #{objectToRuby(val, inclevel + 2, subintname)}"
|
|
199
|
-
code << ", " unless i == dict.length - 1
|
|
200
|
-
|
|
201
|
-
i = i + 1
|
|
202
|
-
code << "\n"
|
|
204
|
+
|
|
205
|
+
code << " " * inclevel + "}"
|
|
203
206
|
end
|
|
204
|
-
code << " " * inclevel + "}"
|
|
205
|
-
end
|
|
206
207
|
|
|
207
|
-
|
|
208
|
+
code
|
|
208
209
|
end
|
|
209
210
|
|
|
210
211
|
def dictionaryToHashMap(dict, inclevel, internalname)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
212
|
+
i = 0
|
|
213
|
+
code = "\n"
|
|
214
|
+
dict.each_pair do |key, val|
|
|
215
|
+
rubyname = nameToRuby(key)
|
|
216
|
+
subintname = "#{internalname}[#{rubyname}]"
|
|
217
|
+
|
|
218
|
+
if val.is_a?(Origami::Reference) and @var_hash[val] and @var_hash[val][0,3] == "obj"
|
|
219
|
+
oldname = @var_hash[val]
|
|
220
|
+
newname = (key.value.to_s.downcase + "_" + @var_hash[val][4..-1]).gsub('.','_')
|
|
221
|
+
|
|
222
|
+
if not @obj_route.include?(oldname)
|
|
223
|
+
@var_hash[val] = newname
|
|
224
|
+
@code_hash[newname] = @code_hash[oldname]
|
|
225
|
+
@code_hash.delete(oldname)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
227
228
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
code << " " * (inclevel + 1) +
|
|
230
|
+
"#{rubyname} => #{objectToRuby(val, inclevel + 2, subintname)}"
|
|
231
|
+
code << ", " unless i == dict.length - 1
|
|
232
|
+
i = i + 1
|
|
233
|
+
code << "\n"
|
|
234
|
+
end
|
|
234
235
|
|
|
235
|
-
|
|
236
|
+
code
|
|
236
237
|
end
|
|
237
238
|
|
|
238
239
|
def streamToRuby(stm, internalname)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
240
|
+
dict = stm.dictionary.dup.delete_if{|k,v| k == :Length}
|
|
241
|
+
|
|
242
|
+
code = "Stream.new("
|
|
243
|
+
|
|
244
|
+
if @options[:xstreams]
|
|
245
|
+
stmdir = File.join(TARGET_DIR, STREAM_DIR)
|
|
246
|
+
Dir::mkdir(stmdir) unless File.directory? stmdir
|
|
247
|
+
stmfile = File.join(stmdir, "stm_#{stm.reference.refno}.data")
|
|
248
|
+
File.binwrite(stmfile, stm.data)
|
|
249
|
+
|
|
250
|
+
code << "File.binread('#{stmfile}')"
|
|
251
|
+
else
|
|
252
|
+
code << stm.data.inspect << ".b"
|
|
249
253
|
end
|
|
250
254
|
|
|
251
|
-
code << "
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
code << ", #{dictionaryToHashMap(dict, 1, internalname)}" unless dict.empty?
|
|
257
|
-
code << ")"
|
|
258
|
-
if stm.dictionary.has_key? :Filter
|
|
259
|
-
code << ".setFilter(#{objectToRuby(stm.Filter, 1, internalname)})"
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
code
|
|
255
|
+
code << ", #{dictionaryToHashMap(dict, 1, internalname)}" unless dict.empty?
|
|
256
|
+
code << ")"
|
|
257
|
+
|
|
258
|
+
code
|
|
263
259
|
end
|
|
264
260
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
verbosity = @options[:verbose] ? Parser::
|
|
268
|
-
target = PDF.read(TARGET, :
|
|
269
|
-
|
|
270
|
-
puts "Document successfully loaded into Origami"
|
|
261
|
+
puts "[*] ".red + "Loading document '#{TARGET}'"
|
|
262
|
+
|
|
263
|
+
verbosity = @options[:verbose] ? Parser::VERBOSE_TRACE : Parser::VERBOSE_QUIET
|
|
264
|
+
target = PDF.read(TARGET, verbosity: verbosity)
|
|
265
|
+
puts "[*] ".red + "Document successfully loaded into Origami"
|
|
271
266
|
|
|
272
267
|
Dir::mkdir(TARGET_DIR) unless File.directory? TARGET_DIR
|
|
273
268
|
fd = File.open(TARGET_FILE, 'w', 0700)
|
|
274
269
|
|
|
275
270
|
DOCREF = "pdf"
|
|
276
|
-
ORIGAMI_PATH = ORIGAMIDIR[0,1] == '/' ?
|
|
277
|
-
ORIGAMIDIR :
|
|
278
|
-
"../#{ORIGAMIDIR}"
|
|
279
271
|
|
|
280
272
|
fd.puts <<RUBY
|
|
281
273
|
#!/usr/bin/env ruby
|
|
282
274
|
|
|
283
275
|
begin
|
|
284
|
-
|
|
276
|
+
require 'origami'
|
|
285
277
|
rescue LoadError
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
require 'origami'
|
|
278
|
+
$: << "#{File.join(__dir__, '../lib')}"
|
|
279
|
+
require 'origami'
|
|
289
280
|
end
|
|
290
281
|
include Origami
|
|
282
|
+
using Origami::TypeConversion
|
|
283
|
+
|
|
284
|
+
# Disable automatic type casting.
|
|
285
|
+
Origami::OPTIONS[:enable_type_guessing] = false
|
|
291
286
|
|
|
292
287
|
OUTPUT = "\#{File.basename(__FILE__, '.rb')}.pdf"
|
|
293
288
|
|
|
@@ -298,50 +293,42 @@ OUTPUT = "\#{File.basename(__FILE__, '.rb')}.pdf"
|
|
|
298
293
|
|
|
299
294
|
RUBY
|
|
300
295
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
varname = "obj_" + obj.no.to_s
|
|
306
|
-
@var_hash[obj.reference] = varname
|
|
296
|
+
puts "[*] ".red + "Retrieving all indirect objects..."
|
|
297
|
+
target.each_object(compressed: true) do |obj|
|
|
298
|
+
varname = "obj_" + obj.no.to_s
|
|
299
|
+
@var_hash[obj.reference] = varname
|
|
307
300
|
end
|
|
308
301
|
|
|
309
|
-
|
|
310
|
-
puts "Retrieving the document Catalog..."
|
|
302
|
+
puts "[*] ".red + "Retrieving the document Catalog..."
|
|
311
303
|
catalog = target.Catalog
|
|
312
304
|
|
|
313
305
|
@var_hash[catalog.reference] = "#{DOCREF}.Catalog"
|
|
314
306
|
@obj_route.push "#{DOCREF}.Catalog"
|
|
315
307
|
|
|
316
|
-
|
|
317
|
-
puts "Processing the object hierarchy..."
|
|
308
|
+
puts "[*] ".red + "Processing the object hierarchy..."
|
|
318
309
|
@current_idx = 0
|
|
319
310
|
while @current_idx != @obj_route.size
|
|
320
|
-
|
|
321
|
-
if RUBY_VERSION < '1.9'
|
|
322
|
-
obj = target[@var_hash.index(varname)]
|
|
323
|
-
else
|
|
311
|
+
varname = @obj_route[@current_idx]
|
|
324
312
|
obj = target[@var_hash.key(varname)]
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
@code_hash[varname] ||= {}
|
|
328
|
-
@code_hash[varname][:body] = objectToRuby(obj, 0, varname, true)
|
|
329
313
|
|
|
330
|
-
|
|
314
|
+
@code_hash[varname] ||= {}
|
|
315
|
+
@code_hash[varname][:body] = objectToRuby(obj, 0, varname, true)
|
|
316
|
+
|
|
317
|
+
@current_idx = @current_idx + 1
|
|
331
318
|
end
|
|
332
319
|
|
|
333
320
|
@obj_route.reverse.each do |varname|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
321
|
+
fd.puts "#{varname} = #{@code_hash[varname][:body]}"
|
|
322
|
+
if @code_hash[varname][:afterDecl]
|
|
323
|
+
@code_hash[varname][:afterDecl].each do |decl|
|
|
324
|
+
fd.puts decl
|
|
325
|
+
end
|
|
338
326
|
end
|
|
339
|
-
|
|
340
|
-
fd.puts
|
|
327
|
+
fd.puts
|
|
341
328
|
end
|
|
342
329
|
|
|
343
330
|
@obj_route.each do |varname|
|
|
344
|
-
|
|
331
|
+
fd.puts "#{DOCREF}.insert(#{varname})" unless varname == "#{DOCREF}.Catalog"
|
|
345
332
|
end
|
|
346
333
|
fd.puts
|
|
347
334
|
|
|
@@ -350,11 +337,8 @@ fd.puts <<RUBY
|
|
|
350
337
|
# Saves the document.
|
|
351
338
|
#
|
|
352
339
|
#{DOCREF}.save(OUTPUT)
|
|
353
|
-
|
|
354
340
|
RUBY
|
|
355
341
|
|
|
356
|
-
|
|
357
|
-
puts "Successfully generated script '#{TARGET_FILE}'"
|
|
358
|
-
fd.close
|
|
359
|
-
exit
|
|
342
|
+
puts "[*] ".red + "Successfully generated script '#{TARGET_FILE}'"
|
|
360
343
|
|
|
344
|
+
fd.close
|