aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2012-01-16 04:27:54 +0000
committerMike Buland <eichlan@xagasoft.com>2012-01-16 04:27:54 +0000
commitdfeb2636eb83098ebd621ce2add83ef9e256318f (patch)
tree5ef416c3410c97cfd95710413de46093e17231ae
parente3efaf2a9ad82deb1644ccab8c1469719a0c5b65 (diff)
downloadlibgats-dfeb2636eb83098ebd621ce2add83ef9e256318f.tar.gz
libgats-dfeb2636eb83098ebd621ce2add83ef9e256318f.tar.bz2
libgats-dfeb2636eb83098ebd621ce2add83ef9e256318f.tar.xz
libgats-dfeb2636eb83098ebd621ce2add83ef9e256318f.zip
Created python bindings. They use the classic python dump/load/dumps/loads
paradigm
-rw-r--r--python/gats.py215
-rwxr-xr-xpython/test.py13
2 files changed, 228 insertions, 0 deletions
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 @@
1import struct
2from cStringIO import StringIO
3import math
4
5_scalarMagic = float.fromhex('0x1.62e42fefa39efp+2')
6
7def loads( sIn ):
8 return load( StringIO( sIn ) )
9
10def dumps( obj ):
11 sTmp = StringIO()
12 dump( obj, sTmp )
13 return sTmp.getvalue()
14
15def load( sIn ):
16 # Scan for a valid packet header
17 while True:
18 version = sIn.read(1)
19 if len(version) == 0:
20 return None
21 version = ord(version[0])
22 if version != 0:
23 break
24
25 if version == 1:
26 size = struct.unpack('>I', sIn.read(4) )[0]
27 return _readObj( sIn )
28
29def dump( obj, sOut ):
30 sTmp = StringIO()
31 _writeObj( obj, sTmp )
32 sCore = sTmp.getvalue()
33 sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) )
34 sOut.write( sCore )
35
36def _readObj( sIn ):
37 t = sIn.read( 1 )
38 if t == 'i': # Integer
39 return _readPackedInt( sIn )
40 elif t == 's': # String
41 lng = _readPackedInt( sIn )
42 return sIn.read( lng )
43 elif t == '0': # Boolean false
44 return False
45 elif t == '1': # Boolean true
46 return True
47 elif t == 'l': # List
48 ret = []
49 while True:
50 value = _readObj( sIn )
51 if value is None:
52 return ret
53 ret.append( value )
54 elif t == 'd': # Dictionary
55 ret = {}
56 while True:
57 key = _readObj( sIn )
58 if key is None:
59 return ret
60 if not isinstance( key, str ):
61 raise Exception('Only strings can be used as keys in gats dictionaries')
62 value = _readObj( sIn );
63 ret[key] = value
64 elif t == 'f': # Float
65 pLng = _readPackedInt( sIn )
66 bNeg = False
67 if pLng < 0:
68 bNeg = True
69 pLng = -pLng
70
71 dValue = 0.0
72 dat = sIn.read( pLng )
73 for i in xrange(len(dat)-1,0,-1):
74 dValue = (dValue+ord(dat[i]))*(1.0/256.0)
75 dValue += ord(dat[0])
76 iScale = _readPackedInt( sIn )
77 dValue *= pow( 256.0, iScale )
78 if bNeg:
79 return -dValue
80 return dValue
81 elif t == 'F': # Exceptional float
82 st = sIn.read(1)
83 if st == 'N':
84 return float('-nan')
85 elif st == 'n':
86 return float('nan')
87 elif st == 'I':
88 return float('-inf')
89 elif st == 'i':
90 return float('inf')
91 elif st == 'Z':
92 return -0.0
93 elif st == 'z':
94 return 0.0
95 else:
96 raise Exception('Invalid exceptional float subtype found.')
97 elif t == 'e': # End marker
98 return None
99 else:
100 raise Exception('Invalid gats type discovered: ' + t)
101 return 'not implemented yet';
102
103def _writeObj( obj, sOut ):
104 if isinstance( obj, int ):
105 sOut.write('i')
106 _writePackedInt( obj, sOut )
107 elif isinstance( obj, str ):
108 sOut.write('s')
109 _writePackedInt( len(obj), sOut )
110 sOut.write( obj )
111 elif isinstance( obj, list ) or isinstance( obj, tuple ):
112 sOut.write('l')
113 for s in obj:
114 _writeObj( s, sOut )
115 sOut.write('e')
116 elif isinstance( obj, dict ):
117 sOut.write('d')
118 for key in obj.iterkeys():
119 _writeObj( key, sOut )
120 _writeObj( obj[key], sOut )
121 sOut.write('e')
122 elif isinstance( obj, bool ):
123 if obj == True:
124 sOut.write('1')
125 else:
126 sOut.write('0')
127 elif isinstance( obj, float ):
128 if math.isnan( obj ):
129 if math.copysign( 1.0, obj ) < 0.0:
130 sOut.write('FN')
131 else:
132 sOut.write('Fn')
133 elif math.isinf( obj ):
134 if math.copysign( 1.0, obj ) < 0.0:
135 sOut.write('FI')
136 else:
137 sOut.write('Fi')
138 elif obj == 0.0:
139 if math.copysign( 1.0, obj ) < 0.0:
140 sOut.write('FZ')
141 else:
142 sOut.write('Fz')
143 else:
144 sOut.write('f')
145 d = obj
146 bNeg = False
147 if d < 0.0:
148 bNeg = True
149 d = -d
150
151 iScale = int(math.log( d ) / _scalarMagic)
152 if iScale < 0:
153 iScale -= 1
154
155 sTmp = StringIO()
156
157 d /= pow( 256.0, iScale )
158 sTmp.write( chr( int(d) ) )
159 d -= int(d)
160 for j in xrange( 0, 150 ):
161 d = d*256.0
162 sTmp.write( chr(int(d)) )
163 d -= int(d)
164 if d == 0.0:
165 break
166
167 sTmp = sTmp.getvalue()
168 if bNeg:
169 _writePackedInt( -len(sTmp), sOut )
170 else:
171 _writePackedInt( len(sTmp), sOut )
172 sOut.write( sTmp )
173 _writePackedInt( iScale, sOut )
174 else:
175 raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj)))
176
177def _readPackedInt( sIn ):
178 bNeg = False
179
180 b = ord(sIn.read(1)[0])
181 bNeg = (b&0x40) == 0x40;
182 rOut = b&0x3F;
183
184 c = 0
185 while (b&0x80) == 0x80:
186 b = ord(sIn.read(1)[0])
187 rOut |= (b&0x7F)<<(6+7*c)
188 c += 1
189 if bNeg:
190 return -rOut
191 return rOut
192
193def _writePackedInt( iIn, sOut ):
194 if iIn < 0:
195 iIn = -iIn
196 b = iIn&0x3F
197 if iIn > b:
198 b |= 0x80 | 0x40
199 else:
200 b |= 0x40
201 else:
202 b = iIn&0x3F
203 if iIn > b:
204 b |= 0x80
205 sOut.write( chr( b ) )
206
207 iIn = iIn >> 6
208
209 while iIn > 0:
210 b = iIn&0x7F
211 if iIn > b:
212 b |= 0x80
213 sOut.write( chr( b ) )
214 iIn = iIn >> 7
215
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 @@
1#!/usr/bin/python
2
3import gats
4
5#print gats.load( open('test.gats', 'rb') )
6
7#gats.dump( 3.14159, open('out.gats', 'wb') )
8
9print gats.loads(
10 gats.dumps(
11 500.12345
12 )
13 )