origami 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,25 +1,20 @@
1
1
  =begin
2
2
 
3
- = File
4
- formats/fdf.rb
5
-
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
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/>.
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
- # Class representing an AcroForm Forms Data Format file.
43
- #
44
- class FDF
45
-
46
- class Header
47
-
48
- MAGIC = /\A%FDF-(\d)\.(\d)/
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
- class Revision #:nodoc;
88
- attr_accessor :pdf
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
- attr_accessor :header, :revisions
105
-
106
- def initialize #:nodoc:
107
- @header = FDF::Header.new
108
- @revisions = [ Revision.new(self) ]
109
- @revisions.first.trailer = Trailer.new
110
- end
111
-
112
- def objects
113
- def append_subobj(root, objset)
114
- if objset.find{ |o| o.object_id == root.object_id }.nil?
115
- objset << root
116
- if root.is_a?(Array) or root.is_a?(Dictionary)
117
- root.each { |subobj| append_subobj(subobj, objset) unless subobj.is_a?(Reference) }
118
- end
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
- end
121
-
122
- objset = []
123
- @revisions.first.body.values.each do |object|
124
- unless object.is_a?(Reference)
125
- append_subobj(object, objset)
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
- lastno, brange = 0, 0
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
- xrefs = [ XRef.new(0, XRef::LASTFREE, XRef::FREE) ]
161
- xrefsection = XRef::Section.new
162
-
163
- @revisions.first.body.values.sort.each { |obj|
164
- if (obj.no - lastno).abs > 1
165
- xrefsection << XRef::Subsection.new(brange, xrefs)
166
- brange = obj.no
167
- xrefs.clear
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
- xrefs << XRef.new(bin.size, obj.generation, XRef::USED)
171
- lastno = obj.no
172
-
173
- bin << obj.to_s
174
- }
175
-
176
- xrefsection << XRef::Subsection.new(brange, xrefs)
177
-
178
- @xreftable = xrefsection
179
- @trailer ||= Trailer.new
180
- @trailer.Size = rev.body.size + 1
181
- @trailer.startxref = bin.size
182
-
183
- bin << @xreftable.to_s
184
- bin << @trailer.to_s
185
-
186
- fd = File.open(filename, "w").binmode
187
- fd << bin
188
- fd.close
189
-
190
- show_entries
191
- end
192
- alias saveas save
193
-
194
- private
195
-
196
- def rebuildxrefs #:nodoc:
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
- @xreftable = buildxrefs(@revisions.first.body)
205
-
206
- @trailer ||= Trailer.new
207
- @trailer.Size = @revisions.first.body.size + 1
208
- @trailer.startxref = startxref
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
- xrefs << XRef.new(get_object_offset(object.no, object.generation), object.generation, XRef::USED)
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
- bodyoffset = @header.to_s.size
241
-
242
- objectoffset = bodyoffset
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
- @revisions.first.body.values.each { |object|
245
- if object.no == no and object.generation == generation then return objectoffset
246
- else
247
- objectoffset += object.to_s.size
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
- nil
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
-