origami 2.0.0 → 2.0.1
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/README.md +1 -0
- data/bin/gui/config.rb +2 -1
- data/bin/gui/file.rb +118 -240
- data/bin/gui/gtkhex.rb +5 -5
- data/bin/gui/hexview.rb +20 -16
- data/bin/gui/imgview.rb +1 -1
- data/bin/gui/menu.rb +138 -158
- data/bin/gui/properties.rb +46 -48
- data/bin/gui/signing.rb +183 -214
- data/bin/gui/textview.rb +1 -1
- data/bin/gui/treeview.rb +13 -7
- data/bin/gui/walker.rb +102 -71
- data/bin/gui/xrefs.rb +1 -1
- data/bin/pdf2ruby +3 -3
- data/bin/pdfcop +18 -11
- data/bin/pdfextract +14 -5
- data/bin/pdfmetadata +3 -3
- data/bin/shell/console.rb +8 -8
- data/bin/shell/hexdump.rb +4 -4
- data/examples/attachments/nested_document.rb +1 -1
- data/examples/javascript/hello_world.rb +3 -3
- data/lib/origami.rb +0 -1
- data/lib/origami/acroform.rb +3 -3
- data/lib/origami/array.rb +1 -3
- data/lib/origami/boolean.rb +1 -3
- data/lib/origami/catalog.rb +3 -9
- data/lib/origami/destinations.rb +2 -2
- data/lib/origami/dictionary.rb +15 -29
- data/lib/origami/encryption.rb +334 -692
- data/lib/origami/extensions/fdf.rb +3 -2
- data/lib/origami/extensions/ppklite.rb +5 -9
- data/lib/origami/filespec.rb +2 -2
- data/lib/origami/filters.rb +54 -36
- data/lib/origami/filters/ascii.rb +67 -49
- data/lib/origami/filters/ccitt.rb +4 -236
- data/lib/origami/filters/ccitt/tables.rb +267 -0
- data/lib/origami/filters/crypt.rb +1 -1
- data/lib/origami/filters/dct.rb +0 -1
- data/lib/origami/filters/flate.rb +3 -43
- data/lib/origami/filters/lzw.rb +62 -99
- data/lib/origami/filters/predictors.rb +135 -105
- data/lib/origami/filters/runlength.rb +34 -22
- data/lib/origami/graphics.rb +2 -2
- data/lib/origami/graphics/colors.rb +89 -63
- data/lib/origami/graphics/path.rb +14 -14
- data/lib/origami/graphics/patterns.rb +31 -33
- data/lib/origami/graphics/render.rb +0 -1
- data/lib/origami/graphics/state.rb +9 -9
- data/lib/origami/graphics/text.rb +17 -17
- data/lib/origami/graphics/xobject.rb +102 -92
- data/lib/origami/javascript.rb +91 -68
- data/lib/origami/linearization.rb +22 -20
- data/lib/origami/metadata.rb +1 -1
- data/lib/origami/name.rb +1 -3
- data/lib/origami/null.rb +1 -3
- data/lib/origami/numeric.rb +3 -13
- data/lib/origami/object.rb +100 -72
- data/lib/origami/page.rb +24 -28
- data/lib/origami/parser.rb +34 -51
- data/lib/origami/parsers/fdf.rb +2 -2
- data/lib/origami/parsers/pdf.rb +41 -18
- data/lib/origami/parsers/pdf/lazy.rb +83 -46
- data/lib/origami/parsers/pdf/linear.rb +19 -10
- data/lib/origami/parsers/ppklite.rb +1 -1
- data/lib/origami/pdf.rb +150 -206
- data/lib/origami/reference.rb +4 -6
- data/lib/origami/signature.rb +76 -48
- data/lib/origami/stream.rb +69 -63
- data/lib/origami/string.rb +2 -19
- data/lib/origami/trailer.rb +25 -22
- data/lib/origami/version.rb +1 -1
- data/lib/origami/xfa.rb +6 -4
- data/lib/origami/xreftable.rb +29 -29
- data/test/test_annotations.rb +16 -38
- data/test/test_pdf_attachment.rb +1 -1
- data/test/test_pdf_parse.rb +1 -1
- data/test/test_xrefs.rb +2 -2
- metadata +4 -4
- data/lib/origami/export.rb +0 -247
data/lib/origami/javascript.rb
CHANGED
@@ -23,16 +23,6 @@ module Origami
|
|
23
23
|
begin
|
24
24
|
require 'v8'
|
25
25
|
|
26
|
-
class V8::Object
|
27
|
-
#def inspect
|
28
|
-
# case self
|
29
|
-
# when V8::Array,V8::Function then super
|
30
|
-
# else
|
31
|
-
# "{#{self.to_a.map{|k,v| "#{k}:#{v.inspect}"}.join(', ')}}"
|
32
|
-
# end
|
33
|
-
#end
|
34
|
-
end
|
35
|
-
|
36
26
|
class PDF
|
37
27
|
|
38
28
|
module JavaScript
|
@@ -105,37 +95,43 @@ module Origami
|
|
105
95
|
|
106
96
|
def self.check_method_args(args, def_args)
|
107
97
|
if args.first.is_a?(V8::Object)
|
108
|
-
args
|
109
|
-
members = args.entries.map{|k,v| k}
|
110
|
-
argv = []
|
111
|
-
def_args.each do |def_arg|
|
112
|
-
raise MissingArgError if def_arg.required and not members.include?(def_arg.name)
|
113
|
-
|
114
|
-
if members.include?(def_arg.name)
|
115
|
-
arg = args[def_arg.name]
|
116
|
-
raise TypeError if def_arg.type and not arg.is_a?(def_arg.type)
|
117
|
-
else
|
118
|
-
arg = def_arg.default
|
119
|
-
end
|
120
|
-
|
121
|
-
argv.push(arg)
|
122
|
-
end
|
123
|
-
|
124
|
-
args = argv
|
98
|
+
check_method_named_args(args.first, def_args)
|
125
99
|
else
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
raise TypeError if def_arg.type and not args[i].is_a?(def_arg.type)
|
100
|
+
check_method_ordered_args(args, def_args)
|
101
|
+
end
|
102
|
+
end
|
130
103
|
|
131
|
-
|
104
|
+
def self.check_method_named_args(object, def_args)
|
105
|
+
members = object.entries.map {|k, _| k}
|
106
|
+
argv = []
|
107
|
+
def_args.each do |def_arg|
|
108
|
+
raise MissingArgError if def_arg.required and not members.include?(def_arg.name)
|
132
109
|
|
133
|
-
|
110
|
+
if members.include?(def_arg.name)
|
111
|
+
arg = object[def_arg.name]
|
112
|
+
raise TypeError if def_arg.type and not arg.is_a?(def_arg.type)
|
113
|
+
else
|
114
|
+
arg = def_arg.default
|
134
115
|
end
|
116
|
+
|
117
|
+
argv.push(arg)
|
118
|
+
end
|
119
|
+
|
120
|
+
argv
|
121
|
+
end
|
122
|
+
private_class_method :check_method_named_args
|
123
|
+
|
124
|
+
def self.check_method_ordered_args(args, def_args)
|
125
|
+
def_args.each_with_index do |def_arg, index|
|
126
|
+
raise MissingArgError if def_arg.required and index >= args.length
|
127
|
+
raise TypeError if def_arg.type and not args[index].is_a?(def_arg.type)
|
128
|
+
|
129
|
+
args.push(def_arg.default) if index >= args.length
|
135
130
|
end
|
136
131
|
|
137
132
|
args
|
138
133
|
end
|
134
|
+
private_class_method :check_method_ordered_args
|
139
135
|
|
140
136
|
def self.acro_method(name, *def_args, &b)
|
141
137
|
define_method(name) do |*args|
|
@@ -158,7 +154,9 @@ module Origami
|
|
158
154
|
)
|
159
155
|
end
|
160
156
|
|
161
|
-
|
157
|
+
unless @engine.privileged?
|
158
|
+
raise NotAllowedError, "Security settings prevent access to this property or method."
|
159
|
+
end
|
162
160
|
|
163
161
|
args = AcrobatObject.check_method_args(args, def_args)
|
164
162
|
self.instance_exec(*args, &b) if b
|
@@ -230,12 +228,12 @@ module Origami
|
|
230
228
|
|
231
229
|
acro_method 'setPersistent',
|
232
230
|
Arg[name: 'cVariable', required: true],
|
233
|
-
Arg[name: 'bPersist', required: true] do |cVariable,
|
231
|
+
Arg[name: 'bPersist', required: true] do |cVariable, _bPersist|
|
234
232
|
|
235
233
|
raise GeneralError unless @vars.include?(cVariable)
|
236
234
|
end
|
237
235
|
|
238
|
-
|
236
|
+
acro_method 'subscribe',
|
239
237
|
Arg[name: 'cVariable', required: true],
|
240
238
|
Arg[name: 'fCallback', type: V8::Function, require: true] do |cVariable, fCallback|
|
241
239
|
|
@@ -344,7 +342,7 @@ module Origami
|
|
344
342
|
|
345
343
|
acro_method 'getDataObjectContents',
|
346
344
|
Arg[name: 'cName', type: ::String, required: true],
|
347
|
-
Arg[name: 'bAllowAuth', default: false] do |cName,
|
345
|
+
Arg[name: 'bAllowAuth', default: false] do |cName, _bAllowAuth|
|
348
346
|
|
349
347
|
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
350
348
|
|
@@ -359,7 +357,7 @@ module Origami
|
|
359
357
|
Arg[name: 'cName', type: ::String, required: true],
|
360
358
|
Arg[name: 'cDIPath' ],
|
361
359
|
Arg[name: 'bAllowAuth'],
|
362
|
-
Arg[name: 'nLaunch'] do |cName,
|
360
|
+
Arg[name: 'nLaunch'] do |cName, _cDIPath, _bAllowAuth, _nLaunch|
|
363
361
|
|
364
362
|
file_desc = @pdf.resolve_name(Names::EMBEDDED_FILES, cName)
|
365
363
|
|
@@ -454,7 +452,7 @@ module Origami
|
|
454
452
|
class Console < AcrobatObject
|
455
453
|
def println(*args)
|
456
454
|
raise MissingArgError unless args.length > 0
|
457
|
-
|
455
|
+
|
458
456
|
@engine.options[:console].puts(args.first.to_s)
|
459
457
|
end
|
460
458
|
|
@@ -466,14 +464,14 @@ module Origami
|
|
466
464
|
class Util < AcrobatObject
|
467
465
|
acro_method 'streamFromString',
|
468
466
|
Arg[name: 'cString', type: ::Object, required: true],
|
469
|
-
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |cString,
|
467
|
+
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |cString, _cCharset|
|
470
468
|
|
471
469
|
ReadStream.new(@engine, cString.to_s)
|
472
470
|
end
|
473
471
|
|
474
472
|
acro_method 'stringFromStream',
|
475
473
|
Arg[name: 'oStream', type: ReadStream, required: true],
|
476
|
-
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |oStream,
|
474
|
+
Arg[name: 'cCharset', type: ::Object, default: 'utf-8'] do |oStream, _cCharset|
|
477
475
|
|
478
476
|
oStream.instance_variable_get(:@data).dup
|
479
477
|
end
|
@@ -500,32 +498,46 @@ module Origami
|
|
500
498
|
end
|
501
499
|
|
502
500
|
def type
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
501
|
+
return '' unless @field.key?(:FT)
|
502
|
+
|
503
|
+
type_name =
|
504
|
+
case @field.FT.value
|
505
|
+
when PDF::Field::Type::BUTTON
|
506
|
+
button_type
|
507
|
+
|
508
|
+
when PDF::Field::Type::TEXT then 'text'
|
509
|
+
when PDF::Field::Type::SIGNATURE then 'signature'
|
510
|
+
when PDF::Field::Type::CHOICE
|
511
|
+
choice_type
|
512
|
+
end
|
513
|
+
|
514
|
+
type_name.to_s
|
515
|
+
end
|
516
|
+
|
517
|
+
private
|
518
|
+
|
519
|
+
def button_type
|
520
|
+
return if @field.key?(:Ff) and not @field.Ff.is_a?(Integer)
|
521
|
+
|
522
|
+
flags = @field.Ff.to_i
|
523
|
+
|
524
|
+
if (flags & Annotation::Widget::Button::Flags::PUSHBUTTON) != 0
|
525
|
+
'button'
|
526
|
+
elsif (flags & Annotation::Widget::Button::Flags::RADIO) != 0
|
527
|
+
'radiobox'
|
528
|
+
else
|
529
|
+
'checkbox'
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
def choice_type
|
534
|
+
return if @field.key?(:Ff) and not @field.Ff.is_a?(Integer)
|
535
|
+
|
536
|
+
if (@field.Ff.to_i & Annotation::Widget::Choice::Flags::COMBO) != 0
|
537
|
+
'combobox'
|
538
|
+
else
|
539
|
+
'listbox'
|
540
|
+
end
|
529
541
|
end
|
530
542
|
end
|
531
543
|
|
@@ -553,6 +565,7 @@ module Origami
|
|
553
565
|
attr_reader :doc
|
554
566
|
attr_reader :context
|
555
567
|
attr_reader :options
|
568
|
+
attr_reader :privileged_mode
|
556
569
|
attr_reader :parseInt
|
557
570
|
|
558
571
|
def initialize(pdf)
|
@@ -563,16 +576,26 @@ module Origami
|
|
563
576
|
viewerVariation: JavaScript::Viewers::ADOBE_READER,
|
564
577
|
platform: JavaScript::Platforms::WINDOWS,
|
565
578
|
console: STDOUT,
|
566
|
-
log_method_calls: false
|
579
|
+
log_method_calls: false,
|
580
|
+
privileged_mode: false
|
567
581
|
}
|
568
582
|
|
569
583
|
@doc = JavaScript::Doc.new(self, pdf)
|
570
584
|
@context = V8::Context.new(with: @doc)
|
585
|
+
@privileged_mode = @options[:privileged_mode]
|
571
586
|
|
572
587
|
@parseInt = V8::Context.new['parseInt']
|
573
588
|
@hooks = {}
|
574
589
|
end
|
575
590
|
|
591
|
+
#
|
592
|
+
# Returns true if the engine is set to execute in privileged mode.
|
593
|
+
# Allows execution of security protected methods.
|
594
|
+
#
|
595
|
+
def privileged?
|
596
|
+
@privileged_mode
|
597
|
+
end
|
598
|
+
|
576
599
|
#
|
577
600
|
# Evaluates a JavaScript code in the current context.
|
578
601
|
#
|
@@ -50,29 +50,17 @@ module Origami
|
|
50
50
|
#
|
51
51
|
prev_trailer = @revisions.first.trailer
|
52
52
|
|
53
|
-
|
54
|
-
hints = lin_dict[:H]
|
53
|
+
linear_dict = @revisions.first.objects.min_by{|obj| obj.file_offset}
|
55
54
|
|
56
55
|
#
|
57
56
|
# Removes hint streams used by linearization.
|
58
57
|
#
|
59
|
-
|
60
|
-
if hints.length > 0 and hints[0].is_a?(Integer)
|
61
|
-
hint_stream = get_object_by_offset(hints[0])
|
62
|
-
delete_object(hint_stream.reference) if hint_stream.is_a?(Stream)
|
63
|
-
end
|
64
|
-
|
65
|
-
if hints.length > 2 and hints[2].is_a?(Integer)
|
66
|
-
overflow_stream = get_object_by_offset(hints[2])
|
67
|
-
delete_object(overflow_stream.reference) if overflow_stream.is_a?(Stream)
|
68
|
-
end
|
69
|
-
end
|
58
|
+
delete_hint_streams(linear_dict)
|
70
59
|
|
71
60
|
#
|
72
61
|
# Update the trailer.
|
73
62
|
#
|
74
63
|
last_trailer = (@revisions.last.trailer ||= Trailer.new)
|
75
|
-
|
76
64
|
last_trailer.dictionary ||= Dictionary.new
|
77
65
|
|
78
66
|
if prev_trailer.has_dictionary?
|
@@ -98,13 +86,30 @@ module Origami
|
|
98
86
|
#
|
99
87
|
# Remove the linearization revision.
|
100
88
|
#
|
101
|
-
@revisions.first.body.delete(
|
89
|
+
@revisions.first.body.delete(linear_dict.reference)
|
102
90
|
@revisions.last.body.merge! @revisions.first.body
|
103
91
|
|
104
92
|
remove_revision(0)
|
105
93
|
|
106
94
|
self
|
107
95
|
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
#
|
100
|
+
# Strip the document from Hint streams given a linearization dictionary.
|
101
|
+
#
|
102
|
+
def delete_hint_streams(linearization_dict)
|
103
|
+
hints = linearization_dict[:H]
|
104
|
+
return unless hints.is_a?(Array)
|
105
|
+
|
106
|
+
hints.each_slice(2) do |offset, _length|
|
107
|
+
next unless offset.is_a?(Integer)
|
108
|
+
|
109
|
+
stream = get_object_by_offset(offset)
|
110
|
+
delete_object(stream.reference) if stream.is_a?(Stream)
|
111
|
+
end
|
112
|
+
end
|
108
113
|
end
|
109
114
|
|
110
115
|
#
|
@@ -192,10 +197,9 @@ module Origami
|
|
192
197
|
data << [ item_data ].pack("B*")
|
193
198
|
end
|
194
199
|
|
195
|
-
i = 0
|
196
200
|
nitems = self.class.nb_entry_items
|
197
|
-
@entries.
|
198
|
-
for no in (1..
|
201
|
+
@entries.each_with_index do |entry, i|
|
202
|
+
for no in (1..nitems)
|
199
203
|
unless entry.include?(no)
|
200
204
|
raise InvalidHintTableError, "Missing item #{no} in entry #{i} of #{self.class}"
|
201
205
|
end
|
@@ -209,8 +213,6 @@ module Origami
|
|
209
213
|
|
210
214
|
data << [ item_data ].pack("B*")
|
211
215
|
end
|
212
|
-
|
213
|
-
i = i + 1
|
214
216
|
end
|
215
217
|
|
216
218
|
data
|
data/lib/origami/metadata.rb
CHANGED
@@ -87,7 +87,7 @@ module Origami
|
|
87
87
|
#
|
88
88
|
def create_metadata(info = {})
|
89
89
|
skeleton = <<-XMP
|
90
|
-
<?packet begin="
|
90
|
+
<?packet begin="\xef\xbb\xbf" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
91
91
|
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
92
92
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
93
93
|
<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
|
data/lib/origami/name.rb
CHANGED
@@ -76,7 +76,7 @@ module Origami
|
|
76
76
|
super(TOKENS.first + Name.expand(@value))
|
77
77
|
end
|
78
78
|
|
79
|
-
def self.parse(stream,
|
79
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
80
80
|
offset = stream.pos
|
81
81
|
|
82
82
|
name =
|
@@ -127,8 +127,6 @@ module Origami
|
|
127
127
|
"#" + c.ord.to_s(16).rjust(2,"0")
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
131
|
-
def self.native_type ; Name end
|
132
130
|
end
|
133
131
|
|
134
132
|
end
|
data/lib/origami/null.rb
CHANGED
@@ -36,7 +36,7 @@ module Origami
|
|
36
36
|
super
|
37
37
|
end
|
38
38
|
|
39
|
-
def self.parse(stream,
|
39
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
40
40
|
offset = stream.pos
|
41
41
|
|
42
42
|
if stream.skip(@@regexp).nil?
|
@@ -59,8 +59,6 @@ module Origami
|
|
59
59
|
def to_s #:nodoc:
|
60
60
|
super(TOKENS.first)
|
61
61
|
end
|
62
|
-
|
63
|
-
def self.native_type ; Null end
|
64
62
|
end
|
65
63
|
|
66
64
|
end
|
data/lib/origami/numeric.rb
CHANGED
@@ -86,22 +86,12 @@ module Origami
|
|
86
86
|
def to_s
|
87
87
|
super(value.to_s)
|
88
88
|
end
|
89
|
-
|
90
|
-
module ClassMethods #:nodoc:all
|
91
|
-
def native_type; Number end
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.included(receiver) #:nodoc:
|
95
|
-
receiver.extend(ClassMethods)
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.native_type; Number end #:nodoc:
|
99
89
|
end
|
100
90
|
|
101
91
|
#
|
102
92
|
# Class representing an Integer Object.
|
103
93
|
#
|
104
|
-
class Integer < DelegateClass(
|
94
|
+
class Integer < DelegateClass(::Integer)
|
105
95
|
include Number
|
106
96
|
|
107
97
|
TOKENS = [ "(\\+|-)?[\\d]+[^.]?" ] #:nodoc:
|
@@ -121,7 +111,7 @@ module Origami
|
|
121
111
|
super(i)
|
122
112
|
end
|
123
113
|
|
124
|
-
def self.parse(stream,
|
114
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
125
115
|
offset = stream.pos
|
126
116
|
|
127
117
|
if not stream.scan(@@regexp)
|
@@ -165,7 +155,7 @@ module Origami
|
|
165
155
|
super(f)
|
166
156
|
end
|
167
157
|
|
168
|
-
def self.parse(stream,
|
158
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
169
159
|
offset = stream.pos
|
170
160
|
|
171
161
|
if not stream.scan(@@regexp)
|
data/lib/origami/object.rb
CHANGED
@@ -25,13 +25,7 @@ module Origami
|
|
25
25
|
|
26
26
|
module TypeConversion
|
27
27
|
|
28
|
-
refine ::
|
29
|
-
def to_o
|
30
|
-
Origami::Integer.new(self)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
refine ::Fixnum do
|
28
|
+
refine ::Integer do
|
35
29
|
def to_o
|
36
30
|
Origami::Integer.new(self)
|
37
31
|
end
|
@@ -92,6 +86,30 @@ module Origami
|
|
92
86
|
class Error < StandardError
|
93
87
|
end
|
94
88
|
|
89
|
+
#
|
90
|
+
# Provides an easier syntax for field access.
|
91
|
+
# The object must have the defined the methods #[] and #[]=.
|
92
|
+
#
|
93
|
+
# Once included, object.Field will automatically resolve to object[:Field].
|
94
|
+
# References are automatically followed.
|
95
|
+
#
|
96
|
+
module FieldAccessor
|
97
|
+
def method_missing(field, *args)
|
98
|
+
raise NoMethodError, "No method `#{field}' for #{self.class}" unless field =~ /^[[:upper:]]/
|
99
|
+
|
100
|
+
if field[-1] == '='
|
101
|
+
self[field[0..-2].to_sym] = args.first
|
102
|
+
else
|
103
|
+
object = self[field]
|
104
|
+
object.is_a?(Reference) ? object.solve : object
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def respond_to_missing?(field, *)
|
109
|
+
not (field =~ /^[[:upper:]]/).nil? or super
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
95
113
|
#
|
96
114
|
# Mixin' module for objects which can store their options into an inner Dictionary.
|
97
115
|
#
|
@@ -114,9 +132,12 @@ module Origami
|
|
114
132
|
@fields
|
115
133
|
end
|
116
134
|
|
135
|
+
#
|
136
|
+
# Define a new field with given attributes.
|
137
|
+
#
|
117
138
|
def field(name, attributes)
|
118
139
|
if attributes[:Required] == true and attributes.has_key?(:Default) and attributes[:Type] == Name
|
119
|
-
self.
|
140
|
+
self.add_type_signature(name, attributes[:Default])
|
120
141
|
end
|
121
142
|
|
122
143
|
if @fields.has_key?(name)
|
@@ -128,7 +149,30 @@ module Origami
|
|
128
149
|
define_field_methods(name)
|
129
150
|
end
|
130
151
|
|
131
|
-
|
152
|
+
#
|
153
|
+
# Returns an array of required fields for the current Object.
|
154
|
+
#
|
155
|
+
def required_fields
|
156
|
+
fields = []
|
157
|
+
@fields.each_pair do |name, attributes|
|
158
|
+
fields << name if attributes[:Required] == true
|
159
|
+
end
|
160
|
+
|
161
|
+
fields
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Returns the expected type for a field name.
|
166
|
+
#
|
167
|
+
def hint_type(name)
|
168
|
+
if @fields.has_key?(name)
|
169
|
+
@fields[name][:Type]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def define_field_methods(field) #:nodoc:
|
132
176
|
|
133
177
|
#
|
134
178
|
# Getter method.
|
@@ -157,24 +201,6 @@ module Origami
|
|
157
201
|
self
|
158
202
|
end
|
159
203
|
end
|
160
|
-
|
161
|
-
#
|
162
|
-
# Returns an array of required fields for the current Object.
|
163
|
-
#
|
164
|
-
def required_fields
|
165
|
-
fields = []
|
166
|
-
@fields.each_pair do |name, attributes|
|
167
|
-
fields << name if attributes[:Required] == true
|
168
|
-
end
|
169
|
-
|
170
|
-
fields
|
171
|
-
end
|
172
|
-
|
173
|
-
def hint_type(name)
|
174
|
-
if @fields.has_key?(name)
|
175
|
-
@fields[name][:Type]
|
176
|
-
end
|
177
|
-
end
|
178
204
|
end
|
179
205
|
|
180
206
|
def pre_build #:nodoc:
|
@@ -184,14 +210,6 @@ module Origami
|
|
184
210
|
super
|
185
211
|
end
|
186
212
|
|
187
|
-
#
|
188
|
-
# Check if an attribute is set in the current Object.
|
189
|
-
# _attr_:: The attribute name.
|
190
|
-
#
|
191
|
-
def has_field? (field)
|
192
|
-
not self[field].nil?
|
193
|
-
end
|
194
|
-
|
195
213
|
#
|
196
214
|
# Returns the version and level required by the current Object.
|
197
215
|
#
|
@@ -218,6 +236,8 @@ module Origami
|
|
218
236
|
max
|
219
237
|
end
|
220
238
|
|
239
|
+
private
|
240
|
+
|
221
241
|
def set_default_value(field) #:nodoc:
|
222
242
|
if self.class.fields[field][:Default]
|
223
243
|
self[field] = self.class.fields[field][:Default]
|
@@ -227,7 +247,7 @@ module Origami
|
|
227
247
|
|
228
248
|
def set_default_values #:nodoc:
|
229
249
|
self.class.required_fields.each do |field|
|
230
|
-
set_default_value(field) unless
|
250
|
+
set_default_value(field) unless self.key?(field)
|
231
251
|
end
|
232
252
|
end
|
233
253
|
|
@@ -238,18 +258,18 @@ module Origami
|
|
238
258
|
begin
|
239
259
|
field_value = self[field].solve
|
240
260
|
rescue InvalidReferenceError
|
241
|
-
STDERR.puts "Warning: in object #{self.class}, field `#{field
|
261
|
+
STDERR.puts "Warning: in object #{self.class}, field `#{field}' is an invalid reference (#{self[field]})"
|
242
262
|
next
|
243
263
|
end
|
244
264
|
|
245
265
|
types = attributes[:Type].is_a?(::Array) ? attributes[:Type] : [ attributes[:Type] ]
|
246
266
|
|
247
267
|
unless types.any? {|type| not type.is_a?(Class) or field_value.is_a?(type.native_type)}
|
248
|
-
STDERR.puts "Warning: in object #{self.class}, field `#{field
|
268
|
+
STDERR.puts "Warning: in object #{self.class}, field `#{field}' has unexpected type #{field_value.class}"
|
249
269
|
end
|
250
270
|
|
251
271
|
if attributes.key?(:Assert) and not (attributes[:Assert] === field_value)
|
252
|
-
STDERR.puts "Warning: assertion failed for field `#{field
|
272
|
+
STDERR.puts "Warning: assertion failed for field `#{field}' in object #{self.class}"
|
253
273
|
end
|
254
274
|
end
|
255
275
|
end
|
@@ -267,7 +287,7 @@ module Origami
|
|
267
287
|
end
|
268
288
|
end
|
269
289
|
|
270
|
-
WHITESPACES = "([ \\f\\t\\r\\n\\0]|%[^\\n]
|
290
|
+
WHITESPACES = "([ \\f\\t\\r\\n\\0]|%[^\\n\\r]*(\\r\\n|\\r|\\n))*" #:nodoc:
|
271
291
|
WHITECHARS_NORET = "[ \\f\\t\\0]*" #:nodoc:
|
272
292
|
EOL = "\r\n" #:nodoc:
|
273
293
|
WHITECHARS = "[ \\f\\t\\r\\n\\0]*" #:nodoc:
|
@@ -296,6 +316,36 @@ module Origami
|
|
296
316
|
attr_accessor :no, :generation, :file_offset, :objstm_offset
|
297
317
|
attr_accessor :parent
|
298
318
|
|
319
|
+
#
|
320
|
+
# Modules or classes including this module are considered native types.
|
321
|
+
#
|
322
|
+
def self.included(base)
|
323
|
+
base.class_variable_set(:@@native_type, base)
|
324
|
+
base.extend(ClassMethods)
|
325
|
+
end
|
326
|
+
|
327
|
+
module ClassMethods
|
328
|
+
# Returns the native type of the derived class or module.
|
329
|
+
def native_type
|
330
|
+
self.class_variable_get(:@@native_type)
|
331
|
+
end
|
332
|
+
|
333
|
+
private
|
334
|
+
|
335
|
+
# Propagate native type to submodules.
|
336
|
+
def included(klass)
|
337
|
+
klass.class_variable_set(:@@native_type, self)
|
338
|
+
klass.extend(ClassMethods)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
#
|
343
|
+
# Returns the native type of the Object.
|
344
|
+
#
|
345
|
+
def native_type
|
346
|
+
self.class.native_type
|
347
|
+
end
|
348
|
+
|
299
349
|
#
|
300
350
|
# Creates a new PDF Object.
|
301
351
|
#
|
@@ -395,31 +445,18 @@ module Origami
|
|
395
445
|
#
|
396
446
|
def xrefs
|
397
447
|
raise InvalidObjectError, "Cannot find xrefs to a direct object" unless self.indirect?
|
448
|
+
raise InvalidObjectError, "Not attached to any document" if self.document.nil?
|
398
449
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
@document.root_objects.each do |obj|
|
405
|
-
if obj.is_a?(ObjectStream)
|
406
|
-
obj.each do |child|
|
407
|
-
case child
|
450
|
+
@document.each_object(compressed: true)
|
451
|
+
.flat_map { |object|
|
452
|
+
case object
|
453
|
+
when Stream
|
454
|
+
object.dictionary.xref_cache[self.reference]
|
408
455
|
when Dictionary, Array
|
409
|
-
|
456
|
+
object.xref_cache[self.reference]
|
410
457
|
end
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
obj = obj.dictionary if obj.is_a?(Stream)
|
415
|
-
|
416
|
-
case obj
|
417
|
-
when Dictionary, Array
|
418
|
-
refs.concat obj.xref_cache[self.reference] if obj.xref_cache.key?(self.reference)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
refs
|
458
|
+
}
|
459
|
+
.compact!
|
423
460
|
end
|
424
461
|
|
425
462
|
#
|
@@ -459,7 +496,7 @@ module Origami
|
|
459
496
|
|
460
497
|
if obj.is_a?(ObjectStream)
|
461
498
|
obj.each do |subobj|
|
462
|
-
resolve_all_references[
|
499
|
+
resolve_all_references[subobj, browsed, ref_cache]
|
463
500
|
end
|
464
501
|
end
|
465
502
|
|
@@ -629,15 +666,6 @@ module Origami
|
|
629
666
|
name.split("::").last.to_sym
|
630
667
|
end
|
631
668
|
|
632
|
-
def self.native_type; Origami::Object end #:nodoc:
|
633
|
-
|
634
|
-
#
|
635
|
-
# Returns the native PDF type of this Object.
|
636
|
-
#
|
637
|
-
def native_type
|
638
|
-
self.class.native_type
|
639
|
-
end
|
640
|
-
|
641
669
|
def cast_to(type, _parser = nil) #:nodoc:
|
642
670
|
if type.native_type != self.native_type
|
643
671
|
raise TypeError, "Incompatible cast from #{self.class} to #{type}"
|