class Mmdb::Decoder
Constants
- METADATA_BEGIN
- Node
- POINTER_BASE_VALUES
- SIZE_BASE_VALUES
- TYPES
Attributes
data[R]
Public Class Methods
new(data)
click to toggle source
# File lib/mmdb/decoder.rb, line 5 def initialize(data) @data = data end
Public Instance Methods
decode(position:, base:)
click to toggle source
# File lib/mmdb/decoder.rb, line 56 def decode(position:, base:) ctrl = data[position + base].ord type = ctrl >> 5 position += 1 if type == POINTER decode_pointer(position, base, ctrl) else if type == EXTENDED_TYPE type = 7 + data[position + base].ord position += 1 end size = ctrl & 0x1f if size >= 29 byte_size = size - 29 + 1 val = fetch(position, base, byte_size) position += byte_size size = val + SIZE_BASE_VALUES[byte_size] end case type when UTF8 val = data[position + base, size].encode('utf-8', 'utf-8') Node.new(position + size, val) when DOUBLE val = data[position + base, size].unpack('G')[0] Node.new(position + size, val) when BYTE val = data[position + base, size] Node.new(position + size, val) when UINT16, UINT32, UINT64, UINT128 val = fetch(position, base, size) Node.new(position + size, val) when MAP val = size.times.each_with_object({}) do |_, map| key_node = decode(position: position, base: base) val_node = decode(position: key_node.position, base: base) position = val_node.position map[key_node.value] = val_node.value end Node.new(position, val) when INT32 v1 = data[position + base, size].unpack('N')[0] bits = size * 8 val = (v1 & ~(1 << bits)) - (v1 & (1 << bits)) Node.new(position + size, val) when ARRAY val = Array.new(size) do node = decode(position: position, base: base) position = node.position node.value end Node.new(position, val) when DATA_CACHE_CONTAINER raise 'TODO:' when END_MARKER Node.new(position, nil) when BOOLEAN Node.new(position, !size.zero?) when FLOAT val = data[position + base, size].unpack('g')[0] Node.new(position + size, val) end end end
ip_version()
click to toggle source
# File lib/mmdb/decoder.rb, line 23 def ip_version metadata['ip_version'] end
metadata()
click to toggle source
# File lib/mmdb/decoder.rb, line 9 def metadata @metadata ||= begin index = data.rindex(METADATA_BEGIN) raise InvalidFileFormat if index.nil? decode(position: index + METADATA_BEGIN.size, base: 0).value end end
node_byte_size()
click to toggle source
# File lib/mmdb/decoder.rb, line 31 def node_byte_size @node_byte_size ||= metadata['record_size'] * 2 / 8 end
node_count()
click to toggle source
# File lib/mmdb/decoder.rb, line 27 def node_count metadata['node_count'] end
read(node:, flag:)
click to toggle source
# File lib/mmdb/decoder.rb, line 43 def read(node:, flag:) position = node_byte_size * node middle = data[position + record_byte_size].ord if node_byte_size.odd? if flag.zero? # LEFT node val = fetch(position, 0) val += ((middle & 0xf0) << 20) if middle else # RIGHT node val = fetch(position + node_byte_size - record_byte_size, 0) val += ((middle & 0xf) << 24) if middle end val end
record_byte_size()
click to toggle source
# File lib/mmdb/decoder.rb, line 39 def record_byte_size @record_byte_size ||= node_byte_size / 2 end
search_tree_size()
click to toggle source
# File lib/mmdb/decoder.rb, line 35 def search_tree_size @search_tree_size ||= node_count * node_byte_size end
start_index()
click to toggle source
# File lib/mmdb/decoder.rb, line 19 def start_index @start_index ||= ip_version == 4 ? 96 : 0 end
Private Instance Methods
decode_pointer(position, base, ctrl)
click to toggle source
# File lib/mmdb/decoder.rb, line 150 def decode_pointer(position, base, ctrl) size = ((ctrl >> 3) & 0x3) + 1 v1 = ctrl & 0x7 v2 = fetch(position, base, size) pointer = (v1 << (8 * size)) + v2 + POINTER_BASE_VALUES[size] Node.new(position + size, decode(position: pointer, base: base).value) end
fetch(position, base, size = record_byte_size)
click to toggle source
# File lib/mmdb/decoder.rb, line 158 def fetch(position, base, size = record_byte_size) bytes = data[position + base, size].unpack('C*') bytes.inject(0) { |r, v| (r << 8) + v } end