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.
Files changed (108) hide show
  1. data/COPYING.LESSER +165 -0
  2. data/README +77 -0
  3. data/VERSION +1 -0
  4. data/bin/config/pdfcop.conf.yml +237 -0
  5. data/bin/gui/about.rb +46 -0
  6. data/bin/gui/config.rb +132 -0
  7. data/bin/gui/file.rb +385 -0
  8. data/bin/gui/hexdump.rb +74 -0
  9. data/bin/gui/hexview.rb +91 -0
  10. data/bin/gui/imgview.rb +72 -0
  11. data/bin/gui/menu.rb +392 -0
  12. data/bin/gui/properties.rb +132 -0
  13. data/bin/gui/signing.rb +635 -0
  14. data/bin/gui/textview.rb +107 -0
  15. data/bin/gui/treeview.rb +409 -0
  16. data/bin/gui/walker.rb +282 -0
  17. data/bin/gui/xrefs.rb +79 -0
  18. data/bin/pdf2graph +121 -0
  19. data/bin/pdf2ruby +353 -0
  20. data/bin/pdfcocoon +104 -0
  21. data/bin/pdfcop +455 -0
  22. data/bin/pdfdecompress +104 -0
  23. data/bin/pdfdecrypt +95 -0
  24. data/bin/pdfencrypt +112 -0
  25. data/bin/pdfextract +221 -0
  26. data/bin/pdfmetadata +123 -0
  27. data/bin/pdfsh +13 -0
  28. data/bin/pdfwalker +7 -0
  29. data/bin/shell/.irbrc +104 -0
  30. data/bin/shell/console.rb +136 -0
  31. data/bin/shell/hexdump.rb +83 -0
  32. data/origami.rb +36 -0
  33. data/origami/3d.rb +239 -0
  34. data/origami/acroform.rb +321 -0
  35. data/origami/actions.rb +299 -0
  36. data/origami/adobe/fdf.rb +259 -0
  37. data/origami/adobe/ppklite.rb +489 -0
  38. data/origami/annotations.rb +775 -0
  39. data/origami/array.rb +187 -0
  40. data/origami/boolean.rb +101 -0
  41. data/origami/catalog.rb +486 -0
  42. data/origami/destinations.rb +213 -0
  43. data/origami/dictionary.rb +188 -0
  44. data/origami/docmdp.rb +96 -0
  45. data/origami/encryption.rb +1293 -0
  46. data/origami/export.rb +283 -0
  47. data/origami/file.rb +222 -0
  48. data/origami/filters.rb +250 -0
  49. data/origami/filters/ascii.rb +189 -0
  50. data/origami/filters/ccitt.rb +515 -0
  51. data/origami/filters/crypt.rb +47 -0
  52. data/origami/filters/dct.rb +61 -0
  53. data/origami/filters/flate.rb +112 -0
  54. data/origami/filters/jbig2.rb +63 -0
  55. data/origami/filters/jpx.rb +53 -0
  56. data/origami/filters/lzw.rb +195 -0
  57. data/origami/filters/predictors.rb +276 -0
  58. data/origami/filters/runlength.rb +117 -0
  59. data/origami/font.rb +209 -0
  60. data/origami/functions.rb +93 -0
  61. data/origami/graphics.rb +33 -0
  62. data/origami/graphics/colors.rb +191 -0
  63. data/origami/graphics/instruction.rb +126 -0
  64. data/origami/graphics/path.rb +154 -0
  65. data/origami/graphics/patterns.rb +180 -0
  66. data/origami/graphics/state.rb +164 -0
  67. data/origami/graphics/text.rb +224 -0
  68. data/origami/graphics/xobject.rb +493 -0
  69. data/origami/header.rb +90 -0
  70. data/origami/linearization.rb +318 -0
  71. data/origami/metadata.rb +114 -0
  72. data/origami/name.rb +170 -0
  73. data/origami/null.rb +75 -0
  74. data/origami/numeric.rb +188 -0
  75. data/origami/obfuscation.rb +233 -0
  76. data/origami/object.rb +527 -0
  77. data/origami/outline.rb +59 -0
  78. data/origami/page.rb +559 -0
  79. data/origami/parser.rb +268 -0
  80. data/origami/parsers/fdf.rb +45 -0
  81. data/origami/parsers/pdf.rb +27 -0
  82. data/origami/parsers/pdf/linear.rb +113 -0
  83. data/origami/parsers/ppklite.rb +86 -0
  84. data/origami/pdf.rb +1144 -0
  85. data/origami/reference.rb +113 -0
  86. data/origami/signature.rb +474 -0
  87. data/origami/stream.rb +575 -0
  88. data/origami/string.rb +416 -0
  89. data/origami/trailer.rb +173 -0
  90. data/origami/webcapture.rb +87 -0
  91. data/origami/xfa.rb +3027 -0
  92. data/origami/xreftable.rb +447 -0
  93. data/templates/patterns.rb +66 -0
  94. data/templates/widgets.rb +173 -0
  95. data/templates/xdp.rb +92 -0
  96. data/tests/dataset/test.dummycrt +28 -0
  97. data/tests/dataset/test.dummykey +27 -0
  98. data/tests/tc_actions.rb +32 -0
  99. data/tests/tc_annotations.rb +85 -0
  100. data/tests/tc_pages.rb +37 -0
  101. data/tests/tc_pdfattach.rb +24 -0
  102. data/tests/tc_pdfencrypt.rb +110 -0
  103. data/tests/tc_pdfnew.rb +32 -0
  104. data/tests/tc_pdfparse.rb +98 -0
  105. data/tests/tc_pdfsig.rb +37 -0
  106. data/tests/tc_streams.rb +129 -0
  107. data/tests/ts_pdf.rb +45 -0
  108. metadata +193 -0
@@ -0,0 +1,90 @@
1
+ =begin
2
+
3
+ = File
4
+ header.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.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/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ class PDF
29
+
30
+ class InvalidHeaderError < Exception #:nodoc:
31
+ end
32
+
33
+ #
34
+ # Class representing a PDF Header.
35
+ #
36
+ class Header
37
+
38
+ MINVERSION = 0
39
+ MAXVERSION = 7
40
+
41
+ MAGIC = /%PDF-(\d+)\.(\d+)/
42
+
43
+ attr_accessor :majorversion, :minorversion
44
+
45
+ #
46
+ # Creates a file header, with the given major and minor versions.
47
+ # _majorversion_:: Major PDF version, must be 1.
48
+ # _minorversion_:: Minor PDF version, must be between 0 and 7.
49
+ #
50
+ def initialize(majorversion = 1, minorversion = 4)
51
+
52
+ #if majorversion.to_i != 1 || ! ((MINVERSION..MAXVERSION) === minorversion.to_i)
53
+ # colorprint("[info ] Warning: Invalid file version : #{majorversion}.#{minorversion}\n", Colors::YELLOW, false, STDERR)
54
+ #end
55
+
56
+ @majorversion, @minorversion = majorversion, minorversion
57
+ end
58
+
59
+ def self.parse(stream) #:nodoc:
60
+
61
+ if not stream.scan(MAGIC).nil?
62
+ maj = stream[1].to_i
63
+ min = stream[2].to_i
64
+ else
65
+ raise InvalidHeaderError, "Invalid header format : #{stream.peek(15).inspect}"
66
+ end
67
+
68
+ PDF::Header.new(maj,min)
69
+ end
70
+
71
+ #
72
+ # Outputs self into PDF code.
73
+ #
74
+ def to_s
75
+ "%PDF-#{@majorversion}.#{@minorversion}" + EOL
76
+ end
77
+
78
+ def to_sym #:nodoc:
79
+ "#{@majorversion}.#{@minorversion}".to_sym
80
+ end
81
+
82
+ def to_f #:nodoc:
83
+ to_sym.to_s.to_f
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,318 @@
1
+ =begin
2
+
3
+ = File
4
+ linearization.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.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/>.
23
+
24
+ =end
25
+
26
+ module Origami
27
+
28
+ class PDF
29
+
30
+ #
31
+ # Returns whether the current document is linearized.
32
+ #
33
+ def is_linearized?
34
+ begin
35
+ obj = @revisions.first.objects.sort_by{|obj| obj.file_offset}.first
36
+ rescue
37
+ return false
38
+ end
39
+
40
+ obj.is_a?(Dictionary) and obj.has_key? :Linearized
41
+ end
42
+
43
+ #
44
+ # Tries to delinearize the document if it has been linearized.
45
+ # This operation is xrefs destructive, should be fixed in the future to merge tables.
46
+ #
47
+ def delinearize!
48
+ raise RuntimeError, 'Not a linearized document' unless is_linearized?
49
+
50
+ #
51
+ # Saves the first trailer.
52
+ #
53
+ prev_trailer = @revisions.first.trailer
54
+
55
+ lin_dict = @revisions.first.objects.first
56
+ hints = lin_dict[:H]
57
+
58
+ #
59
+ # Removes hint streams used by linearization.
60
+ #
61
+ if hints.is_a?(::Array)
62
+ if hints.length > 0 and hints[0].is_a?(Integer)
63
+ hint_stream = get_object_by_offset(hints[0])
64
+ delete_object(hint_stream.reference) if hint_stream.is_a?(Stream)
65
+ end
66
+
67
+ if hints.length > 2 and hints[2].is_a?(Integer)
68
+ overflow_stream = get_object_by_offset(hints[2])
69
+ delete_object(overflow_stream.reference) if overflow_stream.is_a?(Stream)
70
+ end
71
+ end
72
+
73
+ #
74
+ # Remove all xrefs.
75
+ # Fix: Should be merged instead.
76
+ #
77
+ remove_xrefs
78
+
79
+ #
80
+ # Remove the linearization revision.
81
+ #
82
+ remove_revision(0)
83
+
84
+ #
85
+ # Update the trailer.
86
+ #
87
+ last_trailer = (@revisions.last.trailer ||= Trailer.new)
88
+
89
+ last_trailer.dictionary ||= Dictionary.new
90
+ last_trailer.dictionary =
91
+ last_trailer.dictionary.merge(prev_trailer.dictionary)
92
+
93
+ self
94
+ end
95
+
96
+ end
97
+
98
+ #
99
+ # Class representing a linearization dictionary.
100
+ #
101
+ class Linearization < Dictionary
102
+ include StandardObject
103
+
104
+ field :Linearized, :Type => Real, :Default => 1.0, :Required => true
105
+ field :L, :Type => Integer, :Required => true
106
+ field :H, :Type => Array, :Required => true
107
+ field :O, :Type => Integer, :Required => true
108
+ field :E, :Type => Integer, :Required => true
109
+ field :N, :Type => Integer, :Required => true
110
+ field :T, :Type => Integer, :Required => true
111
+ field :P, :Type => Integer, :Default => 0
112
+
113
+ def initialize(hash = {})
114
+ super(hash, true)
115
+ end
116
+
117
+ end
118
+
119
+ class InvalidHintTableError < Exception #:nodoc:
120
+ end
121
+
122
+ module HintTable
123
+ module ClassMethods
124
+ def header_item_size(number, size)
125
+ @header_items_size[number] = size
126
+ end
127
+
128
+ def get_header_item_size(number)
129
+ @header_items_size[number]
130
+ end
131
+
132
+ def entry_item_size(number, size)
133
+ @entry_items_size[number] = size
134
+ end
135
+
136
+ def get_entry_item_size(number)
137
+ @entry_items_size[number]
138
+ end
139
+
140
+ def nb_header_items
141
+ @header_items_size.size
142
+ end
143
+
144
+ def nb_entry_items
145
+ @entry_items_size.size
146
+ end
147
+ end
148
+
149
+ def self.included(receiver)
150
+ receiver.instance_variable_set(:@header_items_size, {})
151
+ receiver.instance_variable_set(:@entry_items_size, {})
152
+ receiver.extend(ClassMethods)
153
+ end
154
+
155
+ attr_accessor :header_items
156
+ attr_accessor :entries
157
+
158
+ def initialize
159
+ @header_items = {}
160
+ @entries = []
161
+ end
162
+
163
+ def to_s
164
+ data = ""
165
+
166
+ nitems = self.class.nb_header_items
167
+ for no in (1..nitems)
168
+ unless @header_items.include?(no)
169
+ raise InvalidHintTableError, "Missing item #{no} in header section of #{self.class}"
170
+ end
171
+
172
+ value = @header_items[no]
173
+ item_size = self.class.get_header_item_size(no)
174
+
175
+ item_size = ((item_size + 7) >> 3) << 3
176
+ item_data = value.to_s(2)
177
+ item_data = "0" * (item_size - item_data.size) + item_data
178
+
179
+ data << [ item_data ].pack("B*")
180
+ end
181
+
182
+ i = 0
183
+ nitems = self.class.nb_entry_items
184
+ @entries.each do |entry|
185
+ for no in (1..items)
186
+ unless entry.include?(no)
187
+ raise InvalidHintTableError, "Missing item #{no} in entry #{i} of #{self.class}"
188
+ end
189
+
190
+ value = entry[no]
191
+ item_size = self.class.get_entry_item_size(no)
192
+
193
+ item_size = ((item_size + 7) >> 3) << 3
194
+ item_data = value.to_s(2)
195
+ item_data = "0" * (item_size - item_data.size) + item_data
196
+
197
+ data << [ item_data ].pack("B*")
198
+ end
199
+
200
+ i = i + 1
201
+ end
202
+
203
+ data
204
+ end
205
+
206
+ class PageOffsetTable
207
+ include HintTable
208
+
209
+ header_item_size 1, 32
210
+ header_item_size 2, 32
211
+ header_item_size 3, 16
212
+ header_item_size 4, 32
213
+ header_item_size 5, 16
214
+ header_item_size 6, 32
215
+ header_item_size 7, 16
216
+ header_item_size 8, 32
217
+ header_item_size 9, 16
218
+ header_item_size 10, 16
219
+ header_item_size 11, 16
220
+ header_item_size 12, 16
221
+ header_item_size 13, 16
222
+
223
+ entry_item_size 1, 16
224
+ entry_item_size 2, 16
225
+ entry_item_size 3, 16
226
+ entry_item_size 4, 16
227
+ entry_item_size 5, 16
228
+ entry_item_size 6, 16
229
+ entry_item_size 7, 16
230
+ end
231
+
232
+ class SharedObjectTable
233
+ include HintTable
234
+
235
+ header_item_size 1, 32
236
+ header_item_size 2, 32
237
+ header_item_size 3, 32
238
+ header_item_size 4, 32
239
+ header_item_size 5, 16
240
+ header_item_size 6, 32
241
+ header_item_size 7, 16
242
+
243
+ entry_item_size 1, 16
244
+ entry_item_size 2, 1
245
+ entry_item_size 3, 128
246
+ entry_item_size 4, 16
247
+ end
248
+
249
+ end
250
+
251
+ class InvalidHintStreamObjectError < InvalidStreamObjectError #:nodoc:
252
+ end
253
+
254
+ class HintStream < Stream
255
+
256
+ attr_accessor :page_offset_table
257
+ attr_accessor :shared_objects_table
258
+ attr_accessor :thumbnails_table
259
+ attr_accessor :outlines_table
260
+ attr_accessor :threads_table
261
+ attr_accessor :named_destinations_table
262
+ attr_accessor :interactive_forms_table
263
+ attr_accessor :information_dictionary_table
264
+ attr_accessor :logical_structure_table
265
+ attr_accessor :page_labels_table
266
+ attr_accessor :renditions_table
267
+ attr_accessor :embedded_files_table
268
+
269
+ field :S, :Type => Integer, :Required => true # SHared objects
270
+ field :T, :Type => Integer # Thumbnails
271
+ field :O, :Type => Integer # Outlines
272
+ field :A, :Type => Integer # Threads
273
+ field :E, :Type => Integer # Named destinations
274
+ field :V, :Type => Integer # Interactive forms
275
+ field :I, :Type => Integer # Information dictionary
276
+ field :C, :Type => Integer # Logical structure
277
+ field :L, :Type => Integer # Page labels
278
+ field :R, :Type => Integer # Renditions
279
+ field :B, :Type => Integer # Embedded files
280
+
281
+ def pre_build
282
+ if @page_offset_table.nil?
283
+ raise InvalidHintStreamObjectError, "No page offset hint table"
284
+ end
285
+
286
+ if @shared_objects_table.nil?
287
+ raise InvalidHintStreamObjectError, "No shared objects hint table"
288
+ end
289
+
290
+ @data = ""
291
+ save_table(@page_offset_table)
292
+ save_table(@shared_objects_table, :S)
293
+ save_table(@thumbnails_table, :T)
294
+ save_table(@outlines_table, :O)
295
+ save_table(@threads_table, :A)
296
+ save_table(@named_destinations_table, :E)
297
+ save_table(@interactive_forms_table, :V)
298
+ save_table(@information_dictionary_table, :I)
299
+ save_table(@logical_structure_table, :C)
300
+ save_table(@page_labels_table, :L)
301
+ save_table(@renditions_table, :R)
302
+ save_table(@embedded_files_table, :B)
303
+
304
+ super
305
+ end
306
+
307
+ private
308
+
309
+ def save_table(table, name = nil)
310
+ unless table.nil?
311
+ self[name] = @data.size if name
312
+ @data << table.to_s
313
+ end
314
+ end
315
+
316
+ end
317
+
318
+ end
@@ -0,0 +1,114 @@
1
+ =begin
2
+
3
+ = File
4
+ metadata.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.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/>.
23
+
24
+ =end
25
+
26
+ require 'rexml/document'
27
+
28
+ module Origami
29
+
30
+ class PDF
31
+
32
+ #
33
+ # Returns true if the document has a document information dictionary.
34
+ #
35
+ def has_document_info?
36
+ has_attr? :Info
37
+ end
38
+
39
+ #
40
+ # Returns true if the document has a catalog metadata stream.
41
+ #
42
+ def has_metadata?
43
+ self.Catalog.has_key? :Metadata
44
+ end
45
+
46
+ #
47
+ # Returns the document information dictionary if present.
48
+ #
49
+ def get_document_info
50
+ get_doc_attr :Info
51
+ end
52
+
53
+ #
54
+ # Returns a Hash of the information found in the metadata stream
55
+ #
56
+ def get_metadata
57
+ metadata_stm = self.Catalog.Metadata
58
+
59
+ if metadata_stm.is_a?(Stream)
60
+ doc = REXML::Document.new(metadata_stm.data)
61
+
62
+ info = {}
63
+
64
+ doc.elements.each('*/*/rdf:Description') do |description|
65
+
66
+ description.attributes.each_attribute do |attr|
67
+ case attr.prefix
68
+ when 'pdf','xap','pdf'
69
+ info[attr.name] = attr.value
70
+ end
71
+ end
72
+
73
+ description.elements.each('*') do |element|
74
+ value = (element.elements['.//rdf:li'] || element).text
75
+ info[element.name] = value.to_s
76
+ end
77
+
78
+ end
79
+
80
+ return info
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ #
87
+ # Class representing an information Dictionary, containing title, author, date of creation and the like.
88
+ #
89
+ class Metadata < Dictionary
90
+ include StandardObject
91
+
92
+ field :Title, :Type => String, :Version => "1.1"
93
+ field :Author, :Type => String
94
+ field :Subject, :Type => String, :Version => "1.1"
95
+ field :Keywords, :Type => String, :Version => "1.1"
96
+ field :Creator, :Type => String
97
+ field :Producer, :Type => String
98
+ field :CreationDate, :Type => ByteString
99
+ field :ModDate, :Type => ByteString, :Version => "1.1"
100
+ field :Trapped, :Type => Name, :Default => :Unknown, :Version => "1.3"
101
+ end
102
+
103
+ #
104
+ # Class representing a metadata Stream.
105
+ # This stream can contain the same information as the Metadata dictionary, but is storing in XML data.
106
+ #
107
+ class MetadataStream < Stream
108
+ include StandardObject
109
+
110
+ field :Type, :Type => Name, :Default => :Metadata, :Required => true
111
+ field :Subtype, :Type => Name, :Default =>:XML, :Required => true
112
+ end
113
+
114
+ end