em_hessian2 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 +7 -0
- data/.gitignore +8 -0
- data/Gemfile +4 -0
- data/README.md +186 -0
- data/Rakefile +1 -0
- data/hessian2.gemspec +28 -0
- data/lib/hessian2.rb +14 -0
- data/lib/hessian2/class_wrapper.rb +8 -0
- data/lib/hessian2/client.rb +73 -0
- data/lib/hessian2/constants.rb +164 -0
- data/lib/hessian2/fault.rb +3 -0
- data/lib/hessian2/handler.rb +11 -0
- data/lib/hessian2/hessian_client.rb +3 -0
- data/lib/hessian2/parser.rb +555 -0
- data/lib/hessian2/struct_wrapper.rb +8 -0
- data/lib/hessian2/type_wrapper.rb +24 -0
- data/lib/hessian2/version.rb +3 -0
- data/lib/hessian2/writer.rb +543 -0
- data/test/Lighthouse.jpg +0 -0
- data/test/another_monkey.rb +7 -0
- data/test/app.rb +23 -0
- data/test/config.ru +2 -0
- data/test/create_monkeys.rb +4 -0
- data/test/defs.pb.rb +25 -0
- data/test/defs.proto +7 -0
- data/test/establish_connection.rb +7 -0
- data/test/get.rb +275 -0
- data/test/monkey.rb +5 -0
- data/test/monkey_service.rb +769 -0
- data/test/seeds.rb +14 -0
- data/test/set.rb +195 -0
- data/test/src/HessianTest.java +20 -0
- data/test/src/example/IMonkeyService.java +283 -0
- data/test/src/example/Monkey.java +31 -0
- data/test/src/example/MonkeyService.java +1125 -0
- data/test/test_class_wrapper.rb +75 -0
- data/test/test_exception.rb +21 -0
- data/test/test_struct_wrapper.rb +93 -0
- data/test/test_type_wrapper.rb +75 -0
- data/test/test_wait_taka.rb +8 -0
- data/test/vs_object_array2struct.rb +50 -0
- data/test/vs_redis_memcached_mysql2.rb +182 -0
- metadata +152 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module Hessian2
|
2
|
+
class TypeWrapper
|
3
|
+
attr_accessor :hessian_type, :object
|
4
|
+
def initialize(hessian_type, object)
|
5
|
+
@hessian_type = hessian_type.is_a?(Array) ? ('[' + unify_type(hessian_type.first)) : unify_type(hessian_type)
|
6
|
+
@object = object
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def unify_type(hessian_type)
|
12
|
+
case hessian_type
|
13
|
+
when 'L', 'l', 'Long', 'long', :long
|
14
|
+
'L'
|
15
|
+
when 'I', 'i', 'Integer', 'int', :int
|
16
|
+
'I'
|
17
|
+
when 'B', 'b', 'Binary', 'bin', :bin
|
18
|
+
'B'
|
19
|
+
else
|
20
|
+
hessian_type
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,543 @@
|
|
1
|
+
require 'hessian2/constants'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
module Hessian2
|
5
|
+
module Writer
|
6
|
+
include Constants
|
7
|
+
|
8
|
+
def call(method, args)
|
9
|
+
refs, crefs, trefs = {}, {}, {}
|
10
|
+
out = [ 'H', '2', '0', 'C' ].pack('ahha')
|
11
|
+
out << write_string(method)
|
12
|
+
out << write_int(args.size)
|
13
|
+
args.each { |arg| out << write(arg, refs, crefs, trefs) }
|
14
|
+
|
15
|
+
out
|
16
|
+
end
|
17
|
+
|
18
|
+
def reply(val)
|
19
|
+
[ 'H', '2', '0', 'R' ].pack('ahha') << write(val)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write_fault(e)
|
23
|
+
val = {
|
24
|
+
code: e.class.to_s,
|
25
|
+
message: e.message,
|
26
|
+
detail: e.backtrace }
|
27
|
+
[ 'F' ].pack('a') << write_hash(val)
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(val, refs = {}, crefs = {}, trefs = {})
|
31
|
+
case val
|
32
|
+
when StructWrapper # ([)object to ([)values-array
|
33
|
+
obj = val.object
|
34
|
+
return write_nil if obj.nil?
|
35
|
+
|
36
|
+
idx = refs[val.object_id]
|
37
|
+
return write_ref(idx) if idx
|
38
|
+
|
39
|
+
refs[val.object_id] = refs.size
|
40
|
+
|
41
|
+
klass = val.klass
|
42
|
+
|
43
|
+
if klass.is_a? Array
|
44
|
+
fields = klass.first.members
|
45
|
+
arr = []
|
46
|
+
|
47
|
+
obj.each do |o|
|
48
|
+
ovals = []
|
49
|
+
if o.is_a? Hash
|
50
|
+
fields.each do |f|
|
51
|
+
ovals << (o[f] || o[f.to_s])
|
52
|
+
end
|
53
|
+
elsif o.instance_variable_get(:@attributes).is_a? Hash
|
54
|
+
attrs = o.attributes
|
55
|
+
fields.each do |f|
|
56
|
+
ovals << attrs[f.to_s]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
fields.each do |f|
|
60
|
+
ovals << o.instance_variable_get(f.to_s.prepend('@'))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
arr << ovals
|
64
|
+
end
|
65
|
+
|
66
|
+
write_array(arr, refs, crefs, trefs)
|
67
|
+
else
|
68
|
+
objvals = []
|
69
|
+
if obj.is_a? Hash
|
70
|
+
klass.members.each do |f|
|
71
|
+
objvals << (obj[f] || obj[f.to_s])
|
72
|
+
end
|
73
|
+
elsif obj.instance_variable_get(:@attributes).is_a? Hash
|
74
|
+
attrs = obj.attributes
|
75
|
+
klass.members.each do |f|
|
76
|
+
objvals << attrs[f.to_s]
|
77
|
+
end
|
78
|
+
else
|
79
|
+
klass.members.each do |f|
|
80
|
+
objvals << obj.instance_variable_get(f.to_s.prepend('@'))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
write_array(objvals, refs, crefs, trefs)
|
85
|
+
end
|
86
|
+
when ClassWrapper # class definition for statically typed languages
|
87
|
+
obj = val.object
|
88
|
+
return write_nil if obj.nil?
|
89
|
+
|
90
|
+
idx = refs[val.object_id]
|
91
|
+
return write_ref(idx) if idx
|
92
|
+
|
93
|
+
refs[val.object_id] = refs.size
|
94
|
+
|
95
|
+
if val.hessian_class[0] == '['
|
96
|
+
type = val.hessian_class
|
97
|
+
if trefs.include?(type)
|
98
|
+
tstr = write_int(trefs[type])
|
99
|
+
else
|
100
|
+
trefs[type] = trefs.size # store a type
|
101
|
+
tstr = write_string(type)
|
102
|
+
end
|
103
|
+
return [ BC_LIST_DIRECT ].pack('C') << tstr if obj.size == 0
|
104
|
+
end
|
105
|
+
|
106
|
+
klass = val.hessian_class.delete('[]')
|
107
|
+
cref = crefs[klass]
|
108
|
+
if cref
|
109
|
+
cidx = cref.first
|
110
|
+
fields = cref.last
|
111
|
+
str = ''
|
112
|
+
else
|
113
|
+
fstr = ''
|
114
|
+
if obj.is_a? Array
|
115
|
+
sample = obj.first
|
116
|
+
if sample.is_a? Hash
|
117
|
+
fields = sample.keys
|
118
|
+
fields.each do |f|
|
119
|
+
fstr << write_string(f.to_s)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
fields = sample.instance_variables
|
123
|
+
fields.each do |f|
|
124
|
+
fstr << write_string(f.to_s[1..-1]) # skip '@'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
elsif obj.is_a? Hash
|
128
|
+
fields = obj.keys
|
129
|
+
fields.each do |f|
|
130
|
+
fstr << write_string(f.to_s)
|
131
|
+
end
|
132
|
+
else
|
133
|
+
fields = obj.instance_variables
|
134
|
+
fields.each do |f|
|
135
|
+
fstr << write_string(f.to_s[1..-1])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
str = [ BC_OBJECT_DEF ].pack('C') << write_string(klass) << write_int(fields.size) << fstr
|
140
|
+
cidx = crefs.size
|
141
|
+
crefs[klass] = [cidx, fields] # store a class definition
|
142
|
+
end
|
143
|
+
|
144
|
+
if cidx <= OBJECT_DIRECT_MAX
|
145
|
+
cstr = [ BC_OBJECT_DIRECT + cidx ].pack('C')
|
146
|
+
else
|
147
|
+
cstr = [ BC_OBJECT ].pack('C') << write_int(cidx)
|
148
|
+
end
|
149
|
+
|
150
|
+
if obj.is_a? Array
|
151
|
+
str << write_class_wrapped_array(obj, tstr, cstr, fields, refs, crefs, trefs)
|
152
|
+
elsif obj.is_a? Hash
|
153
|
+
str << write_class_wrapped_hash(obj, cstr, fields, refs, crefs, trefs)
|
154
|
+
else
|
155
|
+
str << write_class_wrapped_object(obj, cstr, fields, refs, crefs, trefs)
|
156
|
+
end
|
157
|
+
|
158
|
+
str
|
159
|
+
when TypeWrapper
|
160
|
+
obj = val.object
|
161
|
+
return write_nil if obj.nil?
|
162
|
+
|
163
|
+
idx = refs[val.object_id]
|
164
|
+
return write_ref(idx) if idx
|
165
|
+
|
166
|
+
refs[val.object_id] = refs.size
|
167
|
+
|
168
|
+
type = val.hessian_type
|
169
|
+
if trefs.include?(type)
|
170
|
+
tstr = write_int(trefs[type])
|
171
|
+
else
|
172
|
+
trefs[type] = trefs.size
|
173
|
+
tstr = write_string(type)
|
174
|
+
end
|
175
|
+
|
176
|
+
if type[0] == '['
|
177
|
+
write_type_wrapped_array(obj, tstr, type, refs, crefs, trefs)
|
178
|
+
else
|
179
|
+
case type
|
180
|
+
when 'L'
|
181
|
+
write_long(Integer(obj))
|
182
|
+
when 'I'
|
183
|
+
write_int(Integer(obj))
|
184
|
+
when 'B'
|
185
|
+
write_binary(obj)
|
186
|
+
else
|
187
|
+
if obj.is_a? Hash
|
188
|
+
write_type_wrapped_hash(obj, tstr, refs, crefs, trefs)
|
189
|
+
else
|
190
|
+
write(obj, refs, crefs, trefs)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
when TrueClass
|
195
|
+
[ BC_TRUE ].pack('C')
|
196
|
+
when FalseClass
|
197
|
+
[ BC_FALSE ].pack('C')
|
198
|
+
when Time
|
199
|
+
if val.usec == 0 && val.sec == 0 # date in minutes
|
200
|
+
[ BC_DATE_MINUTE, val.to_i / 60 ].pack('CL>')
|
201
|
+
else
|
202
|
+
[ BC_DATE, val.to_i * 1000 + val.usec / 1000 ].pack('CQ>') # date
|
203
|
+
end
|
204
|
+
when Float, BigDecimal
|
205
|
+
case val.infinite?
|
206
|
+
when 1
|
207
|
+
return [ BC_DOUBLE, Float::INFINITY ].pack('CG')
|
208
|
+
when -1
|
209
|
+
return [ BC_DOUBLE, -Float::INFINITY ].pack('CG')
|
210
|
+
else
|
211
|
+
return [ BC_DOUBLE, Float::NAN ].pack('CG') if val.nan?
|
212
|
+
return [ BC_DOUBLE_ZERO ].pack('C') if val.zero? # double zero
|
213
|
+
return [ BC_DOUBLE_ONE ].pack('C') if val == 1 # double one
|
214
|
+
|
215
|
+
ival = val.to_i
|
216
|
+
if ival == val
|
217
|
+
return [ BC_DOUBLE_BYTE, ival ].pack('Cc') if ival >= -0x80 && ival <= 0x7f # double octet
|
218
|
+
return [ BC_DOUBLE_SHORT, (ival >> 8), ival ].pack('Ccc') if ival >= -0x8000 && ival <= 0x7fff # double short
|
219
|
+
end
|
220
|
+
|
221
|
+
mval = val * 1000
|
222
|
+
if mval.finite?
|
223
|
+
mills = mval.to_i
|
224
|
+
if mills >= -0x80_000_000 && mills <= 0x7f_fff_fff && 0.001 * mills == val
|
225
|
+
return [ BC_DOUBLE_MILL, mills ].pack('Cl>') # double mill
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
[ BC_DOUBLE, val ].pack('CG') # double
|
230
|
+
end
|
231
|
+
when Fixnum
|
232
|
+
write_int(val)
|
233
|
+
when Array
|
234
|
+
write_array(val, refs, crefs, trefs)
|
235
|
+
when Bignum
|
236
|
+
if val >= -0x80_000_000 && val <= 0x7f_fff_fff # four octet longs
|
237
|
+
[ BC_LONG_INT, val ].pack('Cl>')
|
238
|
+
else # long
|
239
|
+
[ BC_LONG, val ].pack('Cq>')
|
240
|
+
end
|
241
|
+
when Hash
|
242
|
+
write_hash(val, refs, crefs, trefs)
|
243
|
+
when NilClass
|
244
|
+
write_nil
|
245
|
+
when String
|
246
|
+
write_string(val)
|
247
|
+
when Symbol
|
248
|
+
write_string(val.to_s)
|
249
|
+
else
|
250
|
+
write_object(val, refs, crefs, trefs)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def print_string(str)
|
255
|
+
return str.b if String.method_defined?(:b)
|
256
|
+
|
257
|
+
arr, i = Array.new(str.bytesize), 0
|
258
|
+
str.unpack('U*').each do |c|
|
259
|
+
if c < 0x80 # 0xxxxxxx
|
260
|
+
arr[i] = c
|
261
|
+
elsif c < 0x800 # 110xxxxx 10xxxxxx
|
262
|
+
arr[i] = 0xc0 + ((c >> 6) & 0x1f)
|
263
|
+
arr[i += 1] = 0x80 + (c & 0x3f)
|
264
|
+
else # 1110xxxx 10xxxxxx 10xxxxxx
|
265
|
+
arr[i] = 0xe0 + ((c >> 12) & 0xf)
|
266
|
+
arr[i += 1] = 0x80 + ((c >> 6) & 0x3f)
|
267
|
+
arr[i += 1] = 0x80 + (c & 0x3f)
|
268
|
+
end
|
269
|
+
i += 1
|
270
|
+
end
|
271
|
+
|
272
|
+
arr.pack('C*')
|
273
|
+
end
|
274
|
+
|
275
|
+
def write_array(arr, refs = {}, crefs = {}, trefs = {})
|
276
|
+
idx = refs[arr.object_id]
|
277
|
+
return write_ref(idx) if idx
|
278
|
+
|
279
|
+
refs[arr.object_id] = refs.size
|
280
|
+
len = arr.size
|
281
|
+
if len <= LIST_DIRECT_MAX # [x78-7f] value*
|
282
|
+
str = [ BC_LIST_DIRECT_UNTYPED + len ].pack('C')
|
283
|
+
else # x58 int value*
|
284
|
+
str = [ BC_LIST_FIXED_UNTYPED ].pack('C') << write_int(len)
|
285
|
+
end
|
286
|
+
|
287
|
+
arr.each do |ele|
|
288
|
+
str << write(ele, refs, crefs, trefs)
|
289
|
+
end
|
290
|
+
|
291
|
+
str
|
292
|
+
end
|
293
|
+
|
294
|
+
def write_binary(str)
|
295
|
+
chunks, i, len = [], 0, str.size
|
296
|
+
while len > 0x8000
|
297
|
+
chunks << [ BC_BINARY_CHUNK, 0x8000 ].pack('Cn') << str[i...(i += 0x8000)]
|
298
|
+
len -= 0x8000
|
299
|
+
end
|
300
|
+
|
301
|
+
final = str[i..-1]
|
302
|
+
if len <= BINARY_DIRECT_MAX
|
303
|
+
chunks << [ BC_BINARY_DIRECT + len ].pack('C') << final
|
304
|
+
elsif len <= BINARY_SHORT_MAX
|
305
|
+
chunks << [ BC_BINARY_SHORT + (len >> 8), len ].pack('CC') << final
|
306
|
+
else
|
307
|
+
chunks << [ BC_BINARY, len ].pack('Cn') << final
|
308
|
+
end
|
309
|
+
|
310
|
+
chunks.join
|
311
|
+
end
|
312
|
+
|
313
|
+
def write_class_wrapped_array(arr, tstr, cstr, fields, refs = {}, crefs = {}, trefs = {})
|
314
|
+
len = arr.size
|
315
|
+
if len <= LIST_DIRECT_MAX # [x70-77] type value*
|
316
|
+
str = [ BC_LIST_DIRECT + len ].pack('C') << tstr
|
317
|
+
else # 'V' type int value*
|
318
|
+
str = [ BC_LIST_FIXED ].pack('C') << tstr << write_int(len)
|
319
|
+
end
|
320
|
+
|
321
|
+
if arr.first.is_a? Hash
|
322
|
+
arr.each do |ele|
|
323
|
+
idx = refs[ele.object_id]
|
324
|
+
if idx
|
325
|
+
str << write_ref(idx)
|
326
|
+
else
|
327
|
+
refs[ele.object_id] = refs.size
|
328
|
+
str << cstr
|
329
|
+
fields.each do |f|
|
330
|
+
str << write(ele[f], refs, crefs, trefs)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
else
|
335
|
+
arr.each do |ele|
|
336
|
+
idx = refs[ele.object_id]
|
337
|
+
if idx
|
338
|
+
str << write_ref(idx)
|
339
|
+
else
|
340
|
+
refs[ele.object_id] = refs.size
|
341
|
+
str << cstr
|
342
|
+
fields.each do |f|
|
343
|
+
str << write(ele.instance_variable_get(f), refs, crefs, trefs)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
str
|
350
|
+
end
|
351
|
+
|
352
|
+
def write_class_wrapped_hash(hash, cstr, fields, refs = {}, crefs = {}, trefs = {})
|
353
|
+
str = cstr
|
354
|
+
fields.each do |f|
|
355
|
+
str << write(hash[f], refs, crefs, trefs)
|
356
|
+
end
|
357
|
+
|
358
|
+
str
|
359
|
+
end
|
360
|
+
|
361
|
+
def write_class_wrapped_object(obj, cstr, fields, refs = {}, crefs = {}, trefs = {})
|
362
|
+
str = cstr
|
363
|
+
fields.each do |f|
|
364
|
+
str << write(obj.instance_variable_get(f), refs, crefs, trefs)
|
365
|
+
end
|
366
|
+
|
367
|
+
str
|
368
|
+
end
|
369
|
+
|
370
|
+
def write_hash(hash, refs = {}, crefs = {}, trefs = {})
|
371
|
+
idx = refs[hash.object_id]
|
372
|
+
return write_ref(idx) if idx
|
373
|
+
|
374
|
+
refs[hash.object_id] = refs.size
|
375
|
+
str = [ BC_MAP_UNTYPED ].pack('C')
|
376
|
+
hash.each do |k, v|
|
377
|
+
str << write(k, refs, crefs, trefs)
|
378
|
+
str << write(v, refs, crefs, trefs)
|
379
|
+
end
|
380
|
+
|
381
|
+
str << [ BC_END ].pack('C')
|
382
|
+
end
|
383
|
+
|
384
|
+
def write_int(val)
|
385
|
+
if val >= INT_DIRECT_MIN && val <= INT_DIRECT_MAX # single octet integers
|
386
|
+
[ BC_INT_ZERO + val ].pack('c')
|
387
|
+
elsif val >= INT_BYTE_MIN && val <= INT_BYTE_MAX # two octet integers
|
388
|
+
[ BC_INT_BYTE_ZERO + (val >> 8), val ].pack('cc')
|
389
|
+
elsif val >= INT_SHORT_MIN && val <= INT_SHORT_MAX # three octet integers
|
390
|
+
[ BC_INT_SHORT_ZERO + (val >> 16), (val >> 8), val].pack('ccc')
|
391
|
+
elsif val >= -0x80_000_000 && val <= 0x7f_fff_fff # integer
|
392
|
+
[ BC_INT, val ].pack('Cl>')
|
393
|
+
else
|
394
|
+
[ BC_LONG, val ].pack('Cq>')
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def write_long(val)
|
399
|
+
if val >= LONG_DIRECT_MIN && val <= LONG_DIRECT_MAX # single octet longs
|
400
|
+
[ BC_LONG_ZERO + val ].pack('c')
|
401
|
+
elsif val >= LONG_BYTE_MIN && val <= LONG_BYTE_MAX # two octet longs
|
402
|
+
[ BC_LONG_BYTE_ZERO + (val >> 8), val ].pack('cc')
|
403
|
+
elsif val >= LONG_SHORT_MIN && val <= LONG_SHORT_MAX # three octet longs
|
404
|
+
[ BC_LONG_SHORT_ZERO + (val >> 16), (val >> 8), val ].pack('ccc')
|
405
|
+
elsif val >= -0x80_000_000 && val <= 0x7f_fff_fff # four octet longs
|
406
|
+
[ BC_LONG_INT, val ].pack('Cl>')
|
407
|
+
else
|
408
|
+
[ BC_LONG, val ].pack('Cq>')
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def write_nil
|
413
|
+
[ BC_NULL ].pack('C')
|
414
|
+
end
|
415
|
+
|
416
|
+
def write_object(obj, refs = {}, crefs = {}, trefs = {})
|
417
|
+
idx = refs[obj.object_id]
|
418
|
+
return write_ref(idx) if idx
|
419
|
+
|
420
|
+
attrs = obj.attributes
|
421
|
+
|
422
|
+
refs[obj.object_id] = refs.size
|
423
|
+
klass = obj.class.to_s
|
424
|
+
cref = crefs[klass]
|
425
|
+
if cref
|
426
|
+
cidx = cref.first
|
427
|
+
fields = cref.last
|
428
|
+
str = ''
|
429
|
+
else
|
430
|
+
fields = attrs.is_a?(Hash) ? attrs.keys : obj.instance_variables.map{|sym| sym.to_s[1..-1]}
|
431
|
+
str = [ BC_OBJECT_DEF ].pack('C') << write_string(klass) << write_int(fields.size)
|
432
|
+
fields.each do |f|
|
433
|
+
str << write_string(f)
|
434
|
+
end
|
435
|
+
|
436
|
+
cidx = crefs.size
|
437
|
+
crefs[klass] = [cidx, fields]
|
438
|
+
end
|
439
|
+
|
440
|
+
if cidx <= OBJECT_DIRECT_MAX
|
441
|
+
str << [ BC_OBJECT_DIRECT + cidx ].pack('C')
|
442
|
+
else
|
443
|
+
str << [ BC_OBJECT ].pack('C') << write_int(cidx)
|
444
|
+
end
|
445
|
+
|
446
|
+
if attrs.is_a? Hash
|
447
|
+
fields.each do |f|
|
448
|
+
str << write(attrs[f], refs, crefs, trefs)
|
449
|
+
end
|
450
|
+
else
|
451
|
+
fields.each do |f|
|
452
|
+
str << write(obj.instance_variable_get(f.prepend('@')), refs, crefs, trefs)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
str
|
457
|
+
end
|
458
|
+
|
459
|
+
def write_ref(val)
|
460
|
+
[ BC_REF ].pack('C') << write_int(val)
|
461
|
+
end
|
462
|
+
|
463
|
+
def write_string(str)
|
464
|
+
chunks, i, len = '', 0, str.size
|
465
|
+
while len > 0x8000
|
466
|
+
chunks << [ BC_STRING_CHUNK, 0x8000 ].pack('Cn') << print_string(str[i, i += 0x8000])
|
467
|
+
len -= 0x8000
|
468
|
+
end
|
469
|
+
|
470
|
+
final = str[i..-1]
|
471
|
+
chunks << if len <= STRING_DIRECT_MAX
|
472
|
+
[ BC_STRING_DIRECT + len ].pack('C')
|
473
|
+
elsif len <= STRING_SHORT_MAX
|
474
|
+
[ BC_STRING_SHORT + (len >> 8), len ].pack('CC')
|
475
|
+
else
|
476
|
+
[ BC_STRING, len ].pack('Cn')
|
477
|
+
end
|
478
|
+
|
479
|
+
chunks << print_string(final)
|
480
|
+
end
|
481
|
+
|
482
|
+
def write_type_wrapped_array(arr, tstr, eletype, refs = {}, crefs = {}, trefs = {})
|
483
|
+
len = arr.size
|
484
|
+
return [ BC_LIST_DIRECT ].pack('C') << tstr if len == 0
|
485
|
+
|
486
|
+
if len <= LIST_DIRECT_MAX # [x70-77] type value*
|
487
|
+
str = [ BC_LIST_DIRECT + len ].pack('C') << tstr
|
488
|
+
else # 'V' type int value*
|
489
|
+
str = [ BC_LIST_FIXED ].pack('C') << tstr << write_int(len)
|
490
|
+
end
|
491
|
+
|
492
|
+
case eletype
|
493
|
+
when 'L'
|
494
|
+
arr.each do |ele|
|
495
|
+
str << write_long(Integer(ele))
|
496
|
+
end
|
497
|
+
when 'I'
|
498
|
+
arr.each do |ele|
|
499
|
+
str << write_int(Integer(ele))
|
500
|
+
end
|
501
|
+
when 'B'
|
502
|
+
arr.each do |ele|
|
503
|
+
str << write_binary(ele)
|
504
|
+
end
|
505
|
+
else
|
506
|
+
if arr.first.is_a? Hash
|
507
|
+
arr.each do |ele|
|
508
|
+
idx = refs[ele.object_id]
|
509
|
+
if idx
|
510
|
+
str << write_ref(idx)
|
511
|
+
else
|
512
|
+
refs[ele.object_id] = refs.size
|
513
|
+
str << write_type_wrapped_hash(ele, tstr, refs, crefs, trefs)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
else
|
517
|
+
arr.each do |ele|
|
518
|
+
idx = refs[ele.object_id]
|
519
|
+
if idx
|
520
|
+
str << write_ref(idx)
|
521
|
+
else
|
522
|
+
refs[ele.object_id] = refs.size
|
523
|
+
str << write(ele, refs, crefs, trefs)
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
str
|
530
|
+
end
|
531
|
+
|
532
|
+
def write_type_wrapped_hash(hash, tstr, refs = {}, crefs = {}, trefs = {})
|
533
|
+
str = [ BC_MAP ].pack('C') << tstr
|
534
|
+
hash.each do |k, v|
|
535
|
+
str << write(k, refs, crefs, trefs)
|
536
|
+
str << write(v, refs, crefs, trefs)
|
537
|
+
end
|
538
|
+
|
539
|
+
str << [ BC_END ].pack('C')
|
540
|
+
end
|
541
|
+
|
542
|
+
end
|
543
|
+
end
|