Skip to content

Instantly share code, notes, and snippets.

@peteroupc
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peteroupc/58fd4a29d83fcb7cd0c9 to your computer and use it in GitHub Desktop.
Save peteroupc/58fd4a29d83fcb7cd0c9 to your computer and use it in GitHub Desktop.
Ruby JSON-to-CBOR converter, also intended to demonstrate an issue
# Written by Peter O. in 2014.
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
#
# If you like this, you should donate to Peter O.
# at: http://upokecenter.com/d/
require 'json'
module JCBOR
private
def self._length2cbor(len, mtype, output)
raise "error writing" if len<0
ax=len
if ax<24
output << [mtype|ax].pack("C")
elsif ax<256
output << [mtype|0x18, ax].pack("CC")
elsif ax<65536
output << [mtype|0x19, ax].pack("Cn")
elsif ax<=0xFFFFFFFF
output << [mtype|0x1A, ax].pack("CN")
elsif ax<=0xFFFFFFFFFFFFFFFF
hi=(ax>>32)&0xFFFFFFFF
lo=(ax)&0xFFFFFFFF
output << [mtype|0x1B, hi, lo].pack("CN*")
else
raise "length bigger than supported"
end
end
def self._json2cbor(x, output)
if x==false
output << 0xF4.chr
return
elsif x==true
output << 0xF5.chr
return
elsif x==nil
output << 0xF6.chr
return
elsif x.is_a?(Numeric)
if x.to_i==x
ax=(x<0) ? (-x)-1 : x
mtype=(x<0) ? 0x20 : 0
if ax<24
output << [mtype|ax].pack("C")
elsif ax<256
output << [mtype|0x18, ax].pack("CC")
elsif ax<65536
output << [mtype|0x19, ax].pack("Cn")
elsif ax<=0xFFFFFFFF
output << [mtype|0x1A, ax].pack("CN")
else
output << [0xFB, x.to_f].pack("CG")
end
else
output << [0xFB, x.to_f].pack("CG")
end
elsif x.is_a?(String)
x2=x.encode("UTF-8")
self._length2cbor(x2.bytesize,0x60,output)
output << x2
elsif x.is_a?(Hash)
self._length2cbor(x.length,0xa0,output)
x.keys.each{|item|
self._json2cbor(item,output)
self._json2cbor(x[item],output)
}
elsif x.is_a?(Array)
self._length2cbor(x.length,0x80,output)
x.each{|item| self._json2cbor(item,output) }
else
raise "unsupported object"
end
end
public
def self.json2cbor(x, output)
if !x[/\A\ufeff?\s*[\[\{]/]
# Unfortunately, JSON.parse doesn't accept non-object,
# non-array strings, as are now allowed in the latest JSON RFC,
# so we use this workaround
json=JSON.parse("["+x+"]")
self._json2cbor(json[0],output)
else
json=JSON.parse(x)
self._json2cbor(json,output)
end
end
end
# Generate a fake document as a demonstration
x=[]
for i in 0...1000
y={}
y["item1"]="itemitemitemitem"
y["item2"]=true
y["item3"]=999999999
y["item4"]="itemitemitemitem"
y["item5"]=["itemitemitemitem"]
x.push(y)
end
json=JSON.generate(x)
File.open("document.cbor","wb"){|f|
JCBOR.json2cbor(json,f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment