leon 1.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.
- data/lib/buffer-iterator.rb +68 -0
- data/lib/constants.rb +22 -0
- data/lib/io.rb +525 -0
- data/lib/leon.rb +28 -0
- data/lib/string-buffer.rb +319 -0
- data/lib/types.rb +21 -0
- metadata +52 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'constants'
|
2
|
+
|
3
|
+
module LEON
|
4
|
+
class BufferIterator
|
5
|
+
def initialize(buf)
|
6
|
+
@buffer = buf
|
7
|
+
@i = 0
|
8
|
+
end
|
9
|
+
def readUInt8()
|
10
|
+
@i += 1
|
11
|
+
return @buffer.readUInt8(@i - 1)
|
12
|
+
end
|
13
|
+
def readInt8()
|
14
|
+
@i += 1
|
15
|
+
return @buffer.readInt8(@i - 1)
|
16
|
+
end
|
17
|
+
def readUInt16()
|
18
|
+
@i += 2
|
19
|
+
return @buffer.readUInt16LE(@i - 2)
|
20
|
+
end
|
21
|
+
def readInt16()
|
22
|
+
@i += 2
|
23
|
+
return @buffer.readInt16LE(@i - 2)
|
24
|
+
end
|
25
|
+
def readUInt32()
|
26
|
+
@i += 4
|
27
|
+
return @buffer.readUInt32LE(@i - 4)
|
28
|
+
end
|
29
|
+
def readInt32()
|
30
|
+
@i += 4
|
31
|
+
return @buffer.readInt32LE(@i - 4)
|
32
|
+
end
|
33
|
+
def readFloat()
|
34
|
+
@i += 4
|
35
|
+
return @buffer.readFloatLE(@i - 4)
|
36
|
+
end
|
37
|
+
def readDouble()
|
38
|
+
@i += 8
|
39
|
+
return @buffer.readDoubleLE(@i - 8)
|
40
|
+
end
|
41
|
+
def readValue(type)
|
42
|
+
if type === Constants::UNSIGNED_CHAR
|
43
|
+
return readUInt8()
|
44
|
+
end
|
45
|
+
if type === Constants::CHAR
|
46
|
+
return readInt8()
|
47
|
+
end
|
48
|
+
if type === Constants::UNSIGNED_SHORT
|
49
|
+
return readUInt16()
|
50
|
+
end
|
51
|
+
if type === Constants::SHORT
|
52
|
+
return readInt16()
|
53
|
+
end
|
54
|
+
if type === Constants::UNSIGNED_INT
|
55
|
+
return readUInt32()
|
56
|
+
end
|
57
|
+
if type === Constants::INT
|
58
|
+
return readInt32()
|
59
|
+
end
|
60
|
+
if type === Constants::FLOAT
|
61
|
+
return readFloat()
|
62
|
+
end
|
63
|
+
if type === Constants::DOUBLE
|
64
|
+
return readDouble()
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/constants.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Constants
|
2
|
+
UNSIGNED_CHAR = 0x00
|
3
|
+
CHAR = 0x01
|
4
|
+
UNSIGNED_SHORT = 0x02
|
5
|
+
SHORT = 0x03
|
6
|
+
UNSIGNED_INT = 0x04
|
7
|
+
INT = 0x05
|
8
|
+
FLOAT = 0x06
|
9
|
+
DOUBLE = 0x07
|
10
|
+
STRING = 0x10
|
11
|
+
BOOLEAN = 0x20
|
12
|
+
NULL = 0x40
|
13
|
+
UNDEFINED = 0x14
|
14
|
+
OBJECT = 0x09
|
15
|
+
ARRAY = 0x80
|
16
|
+
DATE = 0x15
|
17
|
+
BUFFER = 0x16
|
18
|
+
REGEXP = 0x17
|
19
|
+
NAN = 0x18
|
20
|
+
INFINITY = 0x19
|
21
|
+
MINUS_INFINITY = 0x1A
|
22
|
+
end
|
data/lib/io.rb
ADDED
@@ -0,0 +1,525 @@
|
|
1
|
+
require 'buffer-iterator'
|
2
|
+
require 'string-buffer'
|
3
|
+
require 'constants'
|
4
|
+
require 'types'
|
5
|
+
require 'date'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
module LEON
|
9
|
+
class Parser
|
10
|
+
def initialize(*args)
|
11
|
+
if args.length > 1
|
12
|
+
@spec = args[1]
|
13
|
+
@hasSpec = true
|
14
|
+
end
|
15
|
+
@buffer = BufferIterator.new(args[0])
|
16
|
+
@state = 0
|
17
|
+
@stringIndex = Array.new
|
18
|
+
@objectLayoutIndex = Array.new
|
19
|
+
end
|
20
|
+
def readString()
|
21
|
+
ret = ''
|
22
|
+
while (true) do
|
23
|
+
char = @buffer.readUInt8()
|
24
|
+
if char === 0
|
25
|
+
break
|
26
|
+
end
|
27
|
+
ret += char.chr
|
28
|
+
end
|
29
|
+
return ret
|
30
|
+
end
|
31
|
+
def readBuffer()
|
32
|
+
ret = StringBuffer.new
|
33
|
+
len = @buffer.readValue(@buffer.readUInt8())
|
34
|
+
for i in 0..(len - 1)
|
35
|
+
ret.writeUInt8(@buffer.readUInt8(), i)
|
36
|
+
end
|
37
|
+
return ret
|
38
|
+
end
|
39
|
+
def readRegExp()
|
40
|
+
return RegExp.new(readString(), readString())
|
41
|
+
end
|
42
|
+
def readDate()
|
43
|
+
return Time.at(@buffer.readUInt32())
|
44
|
+
end
|
45
|
+
def parseSI()
|
46
|
+
if (@state & 0x01) != 0
|
47
|
+
return
|
48
|
+
end
|
49
|
+
@stringIndexType = @buffer.readUInt8()
|
50
|
+
case @stringIndexType
|
51
|
+
when Constants::UNSIGNED_CHAR, Constants::UNSIGNED_SHORT, Constants::UNSIGNED_INT
|
52
|
+
stringCount = @buffer.readValue(@stringIndexType)
|
53
|
+
when 0xFF
|
54
|
+
stringCount = 0
|
55
|
+
else
|
56
|
+
return self
|
57
|
+
end
|
58
|
+
for i in (0..(stringCount - 1))
|
59
|
+
@stringIndex.push readString()
|
60
|
+
end
|
61
|
+
@state |= 0x01
|
62
|
+
return self
|
63
|
+
end
|
64
|
+
def parseOLI()
|
65
|
+
if (@state & 0x01) === 0
|
66
|
+
parseSI()
|
67
|
+
end
|
68
|
+
if @stringIndex.length === 0
|
69
|
+
return self
|
70
|
+
end
|
71
|
+
@OLItype = @buffer.readUInt8()
|
72
|
+
case @OLItype
|
73
|
+
when Constants::UNSIGNED_CHAR, Constants::UNSIGNED_SHORT, Constants::UNSIGNED_INT
|
74
|
+
count = @buffer.readValue(@OLItype)
|
75
|
+
when 0xFF
|
76
|
+
return self
|
77
|
+
else
|
78
|
+
return self
|
79
|
+
end
|
80
|
+
for i in 0..(count - 1)
|
81
|
+
@objectLayoutIndex.push Array.new
|
82
|
+
numFields = @buffer.readValue(@buffer.readUInt8())
|
83
|
+
for j in 0..(numFields - 1)
|
84
|
+
@objectLayoutIndex[i].push(@buffer.readValue(@stringIndexType))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
return self
|
88
|
+
end
|
89
|
+
def parseValueWithSpec(*args)
|
90
|
+
if args.length === 0
|
91
|
+
spec = @spec
|
92
|
+
else
|
93
|
+
spec = args[0]
|
94
|
+
end
|
95
|
+
if spec === Constants::STRING
|
96
|
+
return readString()
|
97
|
+
elsif spec.kind_of?(Array)
|
98
|
+
ret = Array.new
|
99
|
+
spec = spec[0]
|
100
|
+
length = @buffer.readValue(@buffer.readUInt8())
|
101
|
+
for i in (0..(length - 1))
|
102
|
+
ret.push parseValueWithSpec(spec)
|
103
|
+
end
|
104
|
+
return ret
|
105
|
+
elsif spec.is_a?(Hash)
|
106
|
+
ret = Hash.new
|
107
|
+
spec.each do |k, v|
|
108
|
+
ret[k] = parseValueWithSpec(v)
|
109
|
+
end
|
110
|
+
return ret
|
111
|
+
elsif spec === Constants::BOOLEAN
|
112
|
+
return parseValue()
|
113
|
+
else
|
114
|
+
return parseValue(spec)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
def parseValue(*args)
|
118
|
+
if args.length === 0
|
119
|
+
type = @buffer.readUInt8()
|
120
|
+
else
|
121
|
+
type = args[0]
|
122
|
+
end
|
123
|
+
if type < Constants::OBJECT
|
124
|
+
return @buffer.readValue(type)
|
125
|
+
elsif type === Constants::ARRAY
|
126
|
+
len = @buffer.readValue(@buffer.readUInt8())
|
127
|
+
ret = Array.new
|
128
|
+
for i in 0..(len - 1)
|
129
|
+
ret.push parseValue()
|
130
|
+
end
|
131
|
+
return ret
|
132
|
+
elsif type === Constants::OBJECT
|
133
|
+
index = @objectLayoutIndex[@buffer.readValue(@OLItype)]
|
134
|
+
ret = Hash.new
|
135
|
+
index.each_with_index { |val, idx|
|
136
|
+
ret[@stringIndex[val]] = parseValue()
|
137
|
+
}
|
138
|
+
return ret
|
139
|
+
elsif type === Constants::STRING
|
140
|
+
return @stringIndex[@buffer.readValue(@stringIndexType)]
|
141
|
+
elsif type === Constants::UNDEFINED
|
142
|
+
return LEON::Undefined.new
|
143
|
+
elsif type === Constants::BOOLEAN
|
144
|
+
return true
|
145
|
+
elsif type === Constants::BOOLEAN + 1
|
146
|
+
return false
|
147
|
+
elsif type === Constants::NULL
|
148
|
+
return nil
|
149
|
+
elsif type === Constants::NAN
|
150
|
+
return LEON::NaN.new
|
151
|
+
elsif type === Constants::DATE
|
152
|
+
return readDate()
|
153
|
+
elsif type === Constants::REGEXP
|
154
|
+
return readRegExp()
|
155
|
+
elsif type === Constants::BUFFER
|
156
|
+
return readBuffer()
|
157
|
+
elsif type === Constants::INFINITY
|
158
|
+
return Float::INFINITY
|
159
|
+
elsif type === Constants::MINUS_INFINITY
|
160
|
+
return -1/0.0
|
161
|
+
else
|
162
|
+
return
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.type_check(v)
|
168
|
+
if v === nil
|
169
|
+
return Constants::NULL
|
170
|
+
elsif v === true
|
171
|
+
return Constants::BOOLEAN
|
172
|
+
elsif v === false
|
173
|
+
return Constants::BOOLEAN + 1
|
174
|
+
elsif v.kind_of? LEON::NaN
|
175
|
+
return Constants::NAN
|
176
|
+
elsif v.kind_of? LEON::Undefined
|
177
|
+
return Constants::UNDEFINED
|
178
|
+
elsif v.kind_of? Date or v.kind_of? Time
|
179
|
+
return Constants::DATE
|
180
|
+
elsif v.kind_of? LEON::StringBuffer
|
181
|
+
return Constants::BUFFER
|
182
|
+
elsif v.kind_of? LEON::RegExp
|
183
|
+
return Constants::REGEXP
|
184
|
+
elsif v === Float::INFINITY
|
185
|
+
return Constants::INFINITY
|
186
|
+
elsif v === -1/0.0
|
187
|
+
return Constants::MINUS_INFINITY
|
188
|
+
elsif v.kind_of?(Array)
|
189
|
+
return Constants::ARRAY
|
190
|
+
elsif v.kind_of?(Hash)
|
191
|
+
return Constants::OBJECT
|
192
|
+
elsif v.is_a? String
|
193
|
+
return Constants::STRING
|
194
|
+
elsif v.kind_of? Symbol
|
195
|
+
return Constants::STRING
|
196
|
+
elsif v.is_a? Fixnum
|
197
|
+
if v < 0
|
198
|
+
v = v.abs
|
199
|
+
if v < (1 << 6)
|
200
|
+
return Constants::CHAR
|
201
|
+
elsif v < (1 << 14)
|
202
|
+
return Constants::SHORT
|
203
|
+
elsif v < (1 << 30)
|
204
|
+
return Constants::INT
|
205
|
+
end
|
206
|
+
return Constants::DOUBLE
|
207
|
+
end
|
208
|
+
if v < (1 << 7)
|
209
|
+
return Constants::UNSIGNED_CHAR
|
210
|
+
end
|
211
|
+
if v < (1 << 15)
|
212
|
+
return Constants::UNSIGNED_SHORT
|
213
|
+
end
|
214
|
+
if v < (1 << 31)
|
215
|
+
return Constants::UNSIGNED_INT
|
216
|
+
end
|
217
|
+
return Constants::DOUBLE
|
218
|
+
elsif v.is_a? Float
|
219
|
+
v = v.abs
|
220
|
+
log = Math::log(v)/Math::log(2)
|
221
|
+
if log < -128 or log > 127
|
222
|
+
return Constants::DOUBLE
|
223
|
+
end
|
224
|
+
if log < 0
|
225
|
+
log = log.ceil
|
226
|
+
else
|
227
|
+
log = log.floor
|
228
|
+
end
|
229
|
+
v *= 2**(-log + 23)
|
230
|
+
if v.floor != v
|
231
|
+
return Constants::DOUBLE
|
232
|
+
end
|
233
|
+
return Constants::FLOAT
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class Encoder
|
238
|
+
def initialize(*args)
|
239
|
+
if args.length > 1
|
240
|
+
@spec = args[1]
|
241
|
+
@hasSpec = true
|
242
|
+
else
|
243
|
+
@hasSpec = false
|
244
|
+
end
|
245
|
+
@payload = args[0]
|
246
|
+
@OLI = Array.new
|
247
|
+
@stringIndex = Array.new
|
248
|
+
@buffer = StringBuffer.new
|
249
|
+
end
|
250
|
+
def append(buf)
|
251
|
+
@buffer = StringBuffer.concat([@buffer, buf])
|
252
|
+
end
|
253
|
+
def writeData()
|
254
|
+
if @hasSpec
|
255
|
+
writeValueWithSpec(@payload)
|
256
|
+
else
|
257
|
+
writeValue(@payload, LEON::type_check(@payload))
|
258
|
+
end
|
259
|
+
return self
|
260
|
+
end
|
261
|
+
def export()
|
262
|
+
return @buffer.buffer
|
263
|
+
end
|
264
|
+
def writeValueWithSpec(*args)
|
265
|
+
if args.length > 1
|
266
|
+
spec = args[1]
|
267
|
+
else
|
268
|
+
spec = @spec
|
269
|
+
end
|
270
|
+
val = args[0]
|
271
|
+
if spec.kind_of? Array
|
272
|
+
writeValue(val.length, LEON::type_check(val.length))
|
273
|
+
val.each { |v|
|
274
|
+
writeValueWithSpec(v, spec[0])
|
275
|
+
}
|
276
|
+
elsif spec.kind_of? Hash
|
277
|
+
spec.each { |k, v|
|
278
|
+
writeValueWithSpec(val[k], v)
|
279
|
+
}
|
280
|
+
elsif spec === Constants::BOOLEAN
|
281
|
+
writeValue(val, LEON::type_check(val), true)
|
282
|
+
else
|
283
|
+
writeValue(val, spec, true)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
def writeValue(*args)
|
287
|
+
val = args[0]
|
288
|
+
type = args[1]
|
289
|
+
if args.length > 2
|
290
|
+
implicit = args[2]
|
291
|
+
else
|
292
|
+
implicit = false
|
293
|
+
end
|
294
|
+
typeByte = StringBuffer.new
|
295
|
+
typeByte.writeUInt8(type, 0)
|
296
|
+
if type === Constants::UNDEFINED or type === Constants::BOOLEAN or type === Constants::BOOLEAN + 1 or type === Constants::NULL or type === Constants::NAN or type === Constants::MINUS_INFINITY or type === Constants::INFINITY
|
297
|
+
append(typeByte)
|
298
|
+
return 1
|
299
|
+
end
|
300
|
+
byteCount = 0
|
301
|
+
if !implicit
|
302
|
+
append(typeByte)
|
303
|
+
byteCount += 1
|
304
|
+
end
|
305
|
+
if type === Constants::STRING
|
306
|
+
if val.kind_of? Symbol
|
307
|
+
val = val.to_s
|
308
|
+
end
|
309
|
+
if @stringIndex.length === 0
|
310
|
+
writeString(val)
|
311
|
+
return 1 + byteCount + val.length
|
312
|
+
end
|
313
|
+
writeValue(@stringIndex.index(val), @stringIndexType, true)
|
314
|
+
return byteCount + 1
|
315
|
+
elsif type == Constants::CHAR
|
316
|
+
bytes = StringBuffer.new
|
317
|
+
bytes.writeInt8(val, 0)
|
318
|
+
append(bytes)
|
319
|
+
return byteCount + 1
|
320
|
+
elsif type == Constants::UNSIGNED_CHAR
|
321
|
+
bytes = StringBuffer.new
|
322
|
+
bytes.writeUInt8(val, 0)
|
323
|
+
append(bytes)
|
324
|
+
return byteCount + 1
|
325
|
+
elsif type === Constants::SHORT
|
326
|
+
bytes = StringBuffer.new
|
327
|
+
bytes.writeInt16LE(val, 0)
|
328
|
+
append(bytes)
|
329
|
+
return byteCount + 2
|
330
|
+
elsif type === Constants::UNSIGNED_SHORT
|
331
|
+
bytes = StringBuffer.new
|
332
|
+
bytes.writeUInt16LE(val, 0)
|
333
|
+
append(bytes)
|
334
|
+
return byteCount + 2
|
335
|
+
elsif type === Constants::INT
|
336
|
+
bytes = StringBuffer.new
|
337
|
+
bytes.writeInt32LE(val, 0)
|
338
|
+
append(bytes)
|
339
|
+
return byteCount + 4
|
340
|
+
elsif type === Constants::UNSIGNED_INT
|
341
|
+
bytes = StringBuffer.new
|
342
|
+
bytes.writeUInt32LE(val, 0)
|
343
|
+
append(bytes)
|
344
|
+
return byteCount + 4
|
345
|
+
elsif type === Constants::FLOAT
|
346
|
+
bytes = StringBuffer.new
|
347
|
+
bytes.writeFloatLE(val, 0)
|
348
|
+
append(bytes)
|
349
|
+
return byteCount + 4
|
350
|
+
elsif type === Constants::DOUBLE
|
351
|
+
bytes = StringBuffer.new
|
352
|
+
bytes.writeDoubleLE(val, 0)
|
353
|
+
append(bytes)
|
354
|
+
return byteCount + 8
|
355
|
+
elsif type === Constants::ARRAY
|
356
|
+
writeValue(val.length, LEON::type_check(val.length))
|
357
|
+
val.each { |v|
|
358
|
+
writeValue(v, LEON::type_check(v))
|
359
|
+
}
|
360
|
+
return
|
361
|
+
elsif type === Constants::OBJECT
|
362
|
+
index = LEON::match_layout(val, @stringIndex, @OLI)
|
363
|
+
writeValue(index, @OLItype, true)
|
364
|
+
for i in 0..(@OLI[index].length - 1)
|
365
|
+
key = @stringIndex[@OLI[index][i]]
|
366
|
+
if not val.has_key? key
|
367
|
+
key = key.to_sym
|
368
|
+
end
|
369
|
+
tmp = val[key]
|
370
|
+
writeValue(tmp, LEON::type_check(tmp))
|
371
|
+
end
|
372
|
+
return
|
373
|
+
elsif type === Constants::BUFFER
|
374
|
+
len = val.buffer.length
|
375
|
+
writeValue(len, LEON::type_check(len))
|
376
|
+
for i in 0..(len - 1)
|
377
|
+
writeValue(val.buffer[i].ord, Constants::UNSIGNED_CHAR, true)
|
378
|
+
end
|
379
|
+
return byteCount + val.buffer.length
|
380
|
+
elsif type === Constants::REGEXP
|
381
|
+
writeString(val.pattern)
|
382
|
+
writeString(val.modifier)
|
383
|
+
return byteCount + 2 + val.pattern.length + val.modifier.length
|
384
|
+
elsif type === Constants::DATE
|
385
|
+
if val.kind_of? Date
|
386
|
+
val = Time.parse(val.to_s)
|
387
|
+
end
|
388
|
+
writeValue(val.to_i, Constants::UNSIGNED_INT, true)
|
389
|
+
return byteCount + 4
|
390
|
+
end
|
391
|
+
end
|
392
|
+
def writeString(str)
|
393
|
+
bytes = StringBuffer.new
|
394
|
+
len = str.length
|
395
|
+
for i in 0..(len - 1)
|
396
|
+
bytes.writeUInt8(str[i].ord, -1)
|
397
|
+
end
|
398
|
+
bytes.writeUInt8(0, -1)
|
399
|
+
append(bytes)
|
400
|
+
return len + 1
|
401
|
+
end
|
402
|
+
def writeOLI()
|
403
|
+
if @stringIndex.length === 0
|
404
|
+
return self
|
405
|
+
end
|
406
|
+
@OLI = LEON::gather_layouts(@payload, @stringIndex)
|
407
|
+
if @OLI.length === 0
|
408
|
+
writeValue(0xFF, Constants::UNSIGNED_CHAR, true)
|
409
|
+
return self
|
410
|
+
end
|
411
|
+
@OLItype = LEON::type_check(@OLI.length)
|
412
|
+
writeValue(@OLI.length, @OLItype)
|
413
|
+
@OLI.each { |v|
|
414
|
+
type = LEON::type_check(v.length)
|
415
|
+
writeValue(v.length, type)
|
416
|
+
v.each { |v|
|
417
|
+
writeValue(v, @stringIndexType, true)
|
418
|
+
}
|
419
|
+
}
|
420
|
+
return self
|
421
|
+
end
|
422
|
+
def writeSI()
|
423
|
+
@stringIndex = LEON::gather_strings(@payload)
|
424
|
+
if @stringIndex.length === 0
|
425
|
+
writeValue(0xFF, Constants::UNSIGNED_CHAR, true)
|
426
|
+
return self
|
427
|
+
end
|
428
|
+
@stringIndexType = LEON::type_check(@stringIndex.length)
|
429
|
+
writeValue(@stringIndex.length, @stringIndexType)
|
430
|
+
@stringIndex.each { |v|
|
431
|
+
writeString(v)
|
432
|
+
}
|
433
|
+
return self
|
434
|
+
end
|
435
|
+
end
|
436
|
+
def self.match_layout(val, stringIndex, oli)
|
437
|
+
keys = val.keys
|
438
|
+
layout = Array.new
|
439
|
+
for i in 0..(keys.length - 1)
|
440
|
+
if keys[i].kind_of? Symbol
|
441
|
+
keys[i] = keys[i].to_s
|
442
|
+
end
|
443
|
+
layout.push stringIndex.index(keys[i])
|
444
|
+
end
|
445
|
+
layout.sort! { |a, b|
|
446
|
+
a <=> b
|
447
|
+
}
|
448
|
+
i = 0
|
449
|
+
while i < oli.length
|
450
|
+
if layout.eql? oli[i].sort { |a, b| a <=> b }
|
451
|
+
return i
|
452
|
+
end
|
453
|
+
i += 1
|
454
|
+
end
|
455
|
+
end
|
456
|
+
def self.gather_layouts(*args)
|
457
|
+
if args.length > 3
|
458
|
+
branch = args[3]
|
459
|
+
else
|
460
|
+
branch = args[0]
|
461
|
+
end
|
462
|
+
if args.length > 2
|
463
|
+
ret = args[2]
|
464
|
+
else
|
465
|
+
ret = Array.new
|
466
|
+
end
|
467
|
+
val = args[0]
|
468
|
+
stringIndex = args[1]
|
469
|
+
if branch.kind_of? Array
|
470
|
+
branch.each { |v|
|
471
|
+
LEON::gather_layouts(val, stringIndex, ret, v)
|
472
|
+
}
|
473
|
+
elsif branch.kind_of? Hash
|
474
|
+
ret.push Array.new
|
475
|
+
branch.each { |k, v|
|
476
|
+
if k.kind_of? Symbol
|
477
|
+
k = k.to_s
|
478
|
+
end
|
479
|
+
ret[ret.length - 1].push stringIndex.index(k)
|
480
|
+
}
|
481
|
+
branch.each { |k, v|
|
482
|
+
LEON::gather_layouts(val, stringIndex, ret, v)
|
483
|
+
}
|
484
|
+
end
|
485
|
+
return ret
|
486
|
+
end
|
487
|
+
def self.gather_strings(*args)
|
488
|
+
if args.length > 2
|
489
|
+
branch = args[2]
|
490
|
+
else
|
491
|
+
branch = args[0]
|
492
|
+
end
|
493
|
+
if args.length > 1
|
494
|
+
ret = args[1]
|
495
|
+
else
|
496
|
+
ret = Array.new
|
497
|
+
end
|
498
|
+
val = args[0]
|
499
|
+
if branch.kind_of? Array
|
500
|
+
branch.each { |v|
|
501
|
+
LEON::gather_strings(val, ret, v)
|
502
|
+
}
|
503
|
+
elsif branch.kind_of? Hash
|
504
|
+
branch.each { |k, v|
|
505
|
+
if k.kind_of? Symbol
|
506
|
+
k = k.to_s
|
507
|
+
end
|
508
|
+
set_push(ret, k)
|
509
|
+
}
|
510
|
+
branch.each { |k, v|
|
511
|
+
LEON::gather_strings(val, ret, v)
|
512
|
+
}
|
513
|
+
elsif branch.kind_of? String
|
514
|
+
set_push(ret, branch)
|
515
|
+
elsif branch.kind_of? Symbol
|
516
|
+
set_push(ret, branch.to_s)
|
517
|
+
end
|
518
|
+
return ret
|
519
|
+
end
|
520
|
+
def self.set_push(arr, v)
|
521
|
+
if !arr.include? v
|
522
|
+
arr.push v
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
data/lib/leon.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'constants'
|
2
|
+
require 'string-buffer'
|
3
|
+
require 'io'
|
4
|
+
module LEON
|
5
|
+
include Constants
|
6
|
+
class Channel
|
7
|
+
def initialize(spec)
|
8
|
+
@spec = spec
|
9
|
+
end
|
10
|
+
def generate(payload)
|
11
|
+
return Encoder.new(payload, @spec).writeData().export()
|
12
|
+
end
|
13
|
+
def parse(payload)
|
14
|
+
Parser.new(StringBuffer.new(payload), @spec).parseValueWithSpec()
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def self.parse(str)
|
18
|
+
Parser.new(StringBuffer.new(str)).parseSI().parseOLI().parseValue()
|
19
|
+
end
|
20
|
+
def self.generate(payload)
|
21
|
+
Encoder.new(payload).writeSI().writeOLI().writeData().export()
|
22
|
+
end
|
23
|
+
end
|
24
|
+
class Object
|
25
|
+
def to_leon()
|
26
|
+
LEON::generate(self)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
require 'constants'
|
2
|
+
|
3
|
+
module LEON
|
4
|
+
class StringBuffer
|
5
|
+
attr_accessor :buffer
|
6
|
+
def self.bytes(v, type)
|
7
|
+
ret = Array.new
|
8
|
+
if type === Constants::UNSIGNED_CHAR
|
9
|
+
ret.push v
|
10
|
+
return ret
|
11
|
+
end
|
12
|
+
if type === Constants::CHAR
|
13
|
+
return v < 0 ? StringBuffer.bytes(complement(-v, 8), Constants::UNSIGNED_CHAR) : StringBuffer.bytes(v, Constants::UNSIGNED_CHAR)
|
14
|
+
end
|
15
|
+
if type === Constants::UNSIGNED_SHORT
|
16
|
+
ret.push(v >> 8)
|
17
|
+
ret.push(v & 0xFF)
|
18
|
+
return ret
|
19
|
+
end
|
20
|
+
if type === Constants::SHORT
|
21
|
+
return v < 0 ? StringBuffer.bytes(complement(-v, 16), Constants::UNSIGNED_SHORT) : StringBuffer.bytes(v, Constants::UNSIGNED_SHORT)
|
22
|
+
end
|
23
|
+
if type === Constants::UNSIGNED_INT
|
24
|
+
ret.push(v >> 24)
|
25
|
+
ret.push((v >> 16) & 0xFF)
|
26
|
+
ret.push((v >> 8) & 0xFF)
|
27
|
+
ret.push(v & 0xFF)
|
28
|
+
return ret
|
29
|
+
end
|
30
|
+
if type === Constants::INT
|
31
|
+
return v < 0 ? StringBuffer.bytes(complement(-v, 32), Constants::UNSIGNED_INT) : StringBuffer.bytes(v, Constants::UNSIGNED_INT)
|
32
|
+
end
|
33
|
+
if type === Constants::FLOAT
|
34
|
+
exp = 127
|
35
|
+
if v < 0
|
36
|
+
sign = 1
|
37
|
+
else
|
38
|
+
sign = 0
|
39
|
+
end
|
40
|
+
v = v.abs
|
41
|
+
log = Math::log(v)/Math::log(2)
|
42
|
+
if log < 0
|
43
|
+
log = log.ceil
|
44
|
+
else
|
45
|
+
log = log.floor
|
46
|
+
end
|
47
|
+
v *= 2**(-log + 23)
|
48
|
+
exp += log
|
49
|
+
v = v.round
|
50
|
+
v &= 0x7FFFFF
|
51
|
+
ret.push(sign << 7)
|
52
|
+
ret[0] |= ((exp & 0xFE) >> 1)
|
53
|
+
ret.push((exp & 0x01) << 7)
|
54
|
+
ret[1] |= ((v >> 16) & 0x7F)
|
55
|
+
ret.push((v >> 8) & 0xFF)
|
56
|
+
ret.push(v & 0xFF)
|
57
|
+
return ret
|
58
|
+
end
|
59
|
+
if type === Constants::DOUBLE
|
60
|
+
exp = 1023
|
61
|
+
if v < 0
|
62
|
+
sign = 1
|
63
|
+
else
|
64
|
+
sign = 0
|
65
|
+
end
|
66
|
+
v = v.abs
|
67
|
+
log = Math::log(v)/Math::log(2)
|
68
|
+
if log < 0
|
69
|
+
log = log.ceil
|
70
|
+
else
|
71
|
+
log = log.floor
|
72
|
+
end
|
73
|
+
v *= 2**(-log + 52)
|
74
|
+
exp += log
|
75
|
+
str = v.to_int.to_s(2)
|
76
|
+
v = str[1..-1].to_i(2)
|
77
|
+
ret.push(sign << 7)
|
78
|
+
ret[0] |= (exp >> 4)
|
79
|
+
ret.push((exp & 0x0F) << 4)
|
80
|
+
ret[1] |= ((v*2**(-48)).floor & 0x0F)
|
81
|
+
sh = 40
|
82
|
+
for i in 0..5
|
83
|
+
ret.push((v*2**(-sh)).floor & 0xFF)
|
84
|
+
sh -= 8
|
85
|
+
end
|
86
|
+
return ret
|
87
|
+
end
|
88
|
+
end
|
89
|
+
def self.bytes_to_float(bytes)
|
90
|
+
sign = (0x80 & bytes[0]) >> 7
|
91
|
+
exp = ((bytes[0] & 0x7F) << 1) | ((bytes[1] & 0x80) >> 7)
|
92
|
+
sig = 0
|
93
|
+
bytes[1] &= 0x7F
|
94
|
+
for i in 0..2
|
95
|
+
sig |= bytes[1 + i]*2**((2 - i)*8)
|
96
|
+
end
|
97
|
+
sig |= 0x800000
|
98
|
+
return ((sign === 1 ? -sig : sig)*2**(exp - (127 + 23))).to_f
|
99
|
+
end
|
100
|
+
def self.bytes_to_double(bytes)
|
101
|
+
sign = (0x80 & bytes[0]) >> 7
|
102
|
+
exp = ((bytes[0] & 0x7F) << 4) | ((bytes[1] & 0xF0) >> 4)
|
103
|
+
sig = 0
|
104
|
+
bytes[1] &= 0x0F
|
105
|
+
for i in 0..6
|
106
|
+
sig += bytes[i + 1]*2**((6 - i)*8)
|
107
|
+
end
|
108
|
+
sig += 0x10000000000000
|
109
|
+
return ((sign === 1 ? -sig : sig)*2**(exp - (1023 + 52))).to_f
|
110
|
+
end
|
111
|
+
def self.complement(v, bits)
|
112
|
+
return (v ^ ((1 << bits) - 1)) + 1
|
113
|
+
end
|
114
|
+
def initialize(*args)
|
115
|
+
if args.length > 0
|
116
|
+
@buffer = args[0]
|
117
|
+
else
|
118
|
+
@buffer = ''
|
119
|
+
end
|
120
|
+
end
|
121
|
+
def self.concat(arr)
|
122
|
+
return arr.reduce(self.new) { |r, v|
|
123
|
+
r.buffer += v.buffer
|
124
|
+
r
|
125
|
+
}
|
126
|
+
end
|
127
|
+
def writeUInt8(v, i)
|
128
|
+
if i === -1 or i >= @buffer.length
|
129
|
+
@buffer += v.chr
|
130
|
+
else
|
131
|
+
@buffer = @buffer[0..i] + v.chr + @buffer[(i+1)..-1]
|
132
|
+
end
|
133
|
+
return i + 1
|
134
|
+
end
|
135
|
+
def writeInt8(v, i)
|
136
|
+
v = (v < 0 ? complement(-v, 8) : v)
|
137
|
+
return writeUInt8(v, i)
|
138
|
+
end
|
139
|
+
def writeUInt16LE(v, i)
|
140
|
+
bytez = StringBuffer.bytes(v, Constants::UNSIGNED_SHORT)
|
141
|
+
add = ''
|
142
|
+
bytez.reverse_each { |v|
|
143
|
+
add += "#{v.chr}"
|
144
|
+
}
|
145
|
+
if i >= @buffer.length or i === -1
|
146
|
+
@buffer += add
|
147
|
+
else
|
148
|
+
@buffer = @buffer[0..i] + add + @buffer[(i + 2)..-1]
|
149
|
+
end
|
150
|
+
return i + 2
|
151
|
+
end
|
152
|
+
def writeUInt16BE(v, i)
|
153
|
+
bytez = StringBuffer.bytes(v, Constants::UNSIGNED_SHORT)
|
154
|
+
add = ''
|
155
|
+
bytez.each { |v|
|
156
|
+
add += "#{v.chr}"
|
157
|
+
}
|
158
|
+
if i >= @buffer.length or i === -1
|
159
|
+
@buffer += add
|
160
|
+
else
|
161
|
+
@buffer = @buffer[0..i] + add + @buffer[(i + 2)..-1]
|
162
|
+
end
|
163
|
+
return i + 2
|
164
|
+
end
|
165
|
+
def writeInt16LE(v, i)
|
166
|
+
v = (v < 0 ? complement(-v, 16) : v)
|
167
|
+
return writeUInt16LE(v)
|
168
|
+
end
|
169
|
+
def writeInt16BE(v, i)
|
170
|
+
v = (v < 0 ? complement(-v, 16) : v)
|
171
|
+
return writeUInt16BE(v)
|
172
|
+
end
|
173
|
+
def writeUInt32LE(v, i)
|
174
|
+
bytez = StringBuffer.bytes(v, Constants::UNSIGNED_INT)
|
175
|
+
add = ''
|
176
|
+
bytez.reverse_each { |v|
|
177
|
+
add += "#{v.chr}"
|
178
|
+
}
|
179
|
+
if i >= @buffer.length or i === -1
|
180
|
+
@buffer += add
|
181
|
+
else
|
182
|
+
@buffer = @buffer[0..i] + add + @buffer[(i + 4)..-1]
|
183
|
+
end
|
184
|
+
return i + 4
|
185
|
+
end
|
186
|
+
def writeUInt32BE(v, i)
|
187
|
+
bytez = StringBuffer.bytes(v, Constants::UNSIGNED_INT)
|
188
|
+
add = ''
|
189
|
+
bytez.each { |v|
|
190
|
+
add += "#{v.chr}"
|
191
|
+
}
|
192
|
+
if i >= @buffer.length or i === -1
|
193
|
+
@buffer += add
|
194
|
+
else
|
195
|
+
@buffer = @buffer[0..i] + add + @buffer[(i + 4)..-1]
|
196
|
+
end
|
197
|
+
return i + 4
|
198
|
+
end
|
199
|
+
def writeInt32LE(v, i)
|
200
|
+
v = (v < 0 ? complement(-v, i) : v)
|
201
|
+
return writeUInt32LE(v)
|
202
|
+
end
|
203
|
+
def writeInt32BE(v, i)
|
204
|
+
v = (v < 0 ? complement(-v, i) : v)
|
205
|
+
return writeUInt32BE(v)
|
206
|
+
end
|
207
|
+
def writeFloatLE(v, i)
|
208
|
+
bytez = StringBuffer.bytes(v, Constants::FLOAT)
|
209
|
+
bytez.to_enum.with_index.reverse_each { |v, idx|
|
210
|
+
writeUInt8(v, i + (3 - idx))
|
211
|
+
}
|
212
|
+
return i + 4
|
213
|
+
end
|
214
|
+
def writeFloatBE(v, i)
|
215
|
+
bytez = StringBuffer.bytes(v, Constants::FLOAT)
|
216
|
+
bytez.to_enum.with_index.each { |v, idx|
|
217
|
+
writeUInt8(v, i + idx)
|
218
|
+
}
|
219
|
+
return i + 4
|
220
|
+
end
|
221
|
+
def writeDoubleLE(v, i)
|
222
|
+
bytez = StringBuffer.bytes(v, Constants::DOUBLE)
|
223
|
+
bytez.to_enum.with_index.reverse_each { |v, idx|
|
224
|
+
writeUInt8(v, i + (7 - idx))
|
225
|
+
}
|
226
|
+
return i + 8
|
227
|
+
end
|
228
|
+
def writeDoubleBE(v, i)
|
229
|
+
bytez = StringBuffer.bytes(v, Constants::DOUBLE)
|
230
|
+
bytez.to_enum.with_index.each { |v, idx|
|
231
|
+
writeUInt8(v, i + idx)
|
232
|
+
}
|
233
|
+
return i + 8
|
234
|
+
end
|
235
|
+
def readUInt8(i)
|
236
|
+
return @buffer[i].ord
|
237
|
+
end
|
238
|
+
def readInt8(i)
|
239
|
+
v = readUInt8(i)
|
240
|
+
if (0x80 & v) != 0
|
241
|
+
return -complement(v, 8)
|
242
|
+
end
|
243
|
+
return v
|
244
|
+
end
|
245
|
+
def readUInt16LE(i)
|
246
|
+
return @buffer[i].ord | (@buffer[i + 1].ord << 8)
|
247
|
+
end
|
248
|
+
def readUInt16BE(i)
|
249
|
+
return (@buffer[i].ord << 8) | @buffer[i + 1].ord
|
250
|
+
end
|
251
|
+
def readInt16LE(i)
|
252
|
+
v = readUInt16LE(i)
|
253
|
+
if (v & 0x8000) != 0
|
254
|
+
return -complement(v, 16)
|
255
|
+
end
|
256
|
+
return v
|
257
|
+
end
|
258
|
+
def readInt16BE(i)
|
259
|
+
v = readUInt16BE(i)
|
260
|
+
if (v & 0x8000) != 0
|
261
|
+
return -complement(v, 16)
|
262
|
+
end
|
263
|
+
return v
|
264
|
+
end
|
265
|
+
def readUInt32LE(i)
|
266
|
+
return @buffer[i].ord | (@buffer[i + 1].ord << 8) | (@buffer[i + 2].ord << 16) | (@buffer[i + 3].ord << 24)
|
267
|
+
end
|
268
|
+
def readUInt32BE(i)
|
269
|
+
return (@buffer[i].ord << 24) | (@buffer[i + 1].ord << 16) | (@buffer[i + 2].ord << 8) | @buffer[i + 3].ord
|
270
|
+
end
|
271
|
+
def readInt32LE(i)
|
272
|
+
v = readUInt32LE(i)
|
273
|
+
if (v & 0x80000000) != 0
|
274
|
+
return -complement(v, 32)
|
275
|
+
end
|
276
|
+
return v
|
277
|
+
end
|
278
|
+
def readInt32BE(i)
|
279
|
+
v = readUInt32BE(i)
|
280
|
+
if (v & 0x80000000) != 0
|
281
|
+
return -complement(v, 32)
|
282
|
+
end
|
283
|
+
return v
|
284
|
+
end
|
285
|
+
def readFloatLE(i)
|
286
|
+
bytez = Array.new
|
287
|
+
for j in 0..3
|
288
|
+
bytez.push readUInt8(i + j)
|
289
|
+
end
|
290
|
+
bytez.reverse!
|
291
|
+
return StringBuffer.bytes_to_float(bytez)
|
292
|
+
end
|
293
|
+
def readFloatBE(i)
|
294
|
+
bytez = Array.new
|
295
|
+
for j in 0..3
|
296
|
+
bytez.push readUInt8(i + j)
|
297
|
+
end
|
298
|
+
return StringBuffer.bytes_to_float(bytez)
|
299
|
+
end
|
300
|
+
def readDoubleLE(i)
|
301
|
+
bytez = Array.new
|
302
|
+
for j in 0..7
|
303
|
+
bytez.push readUInt8(i + j)
|
304
|
+
end
|
305
|
+
bytez.reverse!
|
306
|
+
return StringBuffer.bytes_to_double(bytez)
|
307
|
+
end
|
308
|
+
def readDoubleBE(i)
|
309
|
+
bytez = Array.new
|
310
|
+
for j in 0..7
|
311
|
+
bytez.push readUInt8(i + j)
|
312
|
+
end
|
313
|
+
return StringBuffer.bytes_to_double(bytez)
|
314
|
+
end
|
315
|
+
def toString()
|
316
|
+
return @buffer
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
data/lib/types.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module LEON
|
2
|
+
class Undefined
|
3
|
+
end
|
4
|
+
class NaN
|
5
|
+
end
|
6
|
+
class RegExp
|
7
|
+
attr_accessor :pattern
|
8
|
+
attr_accessor :modifier
|
9
|
+
def initialize(*args)
|
10
|
+
if args.length > 1
|
11
|
+
@modifier = args[1]
|
12
|
+
else
|
13
|
+
@modifier = ''
|
14
|
+
end
|
15
|
+
@pattern = args[0]
|
16
|
+
end
|
17
|
+
def to_s()
|
18
|
+
return '/' + @pattern + '/' + @modifier
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: leon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Raymond Pulver IV
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-07-19 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Serialize and deserialize all JavaScript data types to a more compact
|
15
|
+
format than JSON that can be dealt with in the browser.
|
16
|
+
email: raymond.pulver_iv@uconn.edu
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/buffer-iterator.rb
|
22
|
+
- lib/io.rb
|
23
|
+
- lib/string-buffer.rb
|
24
|
+
- lib/constants.rb
|
25
|
+
- lib/leon.rb
|
26
|
+
- lib/types.rb
|
27
|
+
homepage: http://github.com/raypulver/ruby-leon
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.23
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: LEON serialization for Ruby.
|
52
|
+
test_files: []
|