origami 1.0.4 → 1.1.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.
- data/README +40 -49
- data/bin/gui/about.rb +1 -1
- data/bin/pdfencrypt +10 -4
- data/origami/actions.rb +0 -1
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +103 -14
- data/origami/graphics.rb +1 -0
- data/origami/graphics/colors.rb +23 -23
- data/origami/graphics/instruction.rb +7 -29
- data/origami/graphics/path.rb +53 -19
- data/origami/graphics/render.rb +69 -0
- data/origami/graphics/state.rb +9 -9
- data/origami/graphics/text.rb +66 -48
- data/origami/graphics/xobject.rb +65 -50
- data/origami/javascript.rb +135 -0
- data/origami/metadata.rb +24 -0
- data/origami/object.rb +1 -1
- data/origami/page.rb +12 -0
- data/origami/parsers/pdf/linear.rb +0 -0
- data/origami/pdf.rb +2 -2
- metadata +77 -75
- data/VERSION +0 -1
data/origami/graphics/xobject.rb
CHANGED
@@ -41,19 +41,30 @@ module Origami
|
|
41
41
|
DEFAULT_LINEWIDTH = 1.0
|
42
42
|
|
43
43
|
attr_reader :instructions
|
44
|
+
attr_accessor :canvas
|
44
45
|
|
45
46
|
def initialize(rawdata = "", dictionary = {})
|
46
47
|
|
47
48
|
@instructions = nil
|
48
|
-
@
|
49
|
+
@canvas = Graphics::DummyCanvas.new
|
49
50
|
|
50
51
|
super(rawdata, dictionary)
|
51
52
|
end
|
52
53
|
|
54
|
+
def render(engine)
|
55
|
+
load! if @instructions.nil?
|
56
|
+
|
57
|
+
@instructions.each do |instruction|
|
58
|
+
instruction.render(engine)
|
59
|
+
end
|
60
|
+
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
53
64
|
def pre_build #:nodoc:
|
54
65
|
load! if @instructions.nil?
|
55
|
-
if @gs.text_state.is_in_text_object?
|
56
|
-
@instructions << PDF::Instruction.new('ET').
|
66
|
+
if @canvas.gs.text_state.is_in_text_object?
|
67
|
+
@instructions << PDF::Instruction.new('ET').render(@canvas)
|
57
68
|
end
|
58
69
|
|
59
70
|
@data = @instructions.join
|
@@ -99,16 +110,16 @@ module Origami
|
|
99
110
|
set_line_join(line_join)
|
100
111
|
set_dash_pattern(dash_pattern)
|
101
112
|
|
102
|
-
if @gs.text_state.is_in_text_object?
|
103
|
-
@instructions << PDF::Instruction.new('ET').
|
113
|
+
if @canvas.gs.text_state.is_in_text_object?
|
114
|
+
@instructions << PDF::Instruction.new('ET').render(@canvas)
|
104
115
|
end
|
105
116
|
|
106
117
|
unless coords.size < 1
|
107
118
|
x,y = coords.slice!(0)
|
108
|
-
@instructions << PDF::Instruction.new('m',x,y).
|
119
|
+
@instructions << PDF::Instruction.new('m',x,y).render(@canvas)
|
109
120
|
|
110
121
|
coords.each do |px,py|
|
111
|
-
@instructions << PDF::Instruction.new('l',px,py).
|
122
|
+
@instructions << PDF::Instruction.new('l',px,py).render(@canvas)
|
112
123
|
end
|
113
124
|
|
114
125
|
@instructions << (i =
|
@@ -121,7 +132,7 @@ module Origami
|
|
121
132
|
end
|
122
133
|
)
|
123
134
|
|
124
|
-
i.
|
135
|
+
i.render(@canvas)
|
125
136
|
end
|
126
137
|
|
127
138
|
self
|
@@ -152,11 +163,11 @@ module Origami
|
|
152
163
|
set_line_join(line_join)
|
153
164
|
set_dash_pattern(dash_pattern)
|
154
165
|
|
155
|
-
if @gs.text_state.is_in_text_object?
|
156
|
-
@instructions << PDF::Instruction.new('ET').
|
166
|
+
if @canvas.gs.text_state.is_in_text_object?
|
167
|
+
@instructions << PDF::Instruction.new('ET').render(@canvas)
|
157
168
|
end
|
158
169
|
|
159
|
-
@instructions << PDF::Instruction.new('re', x,y,width,height).
|
170
|
+
@instructions << PDF::Instruction.new('re', x,y,width,height).render(@canvas)
|
160
171
|
|
161
172
|
@instructions << (i =
|
162
173
|
if stroke and not fill
|
@@ -168,7 +179,7 @@ module Origami
|
|
168
179
|
end
|
169
180
|
)
|
170
181
|
|
171
|
-
i.
|
182
|
+
i.render(@canvas)
|
172
183
|
|
173
184
|
self
|
174
185
|
end
|
@@ -194,10 +205,10 @@ module Origami
|
|
194
205
|
rise = attr[:rise]
|
195
206
|
rendering = attr[:rendering]
|
196
207
|
|
197
|
-
@instructions << PDF::Instruction.new('ET').
|
208
|
+
@instructions << PDF::Instruction.new('ET').render(@canvas) if (x or y) and @canvas.gs.text_state.is_in_text_object?
|
198
209
|
|
199
|
-
unless @gs.text_state.is_in_text_object?
|
200
|
-
@instructions << PDF::Instruction.new('BT').
|
210
|
+
unless @canvas.gs.text_state.is_in_text_object?
|
211
|
+
@instructions << PDF::Instruction.new('BT').render(@canvas)
|
201
212
|
end
|
202
213
|
|
203
214
|
set_text_font(font, size)
|
@@ -219,15 +230,15 @@ module Origami
|
|
219
230
|
|
220
231
|
def paint_shading(shade)
|
221
232
|
load! if @instructions.nil?
|
222
|
-
@instructions << PDF::Instruction.new('sh', shade).
|
233
|
+
@instructions << PDF::Instruction.new('sh', shade).render(@canvas)
|
223
234
|
|
224
235
|
self
|
225
236
|
end
|
226
237
|
|
227
238
|
def set_text_font(fontname, size)
|
228
239
|
load! if @instructions.nil?
|
229
|
-
if fontname != @gs.text_state.font or size != @gs.text_state.font_size
|
230
|
-
@instructions << PDF::Instruction.new('Tf', fontname, size).
|
240
|
+
if fontname != @canvas.gs.text_state.font or size != @canvas.gs.text_state.font_size
|
241
|
+
@instructions << PDF::Instruction.new('Tf', fontname, size).render(@canvas)
|
231
242
|
end
|
232
243
|
|
233
244
|
self
|
@@ -235,15 +246,15 @@ module Origami
|
|
235
246
|
|
236
247
|
def set_text_pos(tx,ty)
|
237
248
|
load! if @instructions.nil?
|
238
|
-
@instructions << PDF::Instruction.new('Td', tx, ty).
|
249
|
+
@instructions << PDF::Instruction.new('Td', tx, ty).render(@canvas)
|
239
250
|
|
240
251
|
self
|
241
252
|
end
|
242
253
|
|
243
254
|
def set_text_leading(leading)
|
244
255
|
load! if @instructions.nil?
|
245
|
-
if leading != @gs.text_state.leading
|
246
|
-
@instructions << PDF::Instruction.new('TL', leading).
|
256
|
+
if leading != @canvas.gs.text_state.leading
|
257
|
+
@instructions << PDF::Instruction.new('TL', leading).render(@canvas)
|
247
258
|
end
|
248
259
|
|
249
260
|
self
|
@@ -251,8 +262,8 @@ module Origami
|
|
251
262
|
|
252
263
|
def set_text_rendering(rendering)
|
253
264
|
load! if @instructions.nil?
|
254
|
-
if rendering != @gs.text_state.rendering_mode
|
255
|
-
@instructions << PDF::Instruction.new('Tr', rendering).
|
265
|
+
if rendering != @canvas.gs.text_state.rendering_mode
|
266
|
+
@instructions << PDF::Instruction.new('Tr', rendering).render(@canvas)
|
256
267
|
end
|
257
268
|
|
258
269
|
self
|
@@ -260,8 +271,8 @@ module Origami
|
|
260
271
|
|
261
272
|
def set_text_rise(rise)
|
262
273
|
load! if @instructions.nil?
|
263
|
-
if rise != @gs.text_state.text_rise
|
264
|
-
@instructions << PDF::Instruction.new('Ts', rise).
|
274
|
+
if rise != @canvas.gs.text_state.text_rise
|
275
|
+
@instructions << PDF::Instruction.new('Ts', rise).render(@canvas)
|
265
276
|
end
|
266
277
|
|
267
278
|
self
|
@@ -269,8 +280,8 @@ module Origami
|
|
269
280
|
|
270
281
|
def set_text_scale(scaling)
|
271
282
|
load! if @instructions.nil?
|
272
|
-
if scale != @gs.text_state.scaling
|
273
|
-
@instructions << PDF::Instruction.new('Tz', scaling).
|
283
|
+
if scale != @canvas.gs.text_state.scaling
|
284
|
+
@instructions << PDF::Instruction.new('Tz', scaling).render(@canvas)
|
274
285
|
end
|
275
286
|
|
276
287
|
self
|
@@ -278,8 +289,8 @@ module Origami
|
|
278
289
|
|
279
290
|
def set_text_word_spacing(word_spacing)
|
280
291
|
load! if @instructions.nil?
|
281
|
-
if word_spacing != @gs.text_state.word_spacing
|
282
|
-
@instructions << PDF::Instruction.new('Tw', word_spacing).
|
292
|
+
if word_spacing != @canvas.gs.text_state.word_spacing
|
293
|
+
@instructions << PDF::Instruction.new('Tw', word_spacing).render(@canvas)
|
283
294
|
end
|
284
295
|
|
285
296
|
self
|
@@ -287,8 +298,8 @@ module Origami
|
|
287
298
|
|
288
299
|
def set_text_char_spacing(char_spacing)
|
289
300
|
load! if @instructions.nil?
|
290
|
-
if char_spacing != @gs.text_state.char_spacing
|
291
|
-
@instructions << PDF::Instruction.new('Tc', char_spacing).
|
301
|
+
if char_spacing != @canvas.gs.text_state.char_spacing
|
302
|
+
@instructions << PDF::Instruction.new('Tc', char_spacing).render(@canvas)
|
292
303
|
end
|
293
304
|
|
294
305
|
self
|
@@ -302,25 +313,25 @@ module Origami
|
|
302
313
|
r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
|
303
314
|
g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
|
304
315
|
b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
|
305
|
-
PDF::Instruction.new('rg', r, g, b) if @gs.nonstroking_color != [r,g,b]
|
316
|
+
PDF::Instruction.new('rg', r, g, b) if @canvas.gs.nonstroking_color != [r,g,b]
|
306
317
|
|
307
318
|
elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
|
308
319
|
c = (color.respond_to?(:c) ? color.c : color[0]).to_f
|
309
320
|
m = (color.respond_to?(:m) ? color.m : color[1]).to_f
|
310
321
|
y = (color.respond_to?(:y) ? color.y : color[2]).to_f
|
311
322
|
k = (color.respond_to?(:k) ? color.k : color[3]).to_f
|
312
|
-
PDF::Instruction.new('k', c, m, y, k) if @gs.nonstroking_color != [c,m,y,k]
|
323
|
+
PDF::Instruction.new('k', c, m, y, k) if @canvas.gs.nonstroking_color != [c,m,y,k]
|
313
324
|
|
314
325
|
elsif color.respond_to?:g or (0.0..1.0) === color
|
315
326
|
g = color.respond_to?(:g) ? color.g : color
|
316
|
-
PDF::Instruction.new('g', g) if @gs.nonstroking_color != [ g ]
|
327
|
+
PDF::Instruction.new('g', g) if @canvas.gs.nonstroking_color != [ g ]
|
317
328
|
|
318
329
|
else
|
319
330
|
raise TypeError, "Invalid color : #{color}"
|
320
331
|
end
|
321
332
|
)
|
322
333
|
|
323
|
-
i.
|
334
|
+
i.render(@canvas) if i
|
324
335
|
self
|
325
336
|
end
|
326
337
|
|
@@ -332,32 +343,32 @@ module Origami
|
|
332
343
|
r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
|
333
344
|
g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
|
334
345
|
b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
|
335
|
-
PDF::Instruction.new('RG', r, g, b) if @gs.stroking_color != [r,g,b]
|
346
|
+
PDF::Instruction.new('RG', r, g, b) if @canvas.gs.stroking_color != [r,g,b]
|
336
347
|
|
337
348
|
elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k) or (color.is_a?(::Array) and color.size == 4)
|
338
349
|
c = (color.respond_to?(:c) ? color.c : color[0]).to_f
|
339
350
|
m = (color.respond_to?(:m) ? color.m : color[1]).to_f
|
340
351
|
y = (color.respond_to?(:y) ? color.y : color[2]).to_f
|
341
352
|
k = (color.respond_to?(:k) ? color.k : color[3]).to_f
|
342
|
-
PDF::Instruction.new('K', c, m, y, k) if @gs.stroking_color != [c,m,y,k]
|
353
|
+
PDF::Instruction.new('K', c, m, y, k) if @canvas.gs.stroking_color != [c,m,y,k]
|
343
354
|
|
344
355
|
elsif color.respond_to?:g or (0.0..1.0) === color
|
345
356
|
g = color.respond_to?(:g) ? color.g : color
|
346
|
-
PDF::Instruction.new('G', g) if @gs.stroking_color != [ g ]
|
357
|
+
PDF::Instruction.new('G', g) if @canvas.gs.stroking_color != [ g ]
|
347
358
|
|
348
359
|
else
|
349
360
|
raise TypeError, "Invalid color : #{color}"
|
350
361
|
end
|
351
362
|
)
|
352
363
|
|
353
|
-
i.
|
364
|
+
i.render(@canvas) if i
|
354
365
|
self
|
355
366
|
end
|
356
367
|
|
357
368
|
def set_dash_pattern(pattern)
|
358
369
|
load! if @instructions.nil?
|
359
|
-
unless @gs.dash_pattern.eql? pattern
|
360
|
-
@instructions << PDF::Instruction.new('d', pattern.array, pattern.phase).
|
370
|
+
unless @canvas.gs.dash_pattern.eql? pattern
|
371
|
+
@instructions << PDF::Instruction.new('d', pattern.array, pattern.phase).render(@canvas)
|
361
372
|
end
|
362
373
|
|
363
374
|
self
|
@@ -365,8 +376,8 @@ module Origami
|
|
365
376
|
|
366
377
|
def set_line_width(width)
|
367
378
|
load! if @instructions.nil?
|
368
|
-
if @gs.line_width != width
|
369
|
-
@instructions << PDF::Instruction.new('w', width).
|
379
|
+
if @canvas.gs.line_width != width
|
380
|
+
@instructions << PDF::Instruction.new('w', width).render(@canvas)
|
370
381
|
end
|
371
382
|
|
372
383
|
self
|
@@ -374,8 +385,8 @@ module Origami
|
|
374
385
|
|
375
386
|
def set_line_cap(cap)
|
376
387
|
load! if @instructions.nil?
|
377
|
-
if @gs.line_cap != cap
|
378
|
-
@instructions << PDF::Instruction.new('J', cap).
|
388
|
+
if @canvas.gs.line_cap != cap
|
389
|
+
@instructions << PDF::Instruction.new('J', cap).render(@canvas)
|
379
390
|
end
|
380
391
|
|
381
392
|
self
|
@@ -383,8 +394,8 @@ module Origami
|
|
383
394
|
|
384
395
|
def set_line_join(join)
|
385
396
|
load! if @instructions.nil?
|
386
|
-
if @gs.line_join != join
|
387
|
-
@instructions << PDF::Instruction.new('j', join).
|
397
|
+
if @canvas.gs.line_join != join
|
398
|
+
@instructions << PDF::Instruction.new('j', join).render(@canvas)
|
388
399
|
end
|
389
400
|
|
390
401
|
self
|
@@ -397,7 +408,11 @@ module Origami
|
|
397
408
|
|
398
409
|
code = StringScanner.new self.data
|
399
410
|
@instructions = []
|
400
|
-
|
411
|
+
|
412
|
+
until code.eos?
|
413
|
+
insn = PDF::Instruction.parse(code)
|
414
|
+
@instructions << insn if insn
|
415
|
+
end
|
401
416
|
|
402
417
|
self
|
403
418
|
end
|
@@ -406,9 +421,9 @@ module Origami
|
|
406
421
|
|
407
422
|
lines = text.split("\n").map!{|line| line.to_s}
|
408
423
|
|
409
|
-
@instructions << PDF::Instruction.new('Tj', lines.slice!(0)).
|
424
|
+
@instructions << PDF::Instruction.new('Tj', lines.slice!(0)).render(@canvas)
|
410
425
|
lines.each do |line|
|
411
|
-
@instructions << PDF::Instruction.new("'", line).
|
426
|
+
@instructions << PDF::Instruction.new("'", line).render(@canvas)
|
412
427
|
end
|
413
428
|
|
414
429
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
javascript.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
|
+
begin
|
30
|
+
require 'johnson'
|
31
|
+
|
32
|
+
class JavaScriptEngine < Johnson::SpiderMonkey::Runtime
|
33
|
+
|
34
|
+
class DocumentObject
|
35
|
+
attr_reader :author, :creator, :creationDate, :keywords, :modDate, :producer, :subject, :title
|
36
|
+
|
37
|
+
def initialize(pdf)
|
38
|
+
@pdf = pdf
|
39
|
+
|
40
|
+
@author = @pdf.author || ''
|
41
|
+
@creator = @pdf.creator || ''
|
42
|
+
@keywords = @pdf.keywords || ''
|
43
|
+
@producer = @pdf.producer || ''
|
44
|
+
@subject = @pdf.subject || ''
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
"[object Doc]"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ApplicationObject
|
53
|
+
DEFAULT_VIEWER_VERSION = 9
|
54
|
+
|
55
|
+
attr_reader :viewerVersion
|
56
|
+
attr_reader :viewerVariation
|
57
|
+
|
58
|
+
def initialize
|
59
|
+
@viewerVersion = DEFAULT_VIEWER_VERSION
|
60
|
+
@viewerVariation = @viewerType = "Reader"
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"[object App]"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class ConsoleObject
|
69
|
+
def println(msg)
|
70
|
+
puts msg.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def show; end
|
74
|
+
def clear; end
|
75
|
+
def hide; end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
"[object Console]"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class UtilObject
|
83
|
+
def to_s
|
84
|
+
"[object Util]"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize(pdf, options = {})
|
89
|
+
super()
|
90
|
+
|
91
|
+
self['app'] = ApplicationObject.new
|
92
|
+
if options.has_key?(:viewerVersion)
|
93
|
+
self['app'].instance_variable_set :@viewerVersion, options[:viewerVersion]
|
94
|
+
end
|
95
|
+
|
96
|
+
self['console'] = ConsoleObject.new
|
97
|
+
self['util'] = UtilObject.new
|
98
|
+
|
99
|
+
# Johnson includes the Ruby namespace in the global scope.
|
100
|
+
# Unsets that for obvious security reasons.
|
101
|
+
self['Ruby'] = nil
|
102
|
+
|
103
|
+
# Hack the 'this' object to point to the DocumentObject
|
104
|
+
@doc_obj = self['doc'] = DocumentObject.new(pdf)
|
105
|
+
evaluate('this.doc.eval = function(script) {eval(script)}')
|
106
|
+
evaluate('this.doc = undefined')
|
107
|
+
end
|
108
|
+
|
109
|
+
def exec(script)
|
110
|
+
@doc_obj.eval(script)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
rescue LoadError
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if defined?(PDF::JavaScriptEngine)
|
120
|
+
module String
|
121
|
+
def eval_as_js(options = {})
|
122
|
+
runtime = options[:runtime] || PDF::JavaScriptEngine.new(self.pdf, options)
|
123
|
+
runtime.exec(self.value)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Stream
|
128
|
+
def eval_as_js(options = {})
|
129
|
+
runtime = options[:runtime] || PDF::JavaScriptEngine.new(self.pdf, options)
|
130
|
+
runtime.exec(self.data)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
data/origami/metadata.rb
CHANGED
@@ -50,6 +50,15 @@ module Origami
|
|
50
50
|
get_doc_attr :Info
|
51
51
|
end
|
52
52
|
|
53
|
+
def title; get_document_info_field(:Title) end
|
54
|
+
def author; get_document_info_field(:Author) end
|
55
|
+
def subject; get_document_info_field(:Subject) end
|
56
|
+
def keywords; get_document_info_field(:Keywords) end
|
57
|
+
def creator; get_document_info_field(:Creator) end
|
58
|
+
def producer; get_document_info_field(:Producer) end
|
59
|
+
def creation_date; get_document_info_field(:CreationDate) end
|
60
|
+
def mod_date; get_document_info_field(:ModDate) end
|
61
|
+
|
53
62
|
#
|
54
63
|
# Returns a Hash of the information found in the metadata stream
|
55
64
|
#
|
@@ -81,6 +90,21 @@ module Origami
|
|
81
90
|
end
|
82
91
|
end
|
83
92
|
|
93
|
+
private
|
94
|
+
|
95
|
+
def get_document_info_field(field) #:nodoc:
|
96
|
+
if has_document_info?
|
97
|
+
doc_info = get_document_info
|
98
|
+
|
99
|
+
if doc_info.has_key?(field)
|
100
|
+
case obj = get_document_info[field].solve
|
101
|
+
when String then return obj.value
|
102
|
+
when Stream then return obj.data
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
84
108
|
end
|
85
109
|
|
86
110
|
#
|