diff options
author | Mike Buland <eichlan@xagasoft.com> | 2012-01-16 04:27:54 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2012-01-16 04:27:54 +0000 |
commit | dfeb2636eb83098ebd621ce2add83ef9e256318f (patch) | |
tree | 5ef416c3410c97cfd95710413de46093e17231ae | |
parent | e3efaf2a9ad82deb1644ccab8c1469719a0c5b65 (diff) | |
download | libgats-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.py | 215 | ||||
-rwxr-xr-x | python/test.py | 13 |
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 @@ | |||
1 | import struct | ||
2 | from cStringIO import StringIO | ||
3 | import math | ||
4 | |||
5 | _scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') | ||
6 | |||
7 | def loads( sIn ): | ||
8 | return load( StringIO( sIn ) ) | ||
9 | |||
10 | def dumps( obj ): | ||
11 | sTmp = StringIO() | ||
12 | dump( obj, sTmp ) | ||
13 | return sTmp.getvalue() | ||
14 | |||
15 | def 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 | |||
29 | def 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 | |||
36 | def _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 | |||
103 | def _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 | |||
177 | def _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 | |||
193 | def _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 | |||
3 | import gats | ||
4 | |||
5 | #print gats.load( open('test.gats', 'rb') ) | ||
6 | |||
7 | #gats.dump( 3.14159, open('out.gats', 'wb') ) | ||
8 | |||
9 | print gats.loads( | ||
10 | gats.dumps( | ||
11 | 500.12345 | ||
12 | ) | ||
13 | ) | ||