Atlas 0.7.0
Networking protocol for the Worldforge system.
binary1.py
1#Binary1 parser and generator
2#see forge/protocols/atlas/spec/binary1_beta.html
3#Note that variable length string/list/map are not yet supported in code!
4
5#Copyright 2001 by Aloril
6
7#This library is free software; you can redistribute it and/or
8#modify it under the terms of the GNU Lesser General Public
9#License as published by the Free Software Foundation; either
10#version 2.1 of the License, or (at your option) any later version.
11
12#This library is distributed in the hope that it will be useful,
13#but WITHOUT ANY WARRANTY; without even the implied warranty of
14#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15#Lesser General Public License for more details.
16
17#You should have received a copy of the GNU Lesser General Public
18#License along with this library; if not, write to the Free Software
19#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21
22import string
23from math import frexp, ldexp
24from atlas import Object, Messages
25from atlas.typemap import *
26
27user_type = 0
28int_pos_type = 1
29int_neg_type = 2
30float_pos_pos_type = 3
31float_pos_neg_type = 4
32float_neg_pos_type = 5
33float_neg_neg_type = 6
34float_special_type = 7
35string_type = 8
36list_type = 9
37map_type = 10
38variable_string_type = 11
39variable_list_type = 12
40variable_map_type = 13
41user_type = 14
42
43def gen_binary1(obj):
44 gen = GenerateBinary1()
45 return gen.encode(obj)
46
47def encode_pos_int(value):
48 res = ""
49 while 1:
50 v = value & 0x7F
51 if value>0x7F: v = v | 0x80
52 res = res + chr(v)
53 value = value >> 7
54 if not value: return res
55
56
58 def __init__(self):
59 self.type_name2binary1_code = {"map": self.encode_map,
60 "list": self.encode_list,
61 "int": self.encode_int,
62 "float": self.encode_float,
63 "string": self.encode_string}
64
65 def encode(self, value):
66 return self.type_name2binary1_code[get_atlas_type(value)](value)
67
68 def decode_pos_int(self, input):
69 value = 0
70 multiplier = 1
71 for ch in input:
72 value = value + (ord(ch) & ~0x80) * multiplier
73 multiplier = multiplier * 128
74 return value
75
76 def encode_name(self, value):
77 return encode_pos_int(len(value)) + value
78
79 def encode_string(self, value):
80 return encode_pos_int(string_type) + \
81 encode_pos_int(len(value)) + \
82 value
83
84 def encode_int(self, value):
85 if value>=0:
86 return encode_pos_int(int_pos_type) +\
87 encode_pos_int(value)
88 else:
89 return encode_pos_int(int_neg_type) +\
90 encode_pos_int(-value)
91
92 def encode_float(self, value):
93 mant, exp = frexp(value)
94 mant = int(mant *2**53)
95 exp = exp - 53
96 if mant>=0:
97 if exp>=0:
98 type_str = encode_pos_int(float_pos_pos_type)
99 else:
100 type_str = encode_pos_int(float_pos_neg_type)
101 exp = -exp
102 else:
103 mant = -mant
104 if exp>=0:
105 type_str = encode_pos_int(float_neg_pos_type)
106 else:
107 type_str = encode_pos_int(float_neg_neg_type)
108 exp = -exp
109 return type_str + \
110 encode_pos_int(mant) + \
111 encode_pos_int(exp)
112
113 def encode_attribute(self, name, value):
114 #CHEAT!: assuming that type code is 1 byte (which though always is true for binary1...)
115 str_name = self.encode_name(name)
116 str_value = self.encode(value)
117 return str_value[0] + str_name + str_value[1:]
118
119 def encode_map(self, obj):
120 str_list = [encode_pos_int(map_type) + encode_pos_int(len(obj))]
121 for name, value in list(obj.items()):
122 str_list.append(self.encode_attribute(name, value))
123 return string.join(str_list, "")
124
125 def encode_list(self, lst):
126 str_list = [encode_pos_int(list_type) + encode_pos_int(len(lst))]
127 for item in lst:
128 str_list.append(self.encode(item))
129 return string.join(str_list,"")
130
131
132
133class BinaryException(Exception): pass
134
136 def __init__(self, data_flag, value, decoder=None):
137 self.data_flag = data_flag
138 self.value = value
139 self.decoder = decoder
140 self.remaining = 0
141 self.name = None
142 self.is_mapping = 0
143 self.is_name = 0
144
146 def __init__(self):
147 """uses tree that start from root_obj, current route to leave
148 is kept in obj_stack"""
149 #Root object is never removed or visible for parser users,
150 #incoming objects are added to its value
151 self.stack = [Context(0, [], self.add_msg)]
152 #resulting complete atlas 'messages' are added here
153 self.msgList = []
154
155 def parse_stream(self, msg):
156 self.feed(msg)
157 res=Messages(*tuple(self.msgList))
158 self.msgList=[]
159 return res
160 __call__=parse_stream #this makes possible to call instance like
161 #it was function
162
163 def feed(self, msg):
164 #import pdb; pdb.set_trace()
165 for ch in msg:
166 if self.stack[-1].data_flag:
167 self.stack[-1].decoder(ch)
168 else:
169 getattr(self, self.type2init[ch].__name__)()
170 self.stack[-1].decoder = getattr(self, self.type2decoder[ch].__name__)
171 if self.stack[-2].is_mapping:
172 self.init_length()
173 self.stack[-1].decoder = self.decode_string_length
174 self.stack[-1].is_name = 1
175
176 def add_msg(self):
177 obj=self.stack[0].value.pop(0)
178 self.msgList.append(obj)
179
180 def start_value(self, initial_value):
181 c = Context(1, initial_value)
182 self.stack.append(c)
183
184 def value_done(self):
185 c = self.stack.pop()
186 if c.is_name:
187 self.stack[-1].name = c.value
188 else:
189 obj = self.stack[-1].value
190 if c.name!=None:
191 if not isinstance(obj, Object):
192 raise BinaryException("attribute outside mapping (%s:%s)!" % \
193 (c.name, c.value))
194 setattr(obj, c.name, c.value)
195 else:
196 if type(obj)!=ListType:
197 raise BinaryException("object not inside list (%s)!" % c.value)
198 obj.append(c.value)
199 self.stack[-1].decoder()
200
201 def decode_int_value(self, ch):
202 ch = ord(ch)
203 c = self.stack[-1]
204 c.value = c.value + (ch & ~0x80) * c.multiplier
205 c.multiplier = c.multiplier * 128
206 if not (ch & 0x80):
207 try:
208 c.value = int(c.value)
209 except OverflowError:
210 pass
211 return 1
212 return 0
213
214 def init_int_pos(self):
215 self.start_value(0)
216 self.stack[-1].multiplier = 1
217 def init_int_neg(self):
218 self.start_value(0)
219 self.stack[-1].multiplier = -1
220 def decode_int(self, ch):
221 if self.decode_int_value(ch):
222 self.value_done()
223
224 def init_float(self, multiplier1, multiplier2):
225 self.start_value(0)
226 self.stack[-1].multiplier = multiplier1
227 self.stack[-1].multiplier2 = multiplier2
228 def init_float_pos_pos(self):
229 self.init_float(1, 1)
230 def init_float_pos_neg(self):
231 self.init_float(1, -1)
232 def init_float_neg_pos(self):
233 self.init_float(-1, 1)
234 def init_float_neg_neg(self):
235 self.init_float(-1, -1)
236 def decode_float_mantissa(self, ch):
237 if self.decode_int_value(ch):
238 self.mantissa = self.stack[-1].value
239 self.stack[-1].value = 0
240 self.stack[-1].multiplier = self.stack[-1].multiplier2
241 self.stack[-1].decoder = self.decode_float_exponent
242 def decode_float_exponent(self, ch):
243 if self.decode_int_value(ch):
244 self.stack[-1].value = ldexp(self.mantissa, self.stack[-1].value)
245 self.value_done()
246
247 init_length = init_int_pos
248
249 def decode_string_length(self, ch):
250 if self.decode_int_value(ch):
251 self.stack[-1].remaining = int(self.stack[-1].value)
252 self.stack[-1].value = ""
253 if self.stack[-1].remaining:
254 self.stack[-1].decoder = self.decode_string_value
255 else:
256 self.value_done()
257 def decode_string_value(self, ch):
258 self.stack[-1].value = self.stack[-1].value + ch
259 self.stack[-1].remaining = self.stack[-1].remaining - 1
260 if not self.stack[-1].remaining:
261 self.value_done()
262
263
264 def init_collection(self, initial_value):
265 self.stack[-1].remaining = int(self.stack[-1].value)
266 self.stack[-1].value = initial_value
267 if self.stack[-1].remaining:
268 self.stack[-1].data_flag = 0
269 self.stack[-1].decoder = self.decode_collection_value
270 else:
271 self.value_done()
272 def decode_collection_value(self):
273 self.stack[-1].remaining = self.stack[-1].remaining - 1
274 if not self.stack[-1].remaining:
275 self.value_done()
276
277
278 def decode_list_length(self, ch):
279 if self.decode_int_value(ch):
280 self.init_collection([])
281
282 def decode_map_length(self, ch):
283 if self.decode_int_value(ch):
284 self.stack[-1].is_mapping = 1
285 self.init_collection(Object())
286
287 type2init = {encode_pos_int(int_pos_type): init_int_pos,
288 encode_pos_int(int_neg_type): init_int_neg,
289 encode_pos_int(float_pos_pos_type): init_float_pos_pos,
290 encode_pos_int(float_pos_neg_type): init_float_pos_neg,
291 encode_pos_int(float_neg_pos_type): init_float_neg_pos,
292 encode_pos_int(float_neg_neg_type): init_float_neg_neg,
293 encode_pos_int(string_type): init_length,
294 encode_pos_int(list_type): init_length,
295 encode_pos_int(map_type): init_length,
296 encode_pos_int(variable_string_type): init_length,
297 encode_pos_int(variable_list_type): init_length,
298 encode_pos_int(variable_map_type): init_length}
299
300 type2decoder = {encode_pos_int(int_pos_type): decode_int,
301 encode_pos_int(int_neg_type): decode_int,
302 encode_pos_int(float_pos_pos_type): decode_float_mantissa,
303 encode_pos_int(float_pos_neg_type): decode_float_mantissa,
304 encode_pos_int(float_neg_pos_type): decode_float_mantissa,
305 encode_pos_int(float_neg_neg_type): decode_float_mantissa,
306 encode_pos_int(string_type): decode_string_length,
307 encode_pos_int(list_type): decode_list_length,
308 encode_pos_int(map_type): decode_map_length,
309 encode_pos_int(variable_string_type): decode_string_length,
310 encode_pos_int(variable_list_type): decode_list_length,
311 encode_pos_int(variable_map_type): decode_map_length}
312
313def get_parser():
314 binary1_msg_parser=Binary1Parser()
315 return binary1_msg_parser
def decode_float_exponent(self, ch)
Definition: binary1.py:242
def decode_string_length(self, ch)
Definition: binary1.py:249
def init_float(self, multiplier1, multiplier2)
Definition: binary1.py:224
def init_collection(self, initial_value)
Definition: binary1.py:264
def start_value(self, initial_value)
Definition: binary1.py:180
def encode_attribute(self, name, value)
Definition: binary1.py:113
def encode_string(self, value)
Definition: binary1.py:79