Skip to content
Snippets Groups Projects
Select Git revision
  • 3de4b35ffa23c1deb5b28426d6c53f73811c00f3
  • master default protected
2 results

CBOR.py

Blame
  • user avatar
    John Doe authored
    260cdb71
    History
    CBOR.py 8.70 KiB
    '''
    SCHC compressor, Copyright (c) <2017><IMT Atlantique and Philippe Clavier>
    
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>
    '''
    #
    # CLASS CBOR
    #
    
    import struct
    from json import loads as json_loads
    from binascii import hexlify
    
    CBOR_POSITIVE = 0x00
    CBOR_NEGATIVE = 0x20
    CBOR_BITMAP = 0x40
    CBOR_STRING = 0x60
    CBOR_ARRAY= 0x80
    CBOR_PAIR = 0xA0
    CBOR_TAG = 0xC0
    CBOR_FLOAT = 0xE0
    
    json_elm = ""
    cbor_src = None
    cbor_ptr = 0
    
    class CBOR:
    
        def __init__(self,  value):
            self.buffer = b''
    
            if type(value) is int:
                if (value >= 0):
                    firstByte = CBOR_POSITIVE
                else:
                    firstByte = CBOR_NEGATIVE
                    value = -1 * value
                    value = value  - 1
    
                if (value < 24):
                    self.buffer = struct.pack('!B', firstByte | value)
                    return
                else:
                    # find the size in bit (first bit to the left != 0)
                    for i in range (63,  0,  -1):
                        if ((0x01 << i) & value):
                            break
    
                    if (i < 7):
                        l = 24
                        nb_byte = 1
                    elif (i < 15):
                        l = 25
                        nb_byte = 2
                    elif (i < 31):
                        l = 26
                        nb_byte = 4
                    elif (i <63):
                        l = 27
                        nb_byte = 8
                    else:
                        print('Too big number')
                        return
    
                    self.buffer = struct.pack('!B', firstByte | l)
    
    
                    for k in range (nb_byte,  0,  -1):
                        msk = 0xFF << 8*(k-1)
                        result = (value & msk) >> 8*(k-1)
                        self.buffer += struct.pack('!B', result)
    
                return #end of Int
    
            if type(value) is str:
                l = len (value)
                self.buffer = struct.pack('!B', (CBOR_STRING | l))
                self.buffer += value
    
                return  #end of string
    
            if type(value) is float:
                self.buffer = struct.pack('!Bf', (CBOR_FLOAT | 26), value) # 4 bytes length
                return
    
            if type(value) is list:
                    l = len(value)
                    if (l < 23):
                        self.buffer = struct.pack('!B', (CBOR_ARRAY | l))
                    else:
                        print('Too much elements')
                        return
                    for elm in value:
                        if type (elm) is CBOR:
                            self.buffer += elm.buffer
                        else:
                            c = CBOR(elm)
                            self.buffer += c.buffer
    
                    return # end of list
    
            if type(value) == dict:
                    l = len(value)
                    if (l < 23):
                        self.buffer = struct.pack('!B', (CBOR_PAIR | l))
                    else:
                        print('Too much elements')
                        return
                    for k, v in value.items():
                        if type(k) == CBOR:
                            self.buffer += k.buffer
                        else:
                            c = CBOR (k)
                            self.buffer += c.buffer
    
                        if type (v) == CBOR:
                            self.buffer += v.buffer
                        else:
                            c = CBOR(v)
                            self.buffer += c.buffer
    
                    return
    
    
    
        def addList(self, elm):
    
            nbElm = 0;
    
            if (self.buffer[0] & 0xE0 == CBOR_ARRAY):
                currentLength = self.buffer[0] & 0x1F
                if (currentLength < 24): #length on 1 Byte
                    nbElm = currentLength
                    self.buffer = self.buffer[1:]
                elif (currentLength == 24): # length on 2 bytes
                    nbElm = self.buffer[1]
                    self.buffer = self.buffer[2:]
                elif currentLength == 25:
                    nbElm = self.buffer[1]<< 8 + self.buffer[2]
                    self.buffer = self.buffer[3:]
                elif currentLength == 26:
                    nbElm = self.buffer[1]<<24 + self.buffer[2]<<16 + self.buffer[3]<< 8 + self.buffer[4]
                    self.buffer = self.buffer[5:]
                elif currentLength == 27:
                    nbElm = self.buffer[1]<<56 + self.buffer[2]<<48 + self.buffer[3]<< 40 + self.buffer[4]<<32 + \
                        self.buffer[5]<<24 + self.buffer[6]<<16 + self.buffer[7]<< 8 + self.buffer[8]
                    self.buffer = self.buffer[9:]
                else:
                    raise Exception ("Length not allowed")
    
                nbElm += 1
    
                if (nbElm < 24):
                    self.buffer = struct.pack('!B', CBOR_ARRAY | nbElm) + self.buffer
                elif nbElm < 0xFF:
                    self.buffer = struct.pack('!BB', CBOR_ARRAY | 24, nbElm) + self.buffer
                elif nbElm < 0xFFFF:
                    self.buffer = struct.pack('!BH', CBOR_ARRAY | 25, nbElm) + self.buffer
                elif nbElm < 0xFFFFFFFF:
                    self.buffer = struct.pack('!BL', CBOR_ARRAY | 26, nbElm) + self.buffer
                elif nbElm < 0xFFFFFFFFFFFFFFFF:
                    self.buffer = struct.pack('!BQ', CBOR_ARRAY | 27, nbElm) + self.buffer
    
                #self.buffer[0] =
    
                self.buffer += elm.buffer
    
            else:
                print ("KO")
    
    
        def length (self):
            return len(self.buffer)
    
        def value(self):
            return self.buffer
    
        def __str__(self):
            return "CBOR object: Len {} Value {}".format(len(self.buffer), hexlify(self.buffer))
    
    def dumps(value):
        return CBOR(value)
    
    def ctoj():
        global json_elm
        global cbor_ptr
        global cbor_src
    
        if (cbor_ptr < len(cbor_src)):
            c_type  = cbor_src[cbor_ptr] & 0b11100000
            c_len   = cbor_src[cbor_ptr] & 0b00011111
    
            cbor_ptr += 1
    
            if c_len > 23:
                real_size = 0x01 << (c_len - 24)
                if c_len < 28:
                    c_len = 0;
                    for i in range (0, real_size):
                        c_len <<= 8;
                        c_len += cbor_src[cbor_ptr]
                        cbor_ptr += 1
                else:
                    raise ValueError("size incorrect")
    
            if c_type == CBOR_POSITIVE:
                json_elm += str(c_len)
    
            elif c_type ==  CBOR_NEGATIVE:
                json_elm += "-"
                json_elm += str(c_len+1)
    
            elif c_type == CBOR_BITMAP:
                json_elm += 'b"'
                for i in range (0, c_len):
                    json_elm += str(cbor_src[cbor_ptr])
                    cbor_ptr == 1
                json_elm == '"'
    
            elif c_type == CBOR_STRING:
                json_elm += '"'
                for i in range (0, c_len):
                    json_elm += chr(cbor_src[cbor_ptr])
                    cbor_ptr += 1
                json_elm += '"'
    
            elif c_type == CBOR_ARRAY:
                json_elm += "["
                for i in range(0, c_len):
                    ctoj()
                    if i+1 < c_len: json_elm += ", "
                json_elm += "]"
    
            elif c_type == CBOR_PAIR:
                json_elm += "{"
                for i in range(0, c_len):
                    ctoj()
                    json_elm += ":"
                    ctoj()
                    if i+1 < c_len: json_elm += ", "
                json_elm += "}"
    
            elif c_type == CBOR_TAG:
                print ("skipping tag")
            elif c_type == CBOR_FLOAT:
                buf = struct.pack(">I", c_len)
                f = struct.unpack (">f", buf)
                json_elm += str (f[0])
                pass
    
        else:
            raise ValueError ("Lenght is incorrect")
    
    
    
    def loads(cbor_elm):
        if type(cbor_elm) in (CBOR, bytes):
            global json_elm
            global cbor_ptr
            global cbor_src
    
            json_elm = ""
            cbor_ptr = 0
            if type(cbor_elm) == CBOR:
                cbor_src = cbor_elm.value()
            elif type(cbor_elm) == bytes:
                cbor_src = cbor_elm
    
            ctoj ()
    
            return json_loads(json_elm)
        else:
            raise ValueError("Not a CBOR object")
    
    
    #
    #  END OF CLASS CBOR
    #
    
    if __name__ == "__main__":
        import binascii
    
        c = CBOR({"adb":1, "hello":"world", "rest":10000, "float":3.141592, "encore":[100, 1000, 10000, 100000, 10000000, 100000000, 1000000000, 10000000000]})
        print (binascii.hexlify(c.value()))
        j = loads(c)
    
        print (j)
    
        c2 = CBOR(10000000000)
        print (binascii.hexlify(c2.value()))