origami 1.2.5 → 1.2.6
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 +7 -0
- data/bin/gui/config.rb +0 -4
- data/bin/gui/imgview.rb +2 -2
- data/bin/gui/menu.rb +11 -3
- data/bin/gui/treeview.rb +9 -3
- data/bin/pdfexplode +220 -0
- data/bin/pdfextract +3 -0
- data/lib/origami/acroform.rb +2 -2
- data/lib/origami/actions.rb +62 -35
- data/lib/origami/annotations.rb +3 -2
- data/lib/origami/array.rb +27 -4
- data/lib/origami/boolean.rb +2 -2
- data/lib/origami/catalog.rb +45 -45
- data/lib/origami/dictionary.rb +87 -14
- data/lib/origami/encryption.rb +46 -24
- data/lib/origami/file.rb +1 -2
- data/lib/origami/filters/ccitt.rb +118 -66
- data/lib/origami/filters/flate.rb +5 -1
- data/lib/origami/filters.rb +84 -2
- data/lib/origami/font.rb +71 -71
- data/lib/origami/graphics/patterns.rb +2 -1
- data/lib/origami/graphics/xobject.rb +123 -1
- data/lib/origami/javascript.rb +2 -1
- data/lib/origami/name.rb +2 -2
- data/lib/origami/null.rb +2 -2
- data/lib/origami/numeric.rb +11 -3
- data/lib/origami/object.rb +37 -16
- data/lib/origami/page.rb +135 -71
- data/lib/origami/parser.rb +11 -4
- data/lib/origami/parsers/pdf/linear.rb +1 -0
- data/lib/origami/parsers/pdf.rb +10 -0
- data/lib/origami/pdf.rb +10 -70
- data/lib/origami/reference.rb +4 -5
- data/lib/origami/signature.rb +22 -8
- data/lib/origami/stream.rb +41 -20
- data/lib/origami/string.rb +15 -6
- data/lib/origami/trailer.rb +9 -5
- data/lib/origami.rb +19 -0
- data/samples/actions/loop/loopgoto.rb +1 -1
- data/samples/actions/loop/loopnamed.rb +2 -2
- data/samples/actions/named/named.rb +1 -1
- data/samples/actions/samba/smbrelay.rb +1 -1
- data/samples/actions/triggerevents/trigger.rb +13 -13
- data/samples/actions/webbug/webbug-browser.rb +1 -1
- data/samples/actions/webbug/webbug-js.rb +1 -1
- data/samples/actions/webbug/webbug-reader.rb +1 -1
- data/samples/attachments/attach.rb +2 -2
- data/samples/exploits/cve-2008-2992-utilprintf.rb +1 -1
- data/samples/exploits/cve-2009-0927-geticon.rb +1 -1
- data/samples/exploits/exploit_customdictopen.rb +2 -2
- data/samples/exploits/getannots.rb +1 -1
- data/samples/javascript/js.rb +2 -2
- data/test/ts_pdf.rb +23 -23
- metadata +71 -86
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 400584bfa83ed0b47e3501f85f6ea19733aa365a
|
4
|
+
data.tar.gz: ebe216889afe825f5ea850ac3a330b7b462afb0a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5383fd775e5eb11a8a2a1212b4e8523f9751974fae787fd72074206e435b29b6e5d915c05154e25c12617733b317f20e5a3cd3c7f099a275ec995ce55308bb8
|
7
|
+
data.tar.gz: 5dd566b2f6cedca2b1be9b124d809efb46cc8057fc4f6ffbd5a7f22a56c165da1ff0fd1e1ea0e8be8695d98ef8363adbefafeb77fcab256ddea3dad38cbe674a
|
data/bin/gui/config.rb
CHANGED
@@ -96,10 +96,8 @@ module PDFWalker
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def set_verbosity(level)
|
99
|
-
|
100
99
|
@conf["Debug"]['Verbosity'] = level
|
101
100
|
save
|
102
|
-
|
103
101
|
end
|
104
102
|
|
105
103
|
def verbosity
|
@@ -113,11 +111,9 @@ module PDFWalker
|
|
113
111
|
private
|
114
112
|
|
115
113
|
def set_missing_values
|
116
|
-
|
117
114
|
@conf ||= {}
|
118
115
|
|
119
116
|
DEFAULT_CONFIG.each_key do |cat|
|
120
|
-
|
121
117
|
@conf[cat] = {} unless @conf.include?(cat)
|
122
118
|
|
123
119
|
DEFAULT_CONFIG[cat].each_pair do |key, value|
|
data/bin/gui/imgview.rb
CHANGED
@@ -41,11 +41,11 @@ module PDFWalker
|
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
44
|
-
def show_raw_img(data, w, h,
|
44
|
+
def show_raw_img(data, w, h, bpc, bpr)
|
45
45
|
set_default_size w,h
|
46
46
|
|
47
47
|
pixbuf = Gdk::Pixbuf.new data,
|
48
|
-
Gdk::Pixbuf::ColorSpace::RGB, false,
|
48
|
+
Gdk::Pixbuf::ColorSpace::RGB, false, bpc,
|
49
49
|
w, h,
|
50
50
|
bpr
|
51
51
|
|
data/bin/gui/menu.rb
CHANGED
@@ -153,8 +153,16 @@ module PDFWalker
|
|
153
153
|
:Callback => lambda { |widget, viewer, path|
|
154
154
|
stm = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
|
155
155
|
w,h = stm.Width, stm.Height
|
156
|
+
colors =
|
157
|
+
case stm.ColorSpace
|
158
|
+
when :DeviceGray.to_o then 1
|
159
|
+
when :DeviceRGB.to_o then 3
|
160
|
+
when :DeviceCMYK.to_o then 4
|
161
|
+
else
|
162
|
+
1
|
163
|
+
end
|
156
164
|
bpc = stm.BitsPerComponent || 8
|
157
|
-
bpr = (bpc
|
165
|
+
bpr = (w * colors * bpc + 7) >> 3
|
158
166
|
data = stm.data
|
159
167
|
|
160
168
|
begin
|
@@ -162,7 +170,7 @@ module PDFWalker
|
|
162
170
|
if stm.Filter == :DCTDecode or (stm.Filter.is_a?(Array) and stm.Filter[0] == :DCTDecode)
|
163
171
|
imgview.show_compressed_img data
|
164
172
|
else
|
165
|
-
imgview.show_raw_img data, w, h,
|
173
|
+
imgview.show_raw_img data, w, h, bpc, bpr
|
166
174
|
end
|
167
175
|
rescue Exception => e
|
168
176
|
viewer.parent.error("#{e.class}: #{e.message}")
|
@@ -179,7 +187,7 @@ module PDFWalker
|
|
179
187
|
if obj.is_a?(Graphics::ImageXObject)
|
180
188
|
:Image
|
181
189
|
else
|
182
|
-
obj.
|
190
|
+
obj.native_type.to_s.split("::").last.to_sym
|
183
191
|
end
|
184
192
|
else case obj
|
185
193
|
when Origami::PDF
|
data/bin/gui/treeview.rb
CHANGED
@@ -107,7 +107,7 @@ module PDFWalker
|
|
107
107
|
expand_row(path, false)
|
108
108
|
end
|
109
109
|
|
110
|
-
goto(obj
|
110
|
+
goto(obj) if obj.is_a?(Origami::Reference)
|
111
111
|
end
|
112
112
|
}
|
113
113
|
|
@@ -136,7 +136,13 @@ module PDFWalker
|
|
136
136
|
if obj.is_a?(Name) and obj.parent.is_a?(Dictionary) and obj.parent.has_key?(obj)
|
137
137
|
obj = obj.parent[obj]
|
138
138
|
elsif obj.is_a?(Reference)
|
139
|
-
obj =
|
139
|
+
obj =
|
140
|
+
begin
|
141
|
+
obj.solve
|
142
|
+
rescue InvalidReferenceError
|
143
|
+
@parent.error("Object not found : #{obj}")
|
144
|
+
return
|
145
|
+
end
|
140
146
|
end
|
141
147
|
|
142
148
|
@treestore.each { |model, path, iter|
|
@@ -279,7 +285,7 @@ module PDFWalker
|
|
279
285
|
obj = @treestore.append(container)
|
280
286
|
@treestore.set_value(obj, OBJCOL, object)
|
281
287
|
|
282
|
-
type = object.
|
288
|
+
type = object.native_type.to_s.split('::').last.to_sym
|
283
289
|
|
284
290
|
if name.nil?
|
285
291
|
name =
|
data/bin/pdfexplode
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
= Author:
|
6
|
+
Guillaume Delugré <guillaume/at/security-labs.org>
|
7
|
+
|
8
|
+
= Info:
|
9
|
+
Explodes a PDF into separate documents.
|
10
|
+
= License:
|
11
|
+
Origami is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU Lesser 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
|
+
Origami 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 Lesser General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU Lesser General Public License
|
22
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'origami'
|
28
|
+
rescue LoadError
|
29
|
+
ORIGAMIDIR = "#{File.dirname(__FILE__)}/../lib"
|
30
|
+
$: << ORIGAMIDIR
|
31
|
+
require 'origami'
|
32
|
+
end
|
33
|
+
include Origami
|
34
|
+
|
35
|
+
require 'optparse'
|
36
|
+
require 'rexml/document'
|
37
|
+
|
38
|
+
class OptParser
|
39
|
+
BANNER = <<USAGE
|
40
|
+
Usage: #{$0} <PDF-file> [-r <range>] [-t pages|rsrc] [-d <output-directory>]
|
41
|
+
Explodes a document into separate documents.
|
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("-d", "--output-dir DIR", "Output directory.") do |d|
|
52
|
+
options[:output_dir] = d
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-r", "--range PAGES", "Page range (e.g: 2-, 1-3, 5). Default to '-'.") do |r|
|
56
|
+
range =
|
57
|
+
if r.index('-').nil?
|
58
|
+
page = r.to_i
|
59
|
+
Range.new(page-1, page-1)
|
60
|
+
else
|
61
|
+
from, to = r.split('-').map{|bound| bound.to_i}
|
62
|
+
from ||= 1
|
63
|
+
to ||= 0
|
64
|
+
Range.new(from-1, to-1)
|
65
|
+
end
|
66
|
+
options[:page_range] = range
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("-t", "--type TYPE", "Split by type. Can be 'pages' or 'rsrc'. Default to 'pages'.") do |t|
|
70
|
+
options[:split_by] = t
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on_tail("-h", "--help", "Show this message.") do
|
74
|
+
puts opts
|
75
|
+
exit
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.parse(args)
|
81
|
+
options =
|
82
|
+
{
|
83
|
+
:page_range => (0..-1),
|
84
|
+
:split_by => 'pages'
|
85
|
+
}
|
86
|
+
|
87
|
+
self.parser(options).parse!(args)
|
88
|
+
|
89
|
+
options
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
begin
|
94
|
+
@options = OptParser.parse(ARGV)
|
95
|
+
|
96
|
+
if ARGV.empty?
|
97
|
+
STDERR.puts "Error: No filename was specified. #{$0} --help for details."
|
98
|
+
exit 1
|
99
|
+
else
|
100
|
+
target = ARGV.shift
|
101
|
+
end
|
102
|
+
|
103
|
+
if @options[:output_dir].nil?
|
104
|
+
@options[:output_dir] = "#{File.join(File.dirname(target), File.basename(target,'.pdf'))}.explode"
|
105
|
+
end
|
106
|
+
|
107
|
+
Origami::OPTIONS[:ignore_bad_references] = true
|
108
|
+
OUTPUT_DIR = @options[:output_dir]
|
109
|
+
Dir::mkdir(OUTPUT_DIR) unless File.directory?(OUTPUT_DIR)
|
110
|
+
|
111
|
+
def split_by_rsrc(n, page, type)
|
112
|
+
all_rsrc = page.resources
|
113
|
+
type_rsrc = page.ls_resources(type)
|
114
|
+
other_rsrc = all_rsrc.keys - type_rsrc.keys
|
115
|
+
|
116
|
+
unless type_rsrc.empty?
|
117
|
+
# Keep only specified resource type.
|
118
|
+
output_file = File.join(OUTPUT_DIR, "page_#{n}_keeponly_#{type}.pdf")
|
119
|
+
PDF.write(output_file) do |pdf|
|
120
|
+
reduced = page.copy
|
121
|
+
# New resource dictionary with only matching resources.
|
122
|
+
reduced.Resources = Resources.new(type => type_rsrc)
|
123
|
+
# Remove mention of other resources.
|
124
|
+
reduced.Contents.data = reduced.Contents.data.lines.to_a.
|
125
|
+
delete_if {|line| other_rsrc.any?{|rsrc| line =~ /#{rsrc}/}}.join
|
126
|
+
|
127
|
+
STDERR.puts "Creating #{output_file}..."
|
128
|
+
pdf.append_page(reduced)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Remove all specified resource type.
|
132
|
+
output_file = File.join(OUTPUT_DIR, "page_#{n}_excluded_#{type}.pdf")
|
133
|
+
PDF.write(output_file) do |pdf|
|
134
|
+
reduced = page.copy
|
135
|
+
# New resource dictionary with no resource of specified type.
|
136
|
+
reduced.Resources = reduced.Resources.copy
|
137
|
+
reduced.Resources.delete(type)
|
138
|
+
# Remove mention this resource type.
|
139
|
+
reduced.Contents.data = reduced.Contents.data.lines.to_a.
|
140
|
+
delete_if {|line| type_rsrc.keys.any?{|rsrc| line =~ /#{rsrc}/}}.join
|
141
|
+
|
142
|
+
STDERR.puts "Creating #{output_file}..."
|
143
|
+
pdf.append_page(reduced)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Now treating each resource object separately.
|
147
|
+
type_rsrc.each_pair do |name, rsrc|
|
148
|
+
anyother_rsrc = all_rsrc.keys - [ name ]
|
149
|
+
# Keey only specified resource object.
|
150
|
+
output_file = File.join(OUTPUT_DIR, "page_#{n}_keeponly_#{type}_#{name}.pdf")
|
151
|
+
PDF.write(output_file) do |pdf|
|
152
|
+
reduced = page.copy
|
153
|
+
# New resource dictionary with only specified resource object.
|
154
|
+
reduced.Resources = Resources.new(type => {name => rsrc})
|
155
|
+
# Remove mention of all other resources.
|
156
|
+
reduced.Contents.data = reduced.Contents.data.lines.to_a.
|
157
|
+
delete_if {|line| anyother_rsrc.any?{|rsrc| line =~ /#{rsrc}/}}.join
|
158
|
+
|
159
|
+
STDERR.puts "Creating #{output_file}..."
|
160
|
+
pdf.append_page(reduced)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Remove only specified resource object.
|
164
|
+
output_file = File.join(OUTPUT_DIR, "page_#{n}_excluded_#{type}_#{name}.pdf")
|
165
|
+
PDF.write(output_file) do |pdf|
|
166
|
+
reduced = page.copy
|
167
|
+
# New resource dictionary with only specified resource object.
|
168
|
+
reduced.Resources = reduced.Resources.copy
|
169
|
+
reduced.Resources[type] = reduced.Resources.send(type).copy
|
170
|
+
reduced.Resources[type].delete(name)
|
171
|
+
# Remove mention of this resource only.
|
172
|
+
reduced.Contents.data = reduced.Contents.data.lines.to_a.
|
173
|
+
delete_if {|line| line =~ /#{name}/}.join
|
174
|
+
|
175
|
+
STDERR.puts "Creating #{output_file}..."
|
176
|
+
pdf.append_page(reduced)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
params =
|
183
|
+
{
|
184
|
+
:verbosity => Parser::VERBOSE_QUIET,
|
185
|
+
}
|
186
|
+
pdf = PDF.read(target, params)
|
187
|
+
|
188
|
+
i = @options[:page_range].first + 1
|
189
|
+
pdf.pages[@options[:page_range]].each do |page|
|
190
|
+
case @options[:split_by]
|
191
|
+
when 'pages'
|
192
|
+
output_file = File.join(OUTPUT_DIR, "page_#{i}.pdf")
|
193
|
+
PDF.write(output_file) do |pdf|
|
194
|
+
STDERR.puts "Creating #{output_file}..."
|
195
|
+
pdf.append_page(page)
|
196
|
+
end
|
197
|
+
|
198
|
+
when 'rsrc'
|
199
|
+
[ Resources::EXTGSTATE,
|
200
|
+
Resources::COLORSPACE,
|
201
|
+
Resources::PATTERN,
|
202
|
+
Resources::SHADING,
|
203
|
+
Resources::XOBJECT,
|
204
|
+
Resources::FONT,
|
205
|
+
Resources::PROPERTIES
|
206
|
+
].each { |type| split_by_rsrc(i, page, type) }
|
207
|
+
|
208
|
+
else
|
209
|
+
raise ArgumentError, "Unknown split option: #{@options[:split_by]}"
|
210
|
+
end
|
211
|
+
|
212
|
+
i += 1
|
213
|
+
end
|
214
|
+
|
215
|
+
rescue SystemExit
|
216
|
+
rescue Exception => e
|
217
|
+
STDERR.puts "#{e.class}: #{e.message} #{e.backtrace}"
|
218
|
+
exit 1
|
219
|
+
end
|
220
|
+
|
data/bin/pdfextract
CHANGED
@@ -120,6 +120,9 @@ begin
|
|
120
120
|
@options[:output_dir] = "#{File.basename(target, '.pdf')}.dump"
|
121
121
|
end
|
122
122
|
|
123
|
+
# Force data extraction, even for invalid FlateDecode streams.
|
124
|
+
Origami::OPTIONS[:ignore_zlib_errors] = true
|
125
|
+
|
123
126
|
OUTPUT_DIR = @options[:output_dir]
|
124
127
|
Dir::mkdir(OUTPUT_DIR) unless File.directory?(OUTPUT_DIR)
|
125
128
|
|
data/lib/origami/acroform.rb
CHANGED
@@ -147,7 +147,7 @@ module Origami
|
|
147
147
|
|
148
148
|
def self.included(receiver) #:nodoc:
|
149
149
|
|
150
|
-
receiver.field :FT, :Type => Name, :
|
150
|
+
receiver.field :FT, :Type => Name, :Required => true
|
151
151
|
receiver.field :Parent, :Type => Dictionary
|
152
152
|
receiver.field :Kids, :Type => Array
|
153
153
|
receiver.field :T, :Type => String
|
@@ -254,7 +254,7 @@ module Origami
|
|
254
254
|
end
|
255
255
|
|
256
256
|
field :Type, :Type => Name, :Default => :SigFieldLock
|
257
|
-
field :Action, :Type => Name, :
|
257
|
+
field :Action, :Type => Name, :Required => true
|
258
258
|
field :Fields, :Type => Array
|
259
259
|
|
260
260
|
def pre_build
|
data/lib/origami/actions.rb
CHANGED
@@ -65,18 +65,20 @@ module Origami
|
|
65
65
|
# Creates a new GoTo Action.
|
66
66
|
# _hash_:: A hash of options to set for this jump.
|
67
67
|
#
|
68
|
-
def
|
69
|
-
|
68
|
+
def self.[](hash = {})
|
70
69
|
if hash.is_a? Destination
|
71
|
-
|
70
|
+
self.new(:S => :GoTo, :D => hash)
|
72
71
|
else
|
73
|
-
|
72
|
+
self.new(hash)
|
74
73
|
end
|
75
|
-
|
76
74
|
end
|
77
75
|
|
78
76
|
end
|
79
77
|
|
78
|
+
def self.GoTo(hash = {})
|
79
|
+
Action::GoTo[hash]
|
80
|
+
end
|
81
|
+
|
80
82
|
#
|
81
83
|
# Class representing an action launching an URL.
|
82
84
|
#
|
@@ -91,12 +93,16 @@ module Origami
|
|
91
93
|
# _uri_:: The URI to launch.
|
92
94
|
# _ismap_::
|
93
95
|
#
|
94
|
-
def
|
95
|
-
|
96
|
+
def self.[](uri, ismap = false)
|
97
|
+
self.new(:URI => uri, :IsMap => ismap)
|
96
98
|
end
|
97
99
|
|
98
100
|
end
|
99
101
|
|
102
|
+
def self.URI(uri, ismap = false)
|
103
|
+
Action::URI[uri, ismap]
|
104
|
+
end
|
105
|
+
|
100
106
|
#
|
101
107
|
# Class representing a JavaScript Action.
|
102
108
|
#
|
@@ -109,11 +115,15 @@ module Origami
|
|
109
115
|
# Creates a new JavaScript Action.
|
110
116
|
# _script_:: The script to be executed.
|
111
117
|
#
|
112
|
-
def
|
113
|
-
|
118
|
+
def self.[](script)
|
119
|
+
self.new(:JS => script)
|
114
120
|
end
|
115
121
|
end
|
116
122
|
|
123
|
+
def self.JavaScript(script)
|
124
|
+
Action::JavaScript[script]
|
125
|
+
end
|
126
|
+
|
117
127
|
#
|
118
128
|
# Class representing an Action which run a command on the current system.
|
119
129
|
#
|
@@ -147,19 +157,22 @@ module Origami
|
|
147
157
|
#
|
148
158
|
class Named < Action
|
149
159
|
|
150
|
-
NEXTPAGE = :NextPage
|
151
|
-
PREVPAGE = :PrevPage
|
152
|
-
FIRSTPAGE = :FirstPage
|
153
|
-
LASTPAGE = :LastPage
|
154
|
-
PRINT = :Print
|
155
|
-
|
156
160
|
field :S, :Type => Name, :Default => :Named, :Required => true
|
157
161
|
field :N, :Type => Name, :Required => true
|
158
162
|
|
159
|
-
def
|
160
|
-
|
163
|
+
def self.[](type)
|
164
|
+
self.new(:N => type)
|
161
165
|
end
|
162
166
|
|
167
|
+
NEXTPAGE = self[:NextPage]
|
168
|
+
PREVPAGE = self[:PrevPage]
|
169
|
+
FIRSTPAGE = self[:FirstPage]
|
170
|
+
LASTPAGE = self[:LastPage]
|
171
|
+
PRINT = self[:Print]
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.Named(type)
|
175
|
+
Action::Named[type]
|
163
176
|
end
|
164
177
|
|
165
178
|
#
|
@@ -178,11 +191,15 @@ module Origami
|
|
178
191
|
# _dest_:: A Destination in the file.
|
179
192
|
# _newwindow_:: Specifies whether the file has to be opened in a new window.
|
180
193
|
#
|
181
|
-
def
|
182
|
-
|
194
|
+
def self.[](file, dest = Destination::GlobalFit.new(0), newwindow = false)
|
195
|
+
self.new(:F => file, :D => dest, :NewWindow => newwindow)
|
183
196
|
end
|
184
197
|
|
185
198
|
end
|
199
|
+
|
200
|
+
def self.GoToR(file, dest = Destination::GlobalFit.new(0), newwindow = false)
|
201
|
+
Action::GoToR[file, dest, newwindow]
|
202
|
+
end
|
186
203
|
|
187
204
|
#
|
188
205
|
# Class representing a GoTo Action to an embedded pdf file.
|
@@ -215,11 +232,15 @@ module Origami
|
|
215
232
|
|
216
233
|
end
|
217
234
|
|
218
|
-
def
|
219
|
-
|
235
|
+
def self.[](filename, dest, newwindow = false)
|
236
|
+
self.new(:T => EmbeddedTarget.new(:R => :C, :N => filename), :D => dest, :NewWindow => newwindow)
|
220
237
|
end
|
221
238
|
|
222
239
|
end
|
240
|
+
|
241
|
+
def self.GoToE(filename, dest, newwindow = false)
|
242
|
+
Action::GoToE[filename, dest, newwindow]
|
243
|
+
end
|
223
244
|
|
224
245
|
#
|
225
246
|
# (PDF 1.2) Send data to a uniform resource locator. p703
|
@@ -247,31 +268,33 @@ module Origami
|
|
247
268
|
field :Fields, :Type => Array
|
248
269
|
field :Flags, :Type => Integer, :Default => 0
|
249
270
|
|
250
|
-
def
|
251
|
-
|
252
|
-
|
253
|
-
end
|
254
|
-
|
255
|
-
super(:F => url, :Fields => fields, :Flags => flags)
|
271
|
+
def self.[](url, fields = [], flags = 0)
|
272
|
+
url = FileSpec.new(:FS => :URL, :F => url) unless url.is_a? FileSpec
|
273
|
+
self.new(:F => url, :Fields => fields, :Flags => flags)
|
256
274
|
end
|
257
275
|
|
258
276
|
end
|
259
277
|
|
278
|
+
def self.SubmitForm(url, fields = [], flags = 0)
|
279
|
+
Action::SubmitForm[url, fields, flags]
|
280
|
+
end
|
281
|
+
|
260
282
|
class ImportData < Action
|
261
283
|
|
262
284
|
field :S, :Type => Name, :Default => :ImportData, :Required => true
|
263
285
|
field :F, :Type => Dictionary, :Required => true
|
264
286
|
|
265
|
-
def
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
super(:F => file)
|
287
|
+
def self.[](file)
|
288
|
+
file = FileSpec.new(:FS => :File, :F => file) unless file.is_a? FileSpec
|
289
|
+
self.new(:F => file)
|
271
290
|
end
|
272
291
|
|
273
292
|
end
|
274
293
|
|
294
|
+
def self.ImportData(file)
|
295
|
+
Action::ImportData[file]
|
296
|
+
end
|
297
|
+
|
275
298
|
class RichMediaExecute < Action
|
276
299
|
|
277
300
|
field :S, :Type => Name, :Default => :RichMediaExecute, :Version => "1.7", :ExtensionLevel => 3, :Required => true
|
@@ -287,11 +310,15 @@ module Origami
|
|
287
310
|
field :A, :Type => Object, :Version => "1.7", :ExtensionLevel => 3
|
288
311
|
end
|
289
312
|
|
290
|
-
def
|
291
|
-
|
313
|
+
def self.[](annotation, command, *params)
|
314
|
+
self.new(:TA => annotation, :CMD => Command.new(:C => command, :A => params))
|
292
315
|
end
|
293
316
|
|
294
317
|
end
|
318
|
+
|
319
|
+
def self.RichMediaExecute(annotation, command, *params)
|
320
|
+
Action::RichMediaExecute[annotation, command, *params]
|
321
|
+
end
|
295
322
|
|
296
323
|
end
|
297
324
|
|
data/lib/origami/annotations.rb
CHANGED
@@ -34,7 +34,7 @@ module Origami
|
|
34
34
|
include StandardObject
|
35
35
|
|
36
36
|
field :Type, :Type => Name, :Default => :Annot
|
37
|
-
field :Subtype, :Type => Name, :
|
37
|
+
field :Subtype, :Type => Name, :Required => true
|
38
38
|
field :Rect, :Type => Array, :Default => [ 0 , 0 , 0 , 0 ], :Required => true
|
39
39
|
field :Contents, :Type => String
|
40
40
|
field :P, :Type => Dictionary, :Version => "1.3"
|
@@ -257,7 +257,7 @@ module Origami
|
|
257
257
|
|
258
258
|
include Markup
|
259
259
|
|
260
|
-
field :Subtype, :Type => Name, :
|
260
|
+
field :Subtype, :Type => Name, :Required => true
|
261
261
|
field :BS, :Type => Dictionary
|
262
262
|
field :IC, :Type => Array
|
263
263
|
field :BE, :Type => Dictionary, :Version => "1.5"
|
@@ -266,6 +266,7 @@ module Origami
|
|
266
266
|
end
|
267
267
|
|
268
268
|
class Square < Shape
|
269
|
+
field :Subtype, :Type => Name, :Default => :Square, :Required => true
|
269
270
|
end
|
270
271
|
|
271
272
|
class Circle < Shape
|
data/lib/origami/array.rb
CHANGED
@@ -85,7 +85,7 @@ module Origami
|
|
85
85
|
super
|
86
86
|
end
|
87
87
|
|
88
|
-
def self.parse(stream) #:nodoc:
|
88
|
+
def self.parse(stream, parser = nil) #:nodoc:
|
89
89
|
data = []
|
90
90
|
offset = stream.pos
|
91
91
|
|
@@ -100,7 +100,7 @@ module Origami
|
|
100
100
|
raise InvalidArrayObjectError, "Bad embedded object format"
|
101
101
|
end
|
102
102
|
|
103
|
-
value = type.parse(stream)
|
103
|
+
value = type.parse(stream, parser)
|
104
104
|
data << value
|
105
105
|
end
|
106
106
|
|
@@ -155,7 +155,20 @@ module Origami
|
|
155
155
|
|
156
156
|
alias value to_a
|
157
157
|
|
158
|
-
def
|
158
|
+
def copy
|
159
|
+
copy = self.class.new
|
160
|
+
self.each do |obj|
|
161
|
+
copy << obj.copy
|
162
|
+
end
|
163
|
+
|
164
|
+
copy.parent = @parent
|
165
|
+
copy.no, copy.generation = @no, @generation
|
166
|
+
copy.set_indirect(true) if is_indirect?
|
167
|
+
copy.set_pdf(@pdf) if is_indirect?
|
168
|
+
copy
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.native_type ; Origami::Array end
|
159
172
|
|
160
173
|
end
|
161
174
|
|
@@ -167,7 +180,17 @@ module Origami
|
|
167
180
|
class << self
|
168
181
|
|
169
182
|
def [](coords)
|
170
|
-
corners =
|
183
|
+
corners =
|
184
|
+
if [ :llx, :lly, :urx, :ury ].all? {|p| coords.include?(p)}
|
185
|
+
coords.values_at(:llx, :lly, :urx, :ury)
|
186
|
+
elsif [ :width, :height ].all? {|p| coords.include?(p)}
|
187
|
+
width, height = coords.values_at(:width, :height)
|
188
|
+
x = coords.values_at(:x).first || 0
|
189
|
+
y = coords.values_at(:y).first || 0
|
190
|
+
[ x, y, x+width, y+height ]
|
191
|
+
else
|
192
|
+
raise ArgumentError, "Bad arguments for #{self.class}: #{coords.inspect}"
|
193
|
+
end
|
171
194
|
|
172
195
|
unless corners.all? { |corner| corner.is_a?(Numeric) }
|
173
196
|
raise TypeError, "All coords must be numbers"
|
data/lib/origami/boolean.rb
CHANGED
@@ -59,7 +59,7 @@ module Origami
|
|
59
59
|
super(@value.to_s)
|
60
60
|
end
|
61
61
|
|
62
|
-
def self.parse(stream) #:nodoc:
|
62
|
+
def self.parse(stream, parser = nil) #:nodoc:
|
63
63
|
|
64
64
|
offset = stream.pos
|
65
65
|
|
@@ -82,7 +82,7 @@ module Origami
|
|
82
82
|
@value
|
83
83
|
end
|
84
84
|
|
85
|
-
def
|
85
|
+
def self.native_type ; Boolean end
|
86
86
|
|
87
87
|
def false?
|
88
88
|
@value == false
|