origami 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING.LESSER +165 -0
- data/README +77 -0
- data/VERSION +1 -0
- data/bin/config/pdfcop.conf.yml +237 -0
- data/bin/gui/about.rb +46 -0
- data/bin/gui/config.rb +132 -0
- data/bin/gui/file.rb +385 -0
- data/bin/gui/hexdump.rb +74 -0
- data/bin/gui/hexview.rb +91 -0
- data/bin/gui/imgview.rb +72 -0
- data/bin/gui/menu.rb +392 -0
- data/bin/gui/properties.rb +132 -0
- data/bin/gui/signing.rb +635 -0
- data/bin/gui/textview.rb +107 -0
- data/bin/gui/treeview.rb +409 -0
- data/bin/gui/walker.rb +282 -0
- data/bin/gui/xrefs.rb +79 -0
- data/bin/pdf2graph +121 -0
- data/bin/pdf2ruby +353 -0
- data/bin/pdfcocoon +104 -0
- data/bin/pdfcop +455 -0
- data/bin/pdfdecompress +104 -0
- data/bin/pdfdecrypt +95 -0
- data/bin/pdfencrypt +112 -0
- data/bin/pdfextract +221 -0
- data/bin/pdfmetadata +123 -0
- data/bin/pdfsh +13 -0
- data/bin/pdfwalker +7 -0
- data/bin/shell/.irbrc +104 -0
- data/bin/shell/console.rb +136 -0
- data/bin/shell/hexdump.rb +83 -0
- data/origami.rb +36 -0
- data/origami/3d.rb +239 -0
- data/origami/acroform.rb +321 -0
- data/origami/actions.rb +299 -0
- data/origami/adobe/fdf.rb +259 -0
- data/origami/adobe/ppklite.rb +489 -0
- data/origami/annotations.rb +775 -0
- data/origami/array.rb +187 -0
- data/origami/boolean.rb +101 -0
- data/origami/catalog.rb +486 -0
- data/origami/destinations.rb +213 -0
- data/origami/dictionary.rb +188 -0
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +1293 -0
- data/origami/export.rb +283 -0
- data/origami/file.rb +222 -0
- data/origami/filters.rb +250 -0
- data/origami/filters/ascii.rb +189 -0
- data/origami/filters/ccitt.rb +515 -0
- data/origami/filters/crypt.rb +47 -0
- data/origami/filters/dct.rb +61 -0
- data/origami/filters/flate.rb +112 -0
- data/origami/filters/jbig2.rb +63 -0
- data/origami/filters/jpx.rb +53 -0
- data/origami/filters/lzw.rb +195 -0
- data/origami/filters/predictors.rb +276 -0
- data/origami/filters/runlength.rb +117 -0
- data/origami/font.rb +209 -0
- data/origami/functions.rb +93 -0
- data/origami/graphics.rb +33 -0
- data/origami/graphics/colors.rb +191 -0
- data/origami/graphics/instruction.rb +126 -0
- data/origami/graphics/path.rb +154 -0
- data/origami/graphics/patterns.rb +180 -0
- data/origami/graphics/state.rb +164 -0
- data/origami/graphics/text.rb +224 -0
- data/origami/graphics/xobject.rb +493 -0
- data/origami/header.rb +90 -0
- data/origami/linearization.rb +318 -0
- data/origami/metadata.rb +114 -0
- data/origami/name.rb +170 -0
- data/origami/null.rb +75 -0
- data/origami/numeric.rb +188 -0
- data/origami/obfuscation.rb +233 -0
- data/origami/object.rb +527 -0
- data/origami/outline.rb +59 -0
- data/origami/page.rb +559 -0
- data/origami/parser.rb +268 -0
- data/origami/parsers/fdf.rb +45 -0
- data/origami/parsers/pdf.rb +27 -0
- data/origami/parsers/pdf/linear.rb +113 -0
- data/origami/parsers/ppklite.rb +86 -0
- data/origami/pdf.rb +1144 -0
- data/origami/reference.rb +113 -0
- data/origami/signature.rb +474 -0
- data/origami/stream.rb +575 -0
- data/origami/string.rb +416 -0
- data/origami/trailer.rb +173 -0
- data/origami/webcapture.rb +87 -0
- data/origami/xfa.rb +3027 -0
- data/origami/xreftable.rb +447 -0
- data/templates/patterns.rb +66 -0
- data/templates/widgets.rb +173 -0
- data/templates/xdp.rb +92 -0
- data/tests/dataset/test.dummycrt +28 -0
- data/tests/dataset/test.dummykey +27 -0
- data/tests/tc_actions.rb +32 -0
- data/tests/tc_annotations.rb +85 -0
- data/tests/tc_pages.rb +37 -0
- data/tests/tc_pdfattach.rb +24 -0
- data/tests/tc_pdfencrypt.rb +110 -0
- data/tests/tc_pdfnew.rb +32 -0
- data/tests/tc_pdfparse.rb +98 -0
- data/tests/tc_pdfsig.rb +37 -0
- data/tests/tc_streams.rb +129 -0
- data/tests/ts_pdf.rb +45 -0
- metadata +193 -0
data/bin/pdfdecompress
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Author:
|
6
|
+
Guillaume Delugré <guillaume/at/security-labs.org>
|
7
|
+
|
8
|
+
= Info:
|
9
|
+
Uncompresses all binary streams of a PDF document.
|
10
|
+
|
11
|
+
= License:
|
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.
|
16
|
+
|
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.
|
21
|
+
|
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/>.
|
24
|
+
|
25
|
+
=end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'origami'
|
29
|
+
rescue LoadError
|
30
|
+
ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
|
31
|
+
$: << ORIGAMIDIR
|
32
|
+
require 'origami'
|
33
|
+
end
|
34
|
+
include Origami
|
35
|
+
|
36
|
+
require 'optparse'
|
37
|
+
|
38
|
+
class OptParser
|
39
|
+
BANNER = <<USAGE
|
40
|
+
Usage: #{$0} [<PDF-file>] [-p <password>] [-o <output-file>]
|
41
|
+
Uncompresses all binary streams of a PDF document.
|
42
|
+
Bug reports or feature requests at: http://origami-pdf.googlecode.com/
|
43
|
+
|
44
|
+
Options:
|
45
|
+
USAGE
|
46
|
+
|
47
|
+
def self.parser(options)
|
48
|
+
OptionParser.new do |opts|
|
49
|
+
opts.banner = BANNER
|
50
|
+
|
51
|
+
opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
|
52
|
+
options[:output] = o
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
56
|
+
puts opts
|
57
|
+
exit
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.parse(args)
|
63
|
+
options =
|
64
|
+
{
|
65
|
+
:output => STDOUT,
|
66
|
+
}
|
67
|
+
|
68
|
+
self.parser(options).parse!(args)
|
69
|
+
|
70
|
+
options
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
@options = OptParser.parse(ARGV)
|
76
|
+
|
77
|
+
target = (ARGV.empty?) ? STDIN : ARGV.shift
|
78
|
+
params =
|
79
|
+
{
|
80
|
+
:verbosity => Parser::VERBOSE_QUIET,
|
81
|
+
}
|
82
|
+
|
83
|
+
pdf = PDF.read(target, params)
|
84
|
+
|
85
|
+
pdf.root_objects.find_all { |obj|
|
86
|
+
obj.is_a?(Stream)
|
87
|
+
}.each { |stream|
|
88
|
+
filters = stream.Filter
|
89
|
+
filters = [ filters ] unless filters.is_a?(::Array)
|
90
|
+
|
91
|
+
unless filters.any?{|filter| [ :JPXDecode, :DCTDecode, :JBIG2Decode ].include? filter}
|
92
|
+
stream.rawdata = stream.data
|
93
|
+
stream.dictionary.delete(:Filter)
|
94
|
+
end
|
95
|
+
}
|
96
|
+
|
97
|
+
pdf.save(@options[:output], :noindent => true)
|
98
|
+
|
99
|
+
rescue SystemExit
|
100
|
+
rescue Exception => e
|
101
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
|
data/bin/pdfdecrypt
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Author:
|
6
|
+
Guillaume Delugré <guillaume/at/security-labs.org>
|
7
|
+
|
8
|
+
= Info:
|
9
|
+
Decrypts a PDF document.
|
10
|
+
|
11
|
+
= License:
|
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.
|
16
|
+
|
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.
|
21
|
+
|
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/>.
|
24
|
+
|
25
|
+
=end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'origami'
|
29
|
+
rescue LoadError
|
30
|
+
ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
|
31
|
+
$: << ORIGAMIDIR
|
32
|
+
require 'origami'
|
33
|
+
end
|
34
|
+
include Origami
|
35
|
+
|
36
|
+
require 'optparse'
|
37
|
+
|
38
|
+
class OptParser
|
39
|
+
BANNER = <<USAGE
|
40
|
+
Usage: #{$0} [<PDF-file>] [-p <password>] [-o <output-file>]
|
41
|
+
Decrypts a PDF document. Supports RC4 40 to 128 bits, AES128, AES256.
|
42
|
+
Bug reports or feature requests at: http://origami-pdf.googlecode.com/
|
43
|
+
|
44
|
+
Options:
|
45
|
+
USAGE
|
46
|
+
|
47
|
+
def self.parser(options)
|
48
|
+
OptionParser.new do |opts|
|
49
|
+
opts.banner = BANNER
|
50
|
+
|
51
|
+
opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
|
52
|
+
options[:output] = o
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-p", "--password PASSWORD", "Password of the document") do |p|
|
56
|
+
options[:password] = p
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
60
|
+
puts opts
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.parse(args)
|
67
|
+
options =
|
68
|
+
{
|
69
|
+
:output => STDOUT,
|
70
|
+
:password => ''
|
71
|
+
}
|
72
|
+
|
73
|
+
self.parser(options).parse!(args)
|
74
|
+
|
75
|
+
options
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
begin
|
80
|
+
@options = OptParser.parse(ARGV)
|
81
|
+
|
82
|
+
target = (ARGV.empty?) ? STDIN : ARGV.shift
|
83
|
+
params =
|
84
|
+
{
|
85
|
+
:verbosity => Parser::VERBOSE_QUIET,
|
86
|
+
:password => @options[:password]
|
87
|
+
}
|
88
|
+
|
89
|
+
PDF.read(target, params).save(@options[:output], :decrypt => true, :noindent => true)
|
90
|
+
rescue SystemExit
|
91
|
+
rescue Exception => e
|
92
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
|
data/bin/pdfencrypt
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Author:
|
6
|
+
Guillaume Delugré <guillaume/at/security-labs.org>
|
7
|
+
|
8
|
+
= Info:
|
9
|
+
Encrypts a PDF document.
|
10
|
+
|
11
|
+
= License:
|
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.
|
16
|
+
|
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.
|
21
|
+
|
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/>.
|
24
|
+
|
25
|
+
=end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'origami'
|
29
|
+
rescue LoadError
|
30
|
+
ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
|
31
|
+
$: << ORIGAMIDIR
|
32
|
+
require 'origami'
|
33
|
+
end
|
34
|
+
include Origami
|
35
|
+
|
36
|
+
require 'optparse'
|
37
|
+
|
38
|
+
class OptParser
|
39
|
+
BANNER = <<USAGE
|
40
|
+
Usage: #{$0} [<PDF-file>] [-p <password>] [-c <cipher>] [-s <key-size>] [-o <output-file>]
|
41
|
+
Encrypts a PDF document. Supports RC4 40 to 128 bits, AES128, AES256.
|
42
|
+
Bug reports or feature requests at: http://origami-pdf.googlecode.com/
|
43
|
+
|
44
|
+
Options:
|
45
|
+
USAGE
|
46
|
+
|
47
|
+
def self.parser(options)
|
48
|
+
OptionParser.new do |opts|
|
49
|
+
opts.banner = BANNER
|
50
|
+
|
51
|
+
opts.on("-o", "--output FILE", "Output PDF file (stdout by default)") do |o|
|
52
|
+
options[:output] = o
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-p", "--password PASSWORD", "Password of the document") do |p|
|
56
|
+
options[:password] = p
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-c", "--cipher CIPHER", "Cipher used to encrypt the document (Default: AES)") do |c|
|
60
|
+
options[:cipher] = c
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-s", "--key-size KEYSIZE", "Key size in bits (Default: 128)") do |s|
|
64
|
+
options[:key_size] = s.to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
68
|
+
puts opts
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.parse(args)
|
75
|
+
options =
|
76
|
+
{
|
77
|
+
:output => STDOUT,
|
78
|
+
:password => '',
|
79
|
+
:cipher => 'aes',
|
80
|
+
:key_size => 128
|
81
|
+
}
|
82
|
+
|
83
|
+
self.parser(options).parse!(args)
|
84
|
+
|
85
|
+
options
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
begin
|
90
|
+
@options = OptParser.parse(ARGV)
|
91
|
+
|
92
|
+
target = (ARGV.empty?) ? STDIN : ARGV.shift
|
93
|
+
params =
|
94
|
+
{
|
95
|
+
:verbosity => Parser::VERBOSE_QUIET,
|
96
|
+
}
|
97
|
+
|
98
|
+
pdf = PDF.read(target, params)
|
99
|
+
pdf.encrypt(
|
100
|
+
:user_password => @options[:password],
|
101
|
+
:owner_password => @options[:password],
|
102
|
+
:cipher => @options[:cipher],
|
103
|
+
:key_size => @options[:key_size]
|
104
|
+
)
|
105
|
+
pdf.save(@options[:output], :noindent => true)
|
106
|
+
|
107
|
+
rescue SystemExit
|
108
|
+
rescue Exception => e
|
109
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
|
data/bin/pdfextract
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Author:
|
6
|
+
Guillaume Delugré <guillaume/at/security-labs.org>
|
7
|
+
|
8
|
+
= Info:
|
9
|
+
Extracts valuable data from a PDF document. Can extract:
|
10
|
+
- decoded streams
|
11
|
+
- JavaScript
|
12
|
+
- file attachments
|
13
|
+
|
14
|
+
= License:
|
15
|
+
Origami is free software: you can redistribute it and/or modify
|
16
|
+
it under the terms of the GNU Lesser General Public License as published by
|
17
|
+
the Free Software Foundation, either version 3 of the License, or
|
18
|
+
(at your option) any later version.
|
19
|
+
|
20
|
+
Origami is distributed in the hope that it will be useful,
|
21
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
22
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
23
|
+
GNU Lesser General Public License for more details.
|
24
|
+
|
25
|
+
You should have received a copy of the GNU Lesser General Public License
|
26
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
27
|
+
|
28
|
+
=end
|
29
|
+
|
30
|
+
begin
|
31
|
+
require 'origami'
|
32
|
+
rescue LoadError
|
33
|
+
ORIGAMIDIR = "#{File.dirname(__FILE__)}/.."
|
34
|
+
$: << ORIGAMIDIR
|
35
|
+
require 'origami'
|
36
|
+
end
|
37
|
+
include Origami
|
38
|
+
|
39
|
+
require 'optparse'
|
40
|
+
require 'rexml/document'
|
41
|
+
|
42
|
+
class OptParser
|
43
|
+
BANNER = <<USAGE
|
44
|
+
Usage: #{$0} <PDF-file> [-afjms] [-d <output-directory>]
|
45
|
+
Extracts various data out of a document (streams, scripts, fonts, metadata, attachments).
|
46
|
+
Bug reports or feature requests at: http://origami-pdf.googlecode.com/
|
47
|
+
|
48
|
+
Options:
|
49
|
+
USAGE
|
50
|
+
|
51
|
+
def self.parser(options)
|
52
|
+
OptionParser.new do |opts|
|
53
|
+
opts.banner = BANNER
|
54
|
+
|
55
|
+
opts.on("-d", "--output-dir DIR", "Output directory") do |d|
|
56
|
+
options[:output_dir] = d
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-s", "--streams", "Extracts all decoded streams") do
|
60
|
+
options[:streams] = true
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-a", "--attachments", "Extracts file attachments") do
|
64
|
+
options[:attachments] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-f", "--fonts", "Extracts embedded font files") do
|
68
|
+
options[:fonts] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on("-j", "--js", "Extracts JavaScript scripts") do
|
72
|
+
options[:javascript] = true
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on("-m", "--metadata", "Extracts metadata streams") do
|
76
|
+
options[:metadata] = true
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
80
|
+
puts opts
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.parse(args)
|
87
|
+
options =
|
88
|
+
{
|
89
|
+
}
|
90
|
+
|
91
|
+
self.parser(options).parse!(args)
|
92
|
+
|
93
|
+
options
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
begin
|
98
|
+
@options = OptParser.parse(ARGV)
|
99
|
+
|
100
|
+
if ARGV.empty?
|
101
|
+
STDERR.puts "Error: No filename was specified. #{$0} --help for details."
|
102
|
+
exit 1
|
103
|
+
else
|
104
|
+
target = ARGV.shift
|
105
|
+
end
|
106
|
+
|
107
|
+
unless [:streams,:javascript,:attachments,:fonts,:metadata].any? {|opt| @options[opt]}
|
108
|
+
@options[:streams] =
|
109
|
+
@options[:javascript] =
|
110
|
+
@options[:fonts] =
|
111
|
+
@options[:attachments] = true
|
112
|
+
end
|
113
|
+
|
114
|
+
if @options[:output_dir].nil?
|
115
|
+
@options[:output_dir] = "#{File.basename(target, '.pdf')}.dump"
|
116
|
+
end
|
117
|
+
|
118
|
+
OUTPUT_DIR = @options[:output_dir]
|
119
|
+
Dir::mkdir(OUTPUT_DIR) unless File.directory?(OUTPUT_DIR)
|
120
|
+
|
121
|
+
params =
|
122
|
+
{
|
123
|
+
:verbosity => Parser::VERBOSE_QUIET,
|
124
|
+
}
|
125
|
+
pdf = PDF.read(target, params)
|
126
|
+
|
127
|
+
if @options[:streams]
|
128
|
+
pdf.root_objects.find_all{|obj| obj.is_a?(Stream)}.each do |stream|
|
129
|
+
stream_file = "#{OUTPUT_DIR}/stream_#{stream.reference.refno}.dmp"
|
130
|
+
File.open(stream_file, "w") do |fd|
|
131
|
+
fd.write(stream.data)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if @options[:javascript]
|
137
|
+
pdf.ls(/^JS$/).each do |script|
|
138
|
+
script_file = "#{OUTPUT_DIR}/script_#{script.hash}.js"
|
139
|
+
File.open(script_file, "w") do |fd|
|
140
|
+
fd.write(
|
141
|
+
case script
|
142
|
+
when Stream then
|
143
|
+
script.data
|
144
|
+
else
|
145
|
+
script.value
|
146
|
+
end
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Also checking for presence of JavaScript in XML forms.
|
152
|
+
if pdf.has_form? and pdf.Catalog.AcroForm.has_key?(:XFA)
|
153
|
+
xfa = pdf.Catalog.AcroForm[:XFA].solve
|
154
|
+
|
155
|
+
case xfa
|
156
|
+
when Array then
|
157
|
+
xml = ""
|
158
|
+
i = 0
|
159
|
+
xfa.each do |packet|
|
160
|
+
if i % 2 == 1
|
161
|
+
xml << packet.solve.data
|
162
|
+
end
|
163
|
+
|
164
|
+
i = i + 1
|
165
|
+
end
|
166
|
+
when Stream then
|
167
|
+
xml = xfa.data
|
168
|
+
else
|
169
|
+
reject("Malformed XFA dictionary")
|
170
|
+
end
|
171
|
+
|
172
|
+
xfadoc = REXML::Document.new(xml)
|
173
|
+
REXML::XPath.match(xfadoc, "//script").each do |script|
|
174
|
+
script_file = "#{OUTPUT_DIR}/script_#{script.hash}.js"
|
175
|
+
File.open(script_file, 'w') do |fd|
|
176
|
+
fd.write(script.text)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if @options[:attachments]
|
183
|
+
pdf.ls_names(Names::Root::EMBEDDEDFILES).each do |name, attachment|
|
184
|
+
attached_file = "#{OUTPUT_DIR}/attached_#{File.basename(name)}"
|
185
|
+
spec = attachment.solve
|
186
|
+
ef = spec[:EF].solve
|
187
|
+
f = ef[:F].solve
|
188
|
+
|
189
|
+
File.open(attached_file, "w") do |fd|
|
190
|
+
fd.write(f.data)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
if @options[:fonts]
|
196
|
+
pdf.root_objects.find_all{|obj| obj.is_a?(Stream)}.each do |stream|
|
197
|
+
font = stream.xrefs.find{|obj| obj.is_a?(FontDescriptor)}
|
198
|
+
if font
|
199
|
+
font_file = "#{OUTPUT_DIR}/font_#{File.basename(font.FontName.value.to_s)}"
|
200
|
+
File.open(font_file, "w") do |fd|
|
201
|
+
fd.write(stream.data)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
if @options[:metadata]
|
208
|
+
pdf.root_objects.find_all{|obj| obj.is_a?(MetadataStream)}.each do |stream|
|
209
|
+
metadata_file = "#{OUTPUT_DIR}/metadata_#{stream.reference.refno}.xml"
|
210
|
+
File.open(metadata_file, "w") do |fd|
|
211
|
+
fd.write(stream.data)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
rescue SystemExit
|
217
|
+
rescue Exception => e
|
218
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
219
|
+
exit 1
|
220
|
+
end
|
221
|
+
|