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
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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/>.
|
|
3
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
|
4
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
5
|
+
|
|
6
|
+
Origami is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser 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
|
+
Origami 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 Lesser General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
23
18
|
|
|
24
19
|
=end
|
|
25
20
|
|
|
@@ -38,220 +33,312 @@ require 'origami/parsers/fdf'
|
|
|
38
33
|
|
|
39
34
|
module Origami
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
attr_accessor :majorversion, :minorversion
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
# Creates a file header, with the given major and minor versions.
|
|
54
|
-
# _majorversion_:: Major version.
|
|
55
|
-
# _minorversion_:: Minor version.
|
|
56
|
-
#
|
|
57
|
-
def initialize(majorversion = 2, minorversion = 1)
|
|
58
|
-
@majorversion, @minorversion = majorversion, minorversion
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def self.parse(stream) #:nodoc:
|
|
62
|
-
|
|
63
|
-
if not stream.scan(MAGIC).nil?
|
|
64
|
-
maj = stream[1].to_i
|
|
65
|
-
min = stream[2].to_i
|
|
66
|
-
else
|
|
67
|
-
raise InvalidHeader, "Invalid header format"
|
|
36
|
+
#
|
|
37
|
+
# Class representing an AcroForm Forms Data Format file.
|
|
38
|
+
#
|
|
39
|
+
class FDF
|
|
40
|
+
|
|
41
|
+
def self.read(path, options = {})
|
|
42
|
+
path = File.expand_path(path) if path.is_a?(::String)
|
|
43
|
+
|
|
44
|
+
FDF::Parser.new(options).parse(path)
|
|
68
45
|
end
|
|
69
|
-
|
|
70
|
-
FDF::Header.new(maj,min)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def to_s
|
|
74
|
-
"%FDF-#{@majorversion}.#{@minorversion}" + EOL
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def to_sym #:nodoc:
|
|
78
|
-
"#{@majorversion}.#{@minorversion}".to_sym
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def to_f #:nodoc:
|
|
82
|
-
to_sym.to_s.to_f
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
end
|
|
86
46
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
attr_accessor :body, :xreftable, :trailer
|
|
90
|
-
|
|
91
|
-
def initialize(adbk)
|
|
92
|
-
@pdf = adbk
|
|
93
|
-
@body = {}
|
|
94
|
-
@xreftable = nil
|
|
95
|
-
@trailer = nil
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def trailer=(trl)
|
|
99
|
-
trl.pdf = @pdf
|
|
100
|
-
@trailer = trl
|
|
101
|
-
end
|
|
102
|
-
end
|
|
47
|
+
class Header
|
|
48
|
+
MAGIC = /%FDF-(?<major>\d)\.(?<minor>\d)/
|
|
103
49
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
50
|
+
attr_accessor :major_version, :minor_version
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Creates a file header, with the given major and minor versions.
|
|
54
|
+
# _major_version_:: Major version.
|
|
55
|
+
# _minor_version_:: Minor version.
|
|
56
|
+
#
|
|
57
|
+
def initialize(major_version = 1, minor_version = 2)
|
|
58
|
+
@major_version, @minor_version = major_version, minor_version
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.parse(stream) #:nodoc:
|
|
62
|
+
if not stream.scan(MAGIC).nil?
|
|
63
|
+
maj = stream['major'].to_i
|
|
64
|
+
min = stream['minor'].to_i
|
|
65
|
+
else
|
|
66
|
+
raise InvalidHeader, "Invalid header format"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
stream.skip(REGEXP_WHITESPACES)
|
|
70
|
+
|
|
71
|
+
FDF::Header.new(maj, min)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_s
|
|
75
|
+
"%FDF-#{@major_version}.#{@minor_version}".b + EOL
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def to_sym #:nodoc:
|
|
79
|
+
"#{@major_version}.#{@minor_version}".to_sym
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def to_f #:nodoc:
|
|
83
|
+
to_sym.to_s.to_f
|
|
84
|
+
end
|
|
119
85
|
end
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
86
|
+
|
|
87
|
+
class Revision #:nodoc;
|
|
88
|
+
attr_accessor :document
|
|
89
|
+
attr_accessor :body, :xreftable
|
|
90
|
+
attr_reader :trailer
|
|
91
|
+
|
|
92
|
+
def initialize(fdf)
|
|
93
|
+
@document = fdf
|
|
94
|
+
@body = {}
|
|
95
|
+
@xreftable = nil
|
|
96
|
+
@trailer = nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def trailer=(trl)
|
|
100
|
+
trl.document = @document
|
|
101
|
+
@trailer = trl
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def each_object(&b)
|
|
105
|
+
@body.each_value(&b)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def objects
|
|
109
|
+
@body.values
|
|
110
|
+
end
|
|
126
111
|
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
objset
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def <<(object)
|
|
133
|
-
|
|
134
|
-
object.set_indirect(true)
|
|
135
|
-
|
|
136
|
-
if object.no.zero?
|
|
137
|
-
maxno = 1
|
|
138
|
-
while get_object(maxno) do maxno = maxno.succ end
|
|
139
|
-
|
|
140
|
-
object.generation = 0
|
|
141
|
-
object.no = maxno
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
@revisions.first.body[object.reference] = object
|
|
145
|
-
|
|
146
|
-
object.reference
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def Catalog
|
|
150
|
-
get_object(@trailer.Root)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def save(filename)
|
|
154
|
-
|
|
155
|
-
bin = ""
|
|
156
|
-
bin << @header.to_s
|
|
157
112
|
|
|
158
|
-
|
|
113
|
+
class JavaScript < Dictionary
|
|
114
|
+
include StandardObject
|
|
115
|
+
|
|
116
|
+
field :Before, :Type => [ String, Stream ]
|
|
117
|
+
field :After, :Type => [ String, Stream ]
|
|
118
|
+
field :AfterPermsReady, :Type => [ String, Stream ]
|
|
119
|
+
field :Doc, :Type => Array.of(Name, String)
|
|
120
|
+
end
|
|
159
121
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
122
|
+
class IconFit < Dictionary
|
|
123
|
+
include StandardObject
|
|
124
|
+
|
|
125
|
+
ALWAYS_SCALE = :A
|
|
126
|
+
SCALE_WHEN_BIGGER = :B
|
|
127
|
+
SCALE_WHEN_SMALLER = :S
|
|
128
|
+
NEVER_SCALE = :N
|
|
129
|
+
|
|
130
|
+
field :SW, :Type => Name
|
|
131
|
+
field :S, :Type => Name
|
|
132
|
+
field :A, :Type => Array.of(Number, length: 2)
|
|
133
|
+
field :FB, :Type => Boolean
|
|
168
134
|
end
|
|
169
135
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
startxref = @header.to_s.size
|
|
199
|
-
|
|
200
|
-
@revisions.first.body.values.each { |object|
|
|
201
|
-
startxref += object.to_s.size
|
|
202
|
-
}
|
|
136
|
+
class NamedPageReference < Dictionary
|
|
137
|
+
include StandardObject
|
|
138
|
+
|
|
139
|
+
field :Name, :Type => String, :Required => true
|
|
140
|
+
field :F, :Type => FileSpec
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class Field < Dictionary
|
|
144
|
+
include StandardObject
|
|
145
|
+
|
|
146
|
+
field :Kids, :Type => Array.of(Field)
|
|
147
|
+
field :T, :Type => String, :Required => true
|
|
148
|
+
field :V, :Type => Dictionary
|
|
149
|
+
field :Ff, :Type => Integer
|
|
150
|
+
field :SetFf, :Type => Integer
|
|
151
|
+
field :ClrFf, :Type => Integer
|
|
152
|
+
field :F, :Type => Integer
|
|
153
|
+
field :SetF, :Type => Integer
|
|
154
|
+
field :ClrF, :Type => Integer
|
|
155
|
+
field :AP, :Type => Annotation::AppearanceDictionary
|
|
156
|
+
field :APRef, :Type => Dictionary
|
|
157
|
+
field :IF, :Type => IconFit
|
|
158
|
+
field :Opt, :Type => Array.of([String, Array.of(String, String)])
|
|
159
|
+
field :A, :Type => Action
|
|
160
|
+
field :AA, :Type => Annotation::AdditionalActions
|
|
161
|
+
field :RV, :Type => [ String, Stream ]
|
|
162
|
+
end
|
|
203
163
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
self
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def buildxrefs(objects) #:nodoc:
|
|
214
|
-
|
|
215
|
-
lastno = 0
|
|
216
|
-
brange = 0
|
|
217
|
-
|
|
218
|
-
xrefs = [ XRef.new(0, XRef::LASTFREE, XRef::FREE) ]
|
|
219
|
-
|
|
220
|
-
xrefsection = XRef::Section.new
|
|
221
|
-
objects.sort.each { |object|
|
|
222
|
-
if (object.no - lastno).abs > 1
|
|
223
|
-
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
224
|
-
brange = object.no
|
|
225
|
-
xrefs.clear
|
|
164
|
+
class Template < Dictionary
|
|
165
|
+
include StandardObject
|
|
166
|
+
|
|
167
|
+
field :TRef, :Type => NamedPageReference, :Required => true
|
|
168
|
+
field :Fields, :Type => Array.of(Field)
|
|
169
|
+
field :Rename, :Type => Boolean
|
|
226
170
|
end
|
|
227
171
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
lastno = object.no
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
234
|
-
|
|
235
|
-
xrefsection
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
def get_object_offset(no,generation) #:nodoc:
|
|
172
|
+
class Page < Dictionary
|
|
173
|
+
include StandardObject
|
|
239
174
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
175
|
+
field :Templates, :Type => Array.of(Template), :Required => true
|
|
176
|
+
field :Info, :Type => Dictionary
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
class Annotation < Origami::Annotation
|
|
180
|
+
field :Page, :Type => Integer, :Required => true
|
|
181
|
+
end
|
|
243
182
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
183
|
+
class Dictionary < Origami::Dictionary
|
|
184
|
+
include StandardObject
|
|
185
|
+
|
|
186
|
+
field :F, :Type => FileSpec
|
|
187
|
+
field :ID, :Type => Array.of(String, length: 2)
|
|
188
|
+
field :Fields, :Type => Array.of(FDF::Field)
|
|
189
|
+
field :Status, :Type => String
|
|
190
|
+
field :Pages, :Type => Array.of(FDF::Page)
|
|
191
|
+
field :Encoding, :Type => Name
|
|
192
|
+
field :Annots, :Type => Array.of(FDF::Annotation)
|
|
193
|
+
field :Differences, :Type => Stream
|
|
194
|
+
field :Target, :Type => String
|
|
195
|
+
field :EmbeddedFDFs, :Type => Array.of(FileSpec)
|
|
196
|
+
field :JavaScript, :Type => JavaScript
|
|
248
197
|
end
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
198
|
+
|
|
199
|
+
class Catalog < Dictionary
|
|
200
|
+
include StandardObject
|
|
201
|
+
|
|
202
|
+
field :Version, :Type => Name
|
|
203
|
+
field :FDF, :Type => FDF::Dictionary, :Required => true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
attr_accessor :header, :revisions
|
|
207
|
+
|
|
208
|
+
def initialize(parser = nil) #:nodoc:
|
|
209
|
+
@header = FDF::Header.new
|
|
210
|
+
@revisions = [ Revision.new(self) ]
|
|
211
|
+
@revisions.first.trailer = Trailer.new
|
|
212
|
+
|
|
213
|
+
init if parser.nil?
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def <<(object)
|
|
217
|
+
object.set_indirect(true)
|
|
218
|
+
object.set_document(self)
|
|
219
|
+
|
|
220
|
+
if object.no.zero?
|
|
221
|
+
maxno = 1
|
|
222
|
+
maxno = maxno.succ while get_object(maxno)
|
|
223
|
+
|
|
224
|
+
object.generation = 0
|
|
225
|
+
object.no = maxno
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
@revisions.first.body[object.reference] = object
|
|
229
|
+
|
|
230
|
+
object.reference
|
|
231
|
+
end
|
|
232
|
+
alias insert <<
|
|
233
|
+
|
|
234
|
+
def get_object(no, generation = 0) #:nodoc:
|
|
235
|
+
case no
|
|
236
|
+
when Reference
|
|
237
|
+
target = no
|
|
238
|
+
when ::Integer
|
|
239
|
+
target = Reference.new(no, generation)
|
|
240
|
+
when Origami::Object
|
|
241
|
+
return no
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
@revisions.first.body[target]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def indirect_objects
|
|
248
|
+
@revisions.inject([]) do |set, rev| set.concat(rev.objects) end
|
|
249
|
+
end
|
|
250
|
+
alias root_objects indirect_objects
|
|
251
|
+
|
|
252
|
+
def cast_object(reference, type, parser = nil) #:nodoc:
|
|
253
|
+
@revisions.each do |rev|
|
|
254
|
+
if rev.body.include?(reference) and type < rev.body[reference].class
|
|
255
|
+
rev.body[reference] = rev.body[reference].cast_to(type, parser)
|
|
256
|
+
|
|
257
|
+
rev.body[reference]
|
|
258
|
+
else
|
|
259
|
+
nil
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def Catalog
|
|
265
|
+
get_object(@revisions.first.trailer.Root)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def save(path)
|
|
269
|
+
bin = "".b
|
|
270
|
+
bin << @header.to_s
|
|
271
|
+
|
|
272
|
+
lastno, brange = 0, 0
|
|
273
|
+
|
|
274
|
+
xrefs = [ XRef.new(0, XRef::FIRSTFREE, XRef::FREE) ]
|
|
275
|
+
xrefsection = XRef::Section.new
|
|
276
|
+
|
|
277
|
+
@revisions.first.body.values.sort.each { |obj|
|
|
278
|
+
if (obj.no - lastno).abs > 1
|
|
279
|
+
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
280
|
+
brange = obj.no
|
|
281
|
+
xrefs.clear
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
xrefs << XRef.new(bin.size, obj.generation, XRef::USED)
|
|
285
|
+
lastno = obj.no
|
|
286
|
+
|
|
287
|
+
obj.pre_build
|
|
288
|
+
|
|
289
|
+
bin << obj.to_s
|
|
290
|
+
|
|
291
|
+
obj.post_build
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
295
|
+
|
|
296
|
+
@xreftable = xrefsection
|
|
297
|
+
@trailer ||= Trailer.new
|
|
298
|
+
@trailer.Size = @revisions.first.body.size + 1
|
|
299
|
+
@trailer.startxref = bin.size
|
|
300
|
+
|
|
301
|
+
bin << @xreftable.to_s
|
|
302
|
+
bin << @trailer.to_s
|
|
303
|
+
|
|
304
|
+
if path.respond_to?(:write)
|
|
305
|
+
io = path
|
|
306
|
+
else
|
|
307
|
+
path = File.expand_path(path)
|
|
308
|
+
io = File.open(path, "wb", encoding: 'binary')
|
|
309
|
+
close = true
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
begin
|
|
313
|
+
io.write(bin)
|
|
314
|
+
ensure
|
|
315
|
+
io.close if close
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
self
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
private
|
|
322
|
+
|
|
323
|
+
def init
|
|
324
|
+
catalog = Catalog.new(:FDF => FDF::Dictionary.new)
|
|
325
|
+
|
|
326
|
+
@revisions.first.trailer.Root = self.insert(catalog)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def get_object_offset(no,generation) #:nodoc:
|
|
330
|
+
bodyoffset = @header.to_s.size
|
|
331
|
+
objectoffset = bodyoffset
|
|
332
|
+
|
|
333
|
+
@revisions.first.body.values.each { |object|
|
|
334
|
+
if object.no == no and object.generation == generation then return objectoffset
|
|
335
|
+
else
|
|
336
|
+
objectoffset += object.to_s.size
|
|
337
|
+
end
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
nil
|
|
341
|
+
end
|
|
342
|
+
|
|
252
343
|
end
|
|
253
|
-
|
|
254
|
-
end
|
|
255
|
-
|
|
256
344
|
end
|
|
257
|
-
|