class WebPackage::CBOR

Concise Binary Object Representation tools.ietf.org/html/rfc7049

Constants

MAJOR_TYPES_RANGE

Major type 0: an unsigned integer. Major type 1: a negative integer. Major type 2: a byte string. Major type 3: a text string, Unicode characters that is encoded as UTF-8 [RFC3629]. Major type 4: an array of data items. Major type 5: a map of pairs of data items. Major type 6: optional semantic tagging of other major types. Major type 7: floating-point numbers and simple data types that need no content.

Public Instance Methods

generate(input) click to toggle source
# File lib/web_package/cbor.rb, line 17
def generate(input)
  generate_bytes(input).pack('C*')
end

Private Instance Methods

generate_bytes(input) click to toggle source

tools.ietf.org/html/rfc7049#section-2.1

# File lib/web_package/cbor.rb, line 24
def generate_bytes(input)
  case input
  when Hash
    input = input.dup.tap do |hsh|
      hsh.keys.each { |key| hsh[bin(key)] = hsh.delete(key) }
    end

    bytes = hsh_size(input)
    bytes[0] |= major_type(5)

    # The sorting rules are:
    #   * If two keys have different lengths, the shorter one sorts earlier;
    #   * If two keys have the same length, the one with the lower value
    #     in (byte-wise) lexical order sorts earlier.
    input.keys.sort_by { |key| [key.bytesize, *key.bytes] }.each do |key|
      bytes.concat generate_bytes(key)
      bytes.concat generate_bytes(input[key])
    end
  when String, Symbol
    input = input.to_s
    bytes = str_size(input)
    # rubocop: disable Style/IdenticalConditionalBranches
    # TODO: Use major_type(3) for non-binary strings.
    #       Right now all strings are encoded as byte strings because Chrome eats only such.
    #       So, we need to either proove wrong, or submit an issue to chromium dev.
    bytes[0] |= input.encoding == Encoding::BINARY ? major_type(2) : major_type(2)
    # rubocop: enable Style/IdenticalConditionalBranches
    bytes.concat input.bytes
  when Integer
    raise '[CBOR] Not implemented for negative integers' if input.negative?

    bytes = int_size(input)
    bytes[0] |= major_type(0) # a positive integer
  else
    raise "[CBOR] Not implemented for #{input.class} class"
  end

  bytes
end
hsh_size(hsh) click to toggle source
# File lib/web_package/cbor.rb, line 73
def hsh_size(hsh)
  size = hsh.size
  raise '[CBOR] Not implemented for the hash of size more than 23 pairs' unless size < 24

  [size]
end
int_size(num) click to toggle source
# File lib/web_package/cbor.rb, line 84
def int_size(num)
  case num
  when     0...   24 then [num]
  when    24... 2**8 then [24, *[num].pack('C').bytes]
  when  2**8...2**16 then [25, *[num].pack('S>').bytes]
  when 2**16...2**32 then [26, *[num].pack('L>').bytes]
  when 2**32...2**64 then [27, *[num].pack('Q>').bytes]
  else raise '[CBOR] Not implemented for integers greater than (2**64 - 1) bits'
  end
end
major_type(num) click to toggle source
# File lib/web_package/cbor.rb, line 64
def major_type(num)
  unless MAJOR_TYPES_RANGE.include? num
    raise "[CBOR] Cannot infer Major Type from int #{num}, which is outside of allowed range."
  end

  # the type takes up 3 most significant bits of first byte
  num << 5
end
str_size(s) click to toggle source
# File lib/web_package/cbor.rb, line 80
def str_size(s)
  int_size s.bytesize
end