erlang_rb 1.3.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.
- data/README.markdown +7 -0
- data/lib/erlang.rb +649 -0
- data.tar.gz.sig +0 -0
- metadata +89 -0
- metadata.gz.sig +4 -0
data/README.markdown
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Erlang Binary Term Format for Ruby
|
2
|
+
==================================
|
3
|
+
|
4
|
+
Provides all encoding and decoding for the Erlang Binary Term Format
|
5
|
+
(as defined at [http://erlang.org/doc/apps/erts/erl_ext_dist.html](http://erlang.org/doc/apps/erts/erl_ext_dist.html))
|
6
|
+
in a single Ruby module.
|
7
|
+
|
data/lib/erlang.rb
ADDED
@@ -0,0 +1,649 @@
|
|
1
|
+
#-*-Mode:ruby;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*-
|
2
|
+
# ex: set ft=ruby fenc=utf-8 sts=4 ts=4 sw=4 et:
|
3
|
+
#
|
4
|
+
# BSD LICENSE
|
5
|
+
#
|
6
|
+
# Copyright (c) 2011-2014, Michael Truog <mjtruog at gmail dot com>
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in
|
16
|
+
# the documentation and/or other materials provided with the
|
17
|
+
# distribution.
|
18
|
+
# * All advertising materials mentioning features or use of this
|
19
|
+
# software must display the following acknowledgment
|
20
|
+
# This product includes software developed by Michael Truog
|
21
|
+
# * The name of the author may not be used to endorse or promote
|
22
|
+
# products derived from this software without specific prior
|
23
|
+
# written permission
|
24
|
+
#
|
25
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
26
|
+
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
27
|
+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
28
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
29
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
30
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
31
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
32
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
33
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
34
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
35
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
36
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
37
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
38
|
+
# DAMAGE.
|
39
|
+
#
|
40
|
+
|
41
|
+
module Erlang
|
42
|
+
|
43
|
+
class OtpErlangList
|
44
|
+
def initialize(value)
|
45
|
+
@value = value
|
46
|
+
end
|
47
|
+
def to_s
|
48
|
+
arity = @value.length
|
49
|
+
if arity == 0
|
50
|
+
return TAG_NIL_EXT.chr
|
51
|
+
else
|
52
|
+
arity_packed = [arity].pack('N')
|
53
|
+
list_packed = @value.map{ |element|
|
54
|
+
term_to_binary_(element)
|
55
|
+
}.join
|
56
|
+
return "#{TAG_LIST_EXT.chr}#{arity_packed}#{list_packed}#{TAG_NIL_EXT.chr}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def hash
|
60
|
+
return to_s.hash
|
61
|
+
end
|
62
|
+
def ==(other)
|
63
|
+
return to_s == other.to_s
|
64
|
+
end
|
65
|
+
alias eql? ==
|
66
|
+
end
|
67
|
+
|
68
|
+
class OtpErlangAtom
|
69
|
+
def initialize(value)
|
70
|
+
@value = value
|
71
|
+
end
|
72
|
+
def to_s
|
73
|
+
if @value.kind_of?(Integer)
|
74
|
+
return "#{TAG_ATOM_CACHE_REF.chr}#{@value.chr}"
|
75
|
+
elsif @value.kind_of?(String)
|
76
|
+
size = @value.bytesize
|
77
|
+
if @value.encoding.name == 'UTF-8'
|
78
|
+
if size < 256
|
79
|
+
return "#{TAG_SMALL_ATOM_UTF8_EXT.chr}#{size.chr}#{@value}"
|
80
|
+
else
|
81
|
+
size_packed = [size].pack('n')
|
82
|
+
return "#{TAG_ATOM_UTF8_EXT.chr}#{size_packed}#{@value}"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
if size < 256
|
86
|
+
return "#{TAG_SMALL_ATOM_EXT.chr}#{size.chr}#{@value}"
|
87
|
+
else
|
88
|
+
size_packed = [size].pack('n')
|
89
|
+
return "#{TAG_ATOM_EXT.chr}#{size_packed}#{@value}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
raise OutputException, 'unknown atom type', caller
|
94
|
+
end
|
95
|
+
end
|
96
|
+
def hash
|
97
|
+
return to_s.hash
|
98
|
+
end
|
99
|
+
def ==(other)
|
100
|
+
return to_s == other.to_s
|
101
|
+
end
|
102
|
+
alias eql? ==
|
103
|
+
end
|
104
|
+
|
105
|
+
class OtpErlangBinary
|
106
|
+
def initialize(value, bits = 8)
|
107
|
+
@value = value
|
108
|
+
@bits = bits # bits in last byte
|
109
|
+
end
|
110
|
+
def to_s
|
111
|
+
size = @value.bytesize
|
112
|
+
size_packed = [size].pack('N')
|
113
|
+
if @bits != 8
|
114
|
+
return "#{TAG_BIT_BINARY_EXT.chr}#{size_packed}#{@bits.chr}#{@value}"
|
115
|
+
else
|
116
|
+
return "#{TAG_BINARY_EXT.chr}#{size_packed}#{@value}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
def hash
|
120
|
+
return to_s.hash
|
121
|
+
end
|
122
|
+
def ==(other)
|
123
|
+
return to_s == other.to_s
|
124
|
+
end
|
125
|
+
alias eql? ==
|
126
|
+
end
|
127
|
+
|
128
|
+
class OtpErlangFunction
|
129
|
+
def initialize(tag, value)
|
130
|
+
@tag = tag
|
131
|
+
@value = value
|
132
|
+
end
|
133
|
+
def to_s
|
134
|
+
return "#{@tag.chr}#{@value}"
|
135
|
+
end
|
136
|
+
def hash
|
137
|
+
return to_s.hash
|
138
|
+
end
|
139
|
+
def ==(other)
|
140
|
+
return to_s == other.to_s
|
141
|
+
end
|
142
|
+
alias eql? ==
|
143
|
+
end
|
144
|
+
|
145
|
+
class OtpErlangReference
|
146
|
+
def initialize(node, id, creation)
|
147
|
+
@node = node
|
148
|
+
@id = id
|
149
|
+
@creation = creation
|
150
|
+
end
|
151
|
+
def to_s
|
152
|
+
size = @id.bytesize / 4
|
153
|
+
if size > 1
|
154
|
+
size_packed = [size].pack('n')
|
155
|
+
return "#{TAG_NEW_REFERENCE_EXT.chr}#{size_packed}#{@node.to_s}#{@creation}#{@id}"
|
156
|
+
else
|
157
|
+
return "#{TAG_REFERENCE_EXT.chr}#{@node.to_s}#{@id}#{@creation}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
def hash
|
161
|
+
return to_s.hash
|
162
|
+
end
|
163
|
+
def ==(other)
|
164
|
+
return to_s == other.to_s
|
165
|
+
end
|
166
|
+
alias eql? ==
|
167
|
+
end
|
168
|
+
|
169
|
+
class OtpErlangPort
|
170
|
+
def initialize(node, id, creation)
|
171
|
+
@node = node
|
172
|
+
@id = id
|
173
|
+
@creation = creation
|
174
|
+
end
|
175
|
+
def to_s
|
176
|
+
return "#{TAG_PORT_EXT.chr}#{@node.to_s}#{@id}#{@creation}"
|
177
|
+
end
|
178
|
+
def hash
|
179
|
+
return to_s.hash
|
180
|
+
end
|
181
|
+
def ==(other)
|
182
|
+
return to_s == other.to_s
|
183
|
+
end
|
184
|
+
alias eql? ==
|
185
|
+
end
|
186
|
+
|
187
|
+
class OtpErlangPid
|
188
|
+
def initialize(node, id, serial, creation)
|
189
|
+
@node = node
|
190
|
+
@id = id
|
191
|
+
@serial = serial
|
192
|
+
@creation = creation
|
193
|
+
end
|
194
|
+
def to_s
|
195
|
+
return "#{TAG_PID_EXT.chr}#{@node.to_s}#{@id}#{@serial}#{@creation}"
|
196
|
+
end
|
197
|
+
def hash
|
198
|
+
return to_s.hash
|
199
|
+
end
|
200
|
+
def ==(other)
|
201
|
+
return to_s == other.to_s
|
202
|
+
end
|
203
|
+
alias eql? ==
|
204
|
+
end
|
205
|
+
|
206
|
+
def binary_to_term(data)
|
207
|
+
if data[0].ord != TAG_VERSION
|
208
|
+
raise ParseException, 'invalid version', caller
|
209
|
+
end
|
210
|
+
result = binary_to_term_(1, data)
|
211
|
+
if result[0] != data.bytesize
|
212
|
+
raise ParseException, 'unparsed data', caller
|
213
|
+
end
|
214
|
+
return result[1]
|
215
|
+
end
|
216
|
+
|
217
|
+
def term_to_binary(term)
|
218
|
+
term_packed = term_to_binary_(term)
|
219
|
+
return "#{TAG_VERSION.chr}#{term_packed}"
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
# binary_to_term
|
225
|
+
|
226
|
+
def binary_to_term_(i, data)
|
227
|
+
tag = data[i].ord
|
228
|
+
i += 1
|
229
|
+
if tag == TAG_NEW_FLOAT_EXT
|
230
|
+
return [i + 8, data[i,8].unpack('G')[0]]
|
231
|
+
elsif tag == TAG_BIT_BINARY_EXT
|
232
|
+
j = data[i,4].unpack('N')[0]
|
233
|
+
i += 4
|
234
|
+
bits = data[i].ord
|
235
|
+
i += 1
|
236
|
+
return [i + j, OtpErlangBinary.new(data[i,j], bits)]
|
237
|
+
elsif tag == TAG_ATOM_CACHE_REF
|
238
|
+
return [i + 1, OtpErlangAtom.new(ord(data[i,1]))]
|
239
|
+
elsif tag == TAG_SMALL_INTEGER_EXT
|
240
|
+
return [i + 1, ord(data[i])]
|
241
|
+
elsif tag == TAG_INTEGER_EXT
|
242
|
+
value = data[i,4].unpack('N')[0]
|
243
|
+
if value & 0x80000000
|
244
|
+
value = -1 * (value & 0x7fffffff)
|
245
|
+
end
|
246
|
+
return [i + 4, Fixnum.induced_from(value)]
|
247
|
+
elsif tag == TAG_FLOAT_EXT
|
248
|
+
value = data[i,31].partition(0.chr)[0].to_f
|
249
|
+
return [i + 31, value]
|
250
|
+
elsif tag == TAG_ATOM_EXT
|
251
|
+
j = data[i,2].unpack('n')[0]
|
252
|
+
i += 2
|
253
|
+
atom_name = data[i,j].force_encoding('ISO-8859-1')
|
254
|
+
if atom_name.valid_encoding?
|
255
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
256
|
+
else
|
257
|
+
raise ParseException, 'invalid atom_name latin1', caller
|
258
|
+
end
|
259
|
+
elsif tag == TAG_REFERENCE_EXT or tag == TAG_PORT_EXT
|
260
|
+
result = binary_to_atom(i, data)
|
261
|
+
i = result[0]; node = result[1]
|
262
|
+
id = data[i,4]
|
263
|
+
i += 4
|
264
|
+
creation = data[i]
|
265
|
+
i += 1
|
266
|
+
if tag == TAG_REFERENCE_EXT
|
267
|
+
return [i, OtpErlangReference.new(node, id, creation)]
|
268
|
+
elsif tag == TAG_PORT_EXT
|
269
|
+
return [i, OtpErlangPort.new(node, id, creation)]
|
270
|
+
end
|
271
|
+
elsif tag == TAG_PID_EXT
|
272
|
+
result = binary_to_atom(i, data)
|
273
|
+
i = result[0]; node = result[1]
|
274
|
+
id = data[i,4]
|
275
|
+
i += 4
|
276
|
+
serial = data[i,4]
|
277
|
+
i += 4
|
278
|
+
creation = data[i]
|
279
|
+
i += 1
|
280
|
+
return [i, OtpErlangPid.new(node, id, serial, creation)]
|
281
|
+
elsif tag == TAG_SMALL_TUPLE_EXT or tag == TAG_LARGE_TUPLE_EXT
|
282
|
+
if tag == TAG_SMALL_TUPLE_EXT
|
283
|
+
arity = data[i].ord
|
284
|
+
i += 1
|
285
|
+
elsif tag == TAG_LARGE_TUPLE_EXT
|
286
|
+
arity = data[i,4].unpack('N')[0]
|
287
|
+
i += 4
|
288
|
+
end
|
289
|
+
result = binary_to_term_sequence(i, arity, data)
|
290
|
+
i = result[0]; tmp = result[1]
|
291
|
+
return [i, tmp]
|
292
|
+
elsif tag == TAG_NIL_EXT
|
293
|
+
return [i, OtpErlangList.new([])]
|
294
|
+
elsif tag == TAG_STRING_EXT
|
295
|
+
j = data[i,2].unpack('n')[0]
|
296
|
+
i += 2
|
297
|
+
return [i + j, data[i,j]]
|
298
|
+
elsif tag == TAG_LIST_EXT
|
299
|
+
arity = data[i,4].unpack('N')[0]
|
300
|
+
i += 4
|
301
|
+
result = binary_to_term_sequence(i, arity, data)
|
302
|
+
i = result[0]; tmp = result[1]
|
303
|
+
result = binary_to_term_(i, data)
|
304
|
+
i = result[0]; tail = result[1]
|
305
|
+
if tail.iskind?(OtpErlangList) == false
|
306
|
+
tmp.append(tail)
|
307
|
+
end
|
308
|
+
return [i, OtpErlangList.new(tmp)]
|
309
|
+
elsif tag == TAG_BINARY_EXT
|
310
|
+
j = data[i,4].unpack('N')[0]
|
311
|
+
i += 4
|
312
|
+
return [i + j, OtpErlangBinary.new(data[i,j], 8)]
|
313
|
+
elsif tag == TAG_SMALL_BIG_EXT or tag == TAG_LARGE_BIG_EXT
|
314
|
+
if tag == TAG_SMALL_BIG_EXT
|
315
|
+
j = data[i].ord
|
316
|
+
i += 1
|
317
|
+
elsif tag == TAG_LARGE_BIG_EXT
|
318
|
+
j = data[i,4].unpack('N')[0]
|
319
|
+
i += 4
|
320
|
+
end
|
321
|
+
sign = data[i].ord
|
322
|
+
i += 1
|
323
|
+
bignum = 0
|
324
|
+
(0...j).each do |bignum_index|
|
325
|
+
digit = data[i...(j - bignum_index)].ord
|
326
|
+
bignum = bignum * 256 + digit
|
327
|
+
end
|
328
|
+
if sign
|
329
|
+
bignum *= -1
|
330
|
+
end
|
331
|
+
return [i + j, bignum]
|
332
|
+
elsif tag == TAG_NEW_FUN_EXT
|
333
|
+
size = data[i,4].unpack('N')[0]
|
334
|
+
return [i + size, OtpErlangFunction.new(tag, data[i,size])]
|
335
|
+
elsif tag == TAG_EXPORT_EXT
|
336
|
+
old_i = i
|
337
|
+
result = binary_to_atom(i, data)
|
338
|
+
i = result[0]; name_module = result[1]
|
339
|
+
result = binary_to_atom(i, data)
|
340
|
+
i = result[0]; function = result[1]
|
341
|
+
if data[i].ord != TAG_SMALL_INTEGER_EXT
|
342
|
+
raise ParseException, 'invalid small integer tag', caller
|
343
|
+
end
|
344
|
+
i += 1
|
345
|
+
arity = data[i].ord
|
346
|
+
i += 1
|
347
|
+
return [i, OtpErlangFunction.new(tag, data[old_i,i])]
|
348
|
+
elsif tag == TAG_NEW_REFERENCE_EXT
|
349
|
+
j = data[i,2].unpack('n')[0] * 4
|
350
|
+
i += 2
|
351
|
+
result = binary_to_atom(i, data)
|
352
|
+
i = result[0]; node = result[1]
|
353
|
+
creation = data[i]
|
354
|
+
i += 1
|
355
|
+
id = data[i,j]
|
356
|
+
return [i + j, OtpErlangReference.new(node, id, creation)]
|
357
|
+
elsif tag == TAG_SMALL_ATOM_EXT
|
358
|
+
j = data[i,1].ord
|
359
|
+
i += 1
|
360
|
+
atom_name = data[i,j].force_encoding('ISO-8859-1')
|
361
|
+
if atom_name.valid_encoding?
|
362
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
363
|
+
else
|
364
|
+
raise ParseException, 'invalid atom_name latin1', caller
|
365
|
+
end
|
366
|
+
elsif tag == TAG_MAP_EXT
|
367
|
+
arity = data[i,4].unpack('N')[0]
|
368
|
+
i += 4
|
369
|
+
pairs = Hash.new
|
370
|
+
(0...arity).each do |arity_index|
|
371
|
+
result = binary_to_term_(i, data)
|
372
|
+
i = result[0]; key = result[1]
|
373
|
+
result = binary_to_term_(i, data)
|
374
|
+
i = result[0]; value = result[1]
|
375
|
+
pairs[key] = value
|
376
|
+
end
|
377
|
+
return [i, pairs]
|
378
|
+
elsif tag == TAG_FUN_EXT
|
379
|
+
old_i = i
|
380
|
+
numfree = data[i,4].unpack('N')[0]
|
381
|
+
i += 4
|
382
|
+
result = binary_to_pid(i, data)
|
383
|
+
i = result[0]; pid = result[1]
|
384
|
+
result = binary_to_atom(i, data)
|
385
|
+
i = result[0]; name_module = result[1]
|
386
|
+
result = binary_to_integer(i, data)
|
387
|
+
i = result[0]; index = result[1]
|
388
|
+
result = binary_to_integer(i, data)
|
389
|
+
i = result[0]; uniq = result[1]
|
390
|
+
result = binary_to_term_sequence(i, numfree, data)
|
391
|
+
i = result[0]; free = result[1]
|
392
|
+
return [i, OtpErlangFunction.new(tag, data[old_i,i])]
|
393
|
+
elsif tag == TAG_ATOM_UTF8_EXT
|
394
|
+
j = data[i,2].unpack('n')[0]
|
395
|
+
i += 2
|
396
|
+
atom_name = data[i,j].force_encoding('UTF-8')
|
397
|
+
if atom_name.valid_encoding?
|
398
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
399
|
+
else
|
400
|
+
raise ParseException, 'invalid atom_name unicode', caller
|
401
|
+
end
|
402
|
+
elsif tag == TAG_SMALL_ATOM_UTF8_EXT
|
403
|
+
j = data[i,1].ord
|
404
|
+
i += 1
|
405
|
+
atom_name = data[i,j].force_encoding('UTF-8')
|
406
|
+
if atom_name.valid_encoding?
|
407
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
408
|
+
else
|
409
|
+
raise ParseException, 'invalid atom_name unicode', caller
|
410
|
+
end
|
411
|
+
else
|
412
|
+
raise ParseException, 'invalid tag', caller
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def binary_to_term_sequence(i, arity, data)
|
417
|
+
sequence = []
|
418
|
+
(0...arity).each do |arity_index|
|
419
|
+
result = binary_to_term_(i, data)
|
420
|
+
i = result[0]; element = result[1]
|
421
|
+
sequence.append(element)
|
422
|
+
end
|
423
|
+
return [i, sequence]
|
424
|
+
end
|
425
|
+
|
426
|
+
def binary_to_integer(i, data)
|
427
|
+
tag = data[i].ord
|
428
|
+
i += 1
|
429
|
+
if tag == TAG_SMALL_INTEGER_EXT
|
430
|
+
return [i + 1, data[i].ord]
|
431
|
+
elsif tag == TAG_INTEGER_EXT
|
432
|
+
value = data[i,4].unpack('N')[0]
|
433
|
+
if value & 0x80000000
|
434
|
+
value = -1 * (value & 0x7fffffff)
|
435
|
+
end
|
436
|
+
return [i + 4, Fixnum.induced_from(value)]
|
437
|
+
else
|
438
|
+
raise ParseException, 'invalid integer tag', caller
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def binary_to_pid(i, data)
|
443
|
+
tag = data[i].ord
|
444
|
+
i += 1
|
445
|
+
if tag == TAG_PID_EXT
|
446
|
+
result = binary_to_atom(i, data)
|
447
|
+
i = result[0]; node = result[1]
|
448
|
+
id = data[i,4]
|
449
|
+
i += 4
|
450
|
+
serial = data[i,4]
|
451
|
+
i += 4
|
452
|
+
creation = data[i]
|
453
|
+
i += 1
|
454
|
+
return [i, OtpErlangPid.new(node, id, serial, creation)]
|
455
|
+
else
|
456
|
+
raise ParseException, 'invalid pid tag', caller
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def binary_to_atom(i, data)
|
461
|
+
tag = data[i].ord
|
462
|
+
i += 1
|
463
|
+
if tag == TAG_ATOM_EXT
|
464
|
+
j = data[i,2].unpack('n')[0]
|
465
|
+
i += 2
|
466
|
+
return [i + j, OtpErlangAtom.new(data[i,j])]
|
467
|
+
elsif tag == TAG_ATOM_CACHE_REF
|
468
|
+
return [i + 1, OtpErlangAtom.new(data[i,1].ord)]
|
469
|
+
elsif tag == TAG_SMALL_ATOM_EXT
|
470
|
+
j = data[i,1].ord
|
471
|
+
i += 1
|
472
|
+
return [i + j, OtpErlangAtom.new(data[i,j])]
|
473
|
+
elsif tag == TAG_ATOM_UTF8_EXT
|
474
|
+
j = data[i,2].unpack('n')[0]
|
475
|
+
i += 2
|
476
|
+
atom_name = data[i,j].force_encoding('UTF-8')
|
477
|
+
if atom_name.valid_encoding?
|
478
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
479
|
+
else
|
480
|
+
raise ParseException, 'invalid atom_name unicode', caller
|
481
|
+
end
|
482
|
+
elsif tag == TAG_SMALL_ATOM_UTF8_EXT
|
483
|
+
j = data[i,1].ord
|
484
|
+
i += 1
|
485
|
+
atom_name = data[i,j].force_encoding('UTF-8')
|
486
|
+
if atom_name.valid_encoding?
|
487
|
+
return [i + j, OtpErlangAtom.new(atom_name)]
|
488
|
+
else
|
489
|
+
raise ParseException, 'invalid atom_name unicode', caller
|
490
|
+
end
|
491
|
+
else
|
492
|
+
raise ParseException, 'invalid atom tag', caller
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
# term_to_binary
|
497
|
+
|
498
|
+
def term_to_binary_(term)
|
499
|
+
if term.kind_of?(String)
|
500
|
+
return string_to_binary(term)
|
501
|
+
elsif term.kind_of?(OtpErlangList)
|
502
|
+
return term.to_s
|
503
|
+
elsif term.kind_of?(Array)
|
504
|
+
return tuple_to_binary(term)
|
505
|
+
elsif term.kind_of?(Float)
|
506
|
+
return float_to_binary(term)
|
507
|
+
elsif term.kind_of?(Integer)
|
508
|
+
return integer_to_binary(term)
|
509
|
+
elsif term.kind_of?(Hash)
|
510
|
+
return hash_to_binary(term)
|
511
|
+
elsif term.kind_of?(Symbol)
|
512
|
+
return OtpErlangAtom.new(term.to_s).to_s
|
513
|
+
elsif term.kind_of?(TrueClass)
|
514
|
+
return OtpErlangAtom.new("true").to_s
|
515
|
+
elsif term.kind_of?(FalseClass)
|
516
|
+
return OtpErlangAtom.new("false").to_s
|
517
|
+
elsif term.kind_of?(OtpErlangAtom)
|
518
|
+
return term.to_s
|
519
|
+
elsif term.kind_of?(OtpErlangBinary)
|
520
|
+
return term.to_s
|
521
|
+
elsif term.kind_of?(OtpErlangFunction)
|
522
|
+
return term.to_s
|
523
|
+
elsif term.kind_of?(OtpErlangReference)
|
524
|
+
return term.to_s
|
525
|
+
elsif term.kind_of?(OtpErlangPort)
|
526
|
+
return term.to_s
|
527
|
+
elsif term.kind_of?(OtpErlangPid)
|
528
|
+
return term.to_s
|
529
|
+
else
|
530
|
+
raise OutputException, 'unknown ruby type', caller
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def string_to_binary(term)
|
535
|
+
arity = term.bytesize
|
536
|
+
if arity == 0
|
537
|
+
return TAG_NIL_EXT.chr
|
538
|
+
elsif arity < 65536
|
539
|
+
arity_packed = [arity].pack('n')
|
540
|
+
return "#{TAG_STRING_EXT.chr}#{arity_packed}#{term}"
|
541
|
+
else
|
542
|
+
arity_packed = [arity].pack('N')
|
543
|
+
term_packed = term.unpack("C#{arity}").map{ |c|
|
544
|
+
"#{TAG_SMALL_INTEGER_EXT.chr}#{c}"
|
545
|
+
}.join
|
546
|
+
return "#{TAG_LIST_EXT.chr}#{arity_packed}#{term_packed}#{TAG_NIL_EXT.chr}"
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
def tuple_to_binary(term)
|
551
|
+
arity = term.length
|
552
|
+
term_packed = term.map{ |element|
|
553
|
+
term_to_binary_(element)
|
554
|
+
}.join
|
555
|
+
if arity < 256
|
556
|
+
return "#{TAG_SMALL_TUPLE_EXT.chr}#{arity.chr}#{term_packed}"
|
557
|
+
else
|
558
|
+
arity_packed = [arity].pack('N')
|
559
|
+
return "#{TAG_LARGE_TUPLE_EXT.chr}#{arity_packed}#{term_packed}"
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def integer_to_binary(term)
|
564
|
+
if 0 <= term and term <= 255
|
565
|
+
return "#{TAG_SMALL_INTEGER_EXT.chr}#{term.chr}"
|
566
|
+
elsif -2147483648 <= term and term <= 2147483647
|
567
|
+
term_packed = [term].pack('N')
|
568
|
+
return "#{TAG_INTEGER_EXT.chr}#{term_packed}"
|
569
|
+
else
|
570
|
+
return bignum_to_binary(term)
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def bignum_to_binary(term)
|
575
|
+
bignum = term.abs
|
576
|
+
size = Integer.new(Math.log(bignum) / Math.log(256)) + 1
|
577
|
+
if term < 0
|
578
|
+
sign = 1.chr
|
579
|
+
else
|
580
|
+
sign = 0.chr
|
581
|
+
end
|
582
|
+
l = [sign]
|
583
|
+
(0...size).each do |byte|
|
584
|
+
l.append((bignum & 255).chr)
|
585
|
+
bignum >>= 8
|
586
|
+
end
|
587
|
+
if size < 256
|
588
|
+
return "#{TAG_SMALL_BIG_EXT.chr}#{size.chr}#{l.join}"
|
589
|
+
else
|
590
|
+
size_packed = [size].pack('N')
|
591
|
+
return "#{TAG_LARGE_BIG_EXT.chr}#{size_packed}#{l.join}"
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def float_to_binary(term)
|
596
|
+
term_packed = [term].pack('G')
|
597
|
+
return "#{TAG_NEW_FLOAT_EXT.chr}#{term_packed}"
|
598
|
+
end
|
599
|
+
|
600
|
+
def hash_to_binary(term)
|
601
|
+
arity = term.length
|
602
|
+
term_packed = term.to_a.map{ |element|
|
603
|
+
key_packed = term_to_binary_(element[0])
|
604
|
+
value_packed = term_to_binary_(element[1])
|
605
|
+
"#{key_packed}#{value_packed}"
|
606
|
+
}.join
|
607
|
+
arity_packed = [arity].pack('N')
|
608
|
+
return "#{TAG_MAP_EXT.chr}#{arity_packed}#{term_packed}"
|
609
|
+
end
|
610
|
+
|
611
|
+
# exceptions
|
612
|
+
|
613
|
+
class ParseException < SyntaxError
|
614
|
+
end
|
615
|
+
|
616
|
+
class OutputException < TypeError
|
617
|
+
end
|
618
|
+
|
619
|
+
# tag values here http://www.erlang.org/doc/apps/erts/erl_ext_dist.html
|
620
|
+
TAG_VERSION = 131
|
621
|
+
TAG_NEW_FLOAT_EXT = 70
|
622
|
+
TAG_BIT_BINARY_EXT = 77
|
623
|
+
TAG_ATOM_CACHE_REF = 78
|
624
|
+
TAG_SMALL_INTEGER_EXT = 97
|
625
|
+
TAG_INTEGER_EXT = 98
|
626
|
+
TAG_FLOAT_EXT = 99
|
627
|
+
TAG_ATOM_EXT = 100
|
628
|
+
TAG_REFERENCE_EXT = 101
|
629
|
+
TAG_PORT_EXT = 102
|
630
|
+
TAG_PID_EXT = 103
|
631
|
+
TAG_SMALL_TUPLE_EXT = 104
|
632
|
+
TAG_LARGE_TUPLE_EXT = 105
|
633
|
+
TAG_NIL_EXT = 106
|
634
|
+
TAG_STRING_EXT = 107
|
635
|
+
TAG_LIST_EXT = 108
|
636
|
+
TAG_BINARY_EXT = 109
|
637
|
+
TAG_SMALL_BIG_EXT = 110
|
638
|
+
TAG_LARGE_BIG_EXT = 111
|
639
|
+
TAG_NEW_FUN_EXT = 112
|
640
|
+
TAG_EXPORT_EXT = 113
|
641
|
+
TAG_NEW_REFERENCE_EXT = 114
|
642
|
+
TAG_SMALL_ATOM_EXT = 115
|
643
|
+
TAG_MAP_EXT = 116
|
644
|
+
TAG_FUN_EXT = 117
|
645
|
+
TAG_ATOM_UTF8_EXT = 118
|
646
|
+
TAG_SMALL_ATOM_UTF8_EXT = 119
|
647
|
+
|
648
|
+
end
|
649
|
+
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: erlang_rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Truog
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain:
|
12
|
+
- ! '-----BEGIN CERTIFICATE-----
|
13
|
+
|
14
|
+
MIIDMDCCAhigAwIBAgIBADANBgkqhkiG9w0BAQUFADA+MRAwDgYDVQQDDAdtanRy
|
15
|
+
|
16
|
+
dW9nMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
|
17
|
+
|
18
|
+
HhcNMTQwNjI0MjAzMDQ2WhcNMTUwNjI0MjAzMDQ2WjA+MRAwDgYDVQQDDAdtanRy
|
19
|
+
|
20
|
+
dW9nMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
|
21
|
+
|
22
|
+
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBOoI/CUuwOhXjks02cT58
|
23
|
+
|
24
|
+
jLxgsOQ412Xzu4eEKqzNsWMoj/3+qYdb5CR4+51EHtuJHZ8hndL5DTYIO8ylcG11
|
25
|
+
|
26
|
+
EvyxqOzU+gqC53gCEBhJLivlyMXvGqL8qHPuSKGEMc1Vpzh0WicwNnaT7z3X6aQP
|
27
|
+
|
28
|
+
UE6qWd1yE9jT7TX+GKcKayBJTufxcBMjtwvzMH4IiVaNjUBHBq2LbeNO1yDPYVzV
|
29
|
+
|
30
|
+
HWnZCv75vIXdUruFrSZcJgNRYRwzMfHEbf+BcvqqGVV6p3PJgJMrjI8FZ7roIJNf
|
31
|
+
|
32
|
+
D7ZO96x4ItjGazoTntAZe3EM9QB5Wjsd1cv2IEOISQ6jyvVX5E84Al+MEKhhhFuL
|
33
|
+
|
34
|
+
AgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFACw0UcBaNl2dQWwgg/Qzeyf
|
35
|
+
|
36
|
+
cKG7MAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAHjLn+8F8yeOFcKst
|
37
|
+
|
38
|
+
mKA3m28OIoICMefZOiJfTC9UkVkW+554IXNBu3vVxLc0nlCqmuf/aQGaFBUm9MLA
|
39
|
+
|
40
|
+
oD5CmlrU9OrEl2fPxqTHAwFgLNre8e2EWtm2OhBg73JTHRVVyBLpSK5GRUDzhJtZ
|
41
|
+
|
42
|
+
7a2ocAE2AgFKpISNxIUe4Zz9O2thg3iryLh9prjETJTUfxDjBmHdx+YkNAblRa2w
|
43
|
+
|
44
|
+
k9A+nCZzZECcR5ZZYSeaK6MCugGmXUhAkDbuWumCzu/RAghlVC9RFFQt7o1SwGQp
|
45
|
+
|
46
|
+
LdvYOeJbviyiH1q1rC3NAJNC4P7Q41zx1OYa8S9M5qn+JpE0ZsomnZyGunWaya9Q
|
47
|
+
|
48
|
+
bTD/aw==
|
49
|
+
|
50
|
+
-----END CERTIFICATE-----
|
51
|
+
|
52
|
+
'
|
53
|
+
date: 2014-06-24 00:00:00.000000000 Z
|
54
|
+
dependencies: []
|
55
|
+
description: Erlang Binary Term Format for Ruby
|
56
|
+
email: mjtruog@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README.markdown
|
61
|
+
files:
|
62
|
+
- lib/erlang.rb
|
63
|
+
- README.markdown
|
64
|
+
homepage: https://github.com/okeuday/erlang_rb
|
65
|
+
licenses:
|
66
|
+
- BSD
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.9.0
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.8.11
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: Erlang
|
89
|
+
test_files: []
|
metadata.gz.sig
ADDED