Module: MPQ::JSONish

Defined in:
lib/jsonish.rb

Class Method Summary collapse

Class Method Details

.parse(data) ⇒ Object

‘parse` is the public API here, the following two methods are simply helpers.



10
11
12
# File 'lib/jsonish.rb', line 10

def self.parse data
  self.parse_recur String.new data
end

.parse_recur(data) ⇒ Object

JSONish consists of strings, arrays, maps, and integers. The first byte of each of these indicates which is about to follow.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/jsonish.rb', line 16

def self.parse_recur data
  case data.slice!(0).bytes.next

  # `02` indicates a string. The next byte is a variable-length integer 
  # (see below) indicating the string's length, and the remaining bytes are 
  # the string itself.
  when 2
    data.slice! 0, vlf(data)

  # `04` is an array, a list of values. Each value indicates its type, so 
  # this is largely just a recursive process.
  when 4
    data.slice! 0, 2
    (0...vlf(data)).map {|i| parse_recur data }

  # `05` starts a map, also known as a Hash or an object literal. It maps 
  # keys to values. In JSONish, keys are always variable-length integers, 
  # while values can be anything.
  when 5
    Hash.[]((0...vlf(data)).map do |i| 
      [vlf(data), parse_recur(data)]
    end)

  # `06` is a single-byte integer.
  when 6
    data.slice! 0

  # `07` is a four-byte integer in little-endian format.
  when 7
    data.slice!(0, 4).unpack("V")[0]

  # `09` is a standalone (i.e. not a key or length) variable-length integer.
  when 9
    vlf data

  # If there are other types in JSONish, we don't know about them.
  else
    nil
  end
end

.vlf(data) ⇒ Object

A variable-length integer is a concise serialization of an arbitrary-precision integer. Each byte (except the last) sets the high bit to ‘1` to indicate that the next byte is included in the integer. Seven bits of each byte, plus all eight bits of the final byte, make up the final number in little-endian format.



62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/jsonish.rb', line 62

def self.vlf data
  ret, shift = 0, 0
  loop do
    char = data.slice!(0)
    return nil unless char
    byte = char.bytes.next
    ret += (byte & 0x7F) << (7 * shift)
    break if byte & 0x80 == 0
    shift += 1
  end
  (ret >> 1) * ((ret & 0x1) == 0 ? 1 : -1)
end