From dfeb2636eb83098ebd621ce2add83ef9e256318f Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 16 Jan 2012 04:27:54 +0000 Subject: Created python bindings. They use the classic python dump/load/dumps/loads paradigm --- python/gats.py | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ python/test.py | 13 ++++ 2 files changed, 228 insertions(+) create mode 100644 python/gats.py create mode 100755 python/test.py (limited to 'python') diff --git a/python/gats.py b/python/gats.py new file mode 100644 index 0000000..7e66f52 --- /dev/null +++ b/python/gats.py @@ -0,0 +1,215 @@ +import struct +from cStringIO import StringIO +import math + +_scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') + +def loads( sIn ): + return load( StringIO( sIn ) ) + +def dumps( obj ): + sTmp = StringIO() + dump( obj, sTmp ) + return sTmp.getvalue() + +def load( sIn ): + # Scan for a valid packet header + while True: + version = sIn.read(1) + if len(version) == 0: + return None + version = ord(version[0]) + if version != 0: + break + + if version == 1: + size = struct.unpack('>I', sIn.read(4) )[0] + return _readObj( sIn ) + +def dump( obj, sOut ): + sTmp = StringIO() + _writeObj( obj, sTmp ) + sCore = sTmp.getvalue() + sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) + sOut.write( sCore ) + +def _readObj( sIn ): + t = sIn.read( 1 ) + if t == 'i': # Integer + return _readPackedInt( sIn ) + elif t == 's': # String + lng = _readPackedInt( sIn ) + return sIn.read( lng ) + elif t == '0': # Boolean false + return False + elif t == '1': # Boolean true + return True + elif t == 'l': # List + ret = [] + while True: + value = _readObj( sIn ) + if value is None: + return ret + ret.append( value ) + elif t == 'd': # Dictionary + ret = {} + while True: + key = _readObj( sIn ) + if key is None: + return ret + if not isinstance( key, str ): + raise Exception('Only strings can be used as keys in gats dictionaries') + value = _readObj( sIn ); + ret[key] = value + elif t == 'f': # Float + pLng = _readPackedInt( sIn ) + bNeg = False + if pLng < 0: + bNeg = True + pLng = -pLng + + dValue = 0.0 + dat = sIn.read( pLng ) + for i in xrange(len(dat)-1,0,-1): + dValue = (dValue+ord(dat[i]))*(1.0/256.0) + dValue += ord(dat[0]) + iScale = _readPackedInt( sIn ) + dValue *= pow( 256.0, iScale ) + if bNeg: + return -dValue + return dValue + elif t == 'F': # Exceptional float + st = sIn.read(1) + if st == 'N': + return float('-nan') + elif st == 'n': + return float('nan') + elif st == 'I': + return float('-inf') + elif st == 'i': + return float('inf') + elif st == 'Z': + return -0.0 + elif st == 'z': + return 0.0 + else: + raise Exception('Invalid exceptional float subtype found.') + elif t == 'e': # End marker + return None + else: + raise Exception('Invalid gats type discovered: ' + t) + return 'not implemented yet'; + +def _writeObj( obj, sOut ): + if isinstance( obj, int ): + sOut.write('i') + _writePackedInt( obj, sOut ) + elif isinstance( obj, str ): + sOut.write('s') + _writePackedInt( len(obj), sOut ) + sOut.write( obj ) + elif isinstance( obj, list ) or isinstance( obj, tuple ): + sOut.write('l') + for s in obj: + _writeObj( s, sOut ) + sOut.write('e') + elif isinstance( obj, dict ): + sOut.write('d') + for key in obj.iterkeys(): + _writeObj( key, sOut ) + _writeObj( obj[key], sOut ) + sOut.write('e') + elif isinstance( obj, bool ): + if obj == True: + sOut.write('1') + else: + sOut.write('0') + elif isinstance( obj, float ): + if math.isnan( obj ): + if math.copysign( 1.0, obj ) < 0.0: + sOut.write('FN') + else: + sOut.write('Fn') + elif math.isinf( obj ): + if math.copysign( 1.0, obj ) < 0.0: + sOut.write('FI') + else: + sOut.write('Fi') + elif obj == 0.0: + if math.copysign( 1.0, obj ) < 0.0: + sOut.write('FZ') + else: + sOut.write('Fz') + else: + sOut.write('f') + d = obj + bNeg = False + if d < 0.0: + bNeg = True + d = -d + + iScale = int(math.log( d ) / _scalarMagic) + if iScale < 0: + iScale -= 1 + + sTmp = StringIO() + + d /= pow( 256.0, iScale ) + sTmp.write( chr( int(d) ) ) + d -= int(d) + for j in xrange( 0, 150 ): + d = d*256.0 + sTmp.write( chr(int(d)) ) + d -= int(d) + if d == 0.0: + break + + sTmp = sTmp.getvalue() + if bNeg: + _writePackedInt( -len(sTmp), sOut ) + else: + _writePackedInt( len(sTmp), sOut ) + sOut.write( sTmp ) + _writePackedInt( iScale, sOut ) + else: + raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) + +def _readPackedInt( sIn ): + bNeg = False + + b = ord(sIn.read(1)[0]) + bNeg = (b&0x40) == 0x40; + rOut = b&0x3F; + + c = 0 + while (b&0x80) == 0x80: + b = ord(sIn.read(1)[0]) + rOut |= (b&0x7F)<<(6+7*c) + c += 1 + if bNeg: + return -rOut + return rOut + +def _writePackedInt( iIn, sOut ): + if iIn < 0: + iIn = -iIn + b = iIn&0x3F + if iIn > b: + b |= 0x80 | 0x40 + else: + b |= 0x40 + else: + b = iIn&0x3F + if iIn > b: + b |= 0x80 + sOut.write( chr( b ) ) + + iIn = iIn >> 6 + + while iIn > 0: + b = iIn&0x7F + if iIn > b: + b |= 0x80 + sOut.write( chr( b ) ) + iIn = iIn >> 7 + diff --git a/python/test.py b/python/test.py new file mode 100755 index 0000000..14e8306 --- /dev/null +++ b/python/test.py @@ -0,0 +1,13 @@ +#!/usr/bin/python + +import gats + +#print gats.load( open('test.gats', 'rb') ) + +#gats.dump( 3.14159, open('out.gats', 'wb') ) + +print gats.loads( + gats.dumps( + 500.12345 + ) + ) -- cgit v1.2.3