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 
22 import string
23 from math import frexp, ldexp
24 from atlas import Object, Messages
25 from atlas.typemap import *
26 
27 user_type = 0
28 int_pos_type = 1
29 int_neg_type = 2
30 float_pos_pos_type = 3
31 float_pos_neg_type = 4
32 float_neg_pos_type = 5
33 float_neg_neg_type = 6
34 float_special_type = 7
35 string_type = 8
36 list_type = 9
37 map_type = 10
38 variable_string_type = 11
39 variable_list_type = 12
40 variable_map_type = 13
41 user_type = 14
42 
43 def gen_binary1(obj):
44  gen = GenerateBinary1()
45  return gen.encode(obj)
46 
47 def 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_codetype_name2binary1_code = {"map": self.encode_mapencode_map,
60  "list": self.encode_listencode_list,
61  "int": self.encode_intencode_int,
62  "float": self.encode_floatencode_float,
63  "string": self.encode_stringencode_string}
64 
65  def encode(self, value):
66  return self.type_name2binary1_codetype_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_nameencode_name(name)
116  str_value = self.encodeencode(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_attributeencode_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.encodeencode(item))
129  return string.join(str_list,"")
130 
131 
132 
133 class BinaryException(Exception): pass
134 
135 class Context:
136  def __init__(self, data_flag, value, decoder=None):
137  self.data_flagdata_flag = data_flag
138  self.valuevalue = value
139  self.decoderdecoder = decoder
140  self.remainingremaining = 0
141  self.namename = None
142  self.is_mappingis_mapping = 0
143  self.is_nameis_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.stackstack = [Context(0, [], self.add_msgadd_msg)]
152  #resulting complete atlas 'messages' are added here
153  self.msgListmsgList = []
154 
155  def parse_stream(self, msg):
156  self.feedfeed(msg)
157  res=Messages(*tuple(self.msgListmsgList))
158  self.msgListmsgList=[]
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.stackstack[-1].data_flag:
167  self.stackstack[-1].decoder(ch)
168  else:
169  getattr(self, self.type2inittype2init[ch].__name__)()
170  self.stackstack[-1].decoder = getattr(self, self.type2decodertype2decoder[ch].__name__)
171  if self.stackstack[-2].is_mapping:
172  self.init_lengthinit_length()
173  self.stackstack[-1].decoder = self.decode_string_lengthdecode_string_length
174  self.stackstack[-1].is_name = 1
175 
176  def add_msg(self):
177  obj=self.stackstack[0].value.pop(0)
178  self.msgListmsgList.append(obj)
179 
180  def start_value(self, initial_value):
181  c = Context(1, initial_value)
182  self.stackstack.append(c)
183 
184  def value_done(self):
185  c = self.stackstack.pop()
186  if c.is_name:
187  self.stackstack[-1].name = c.value
188  else:
189  obj = self.stackstack[-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.stackstack[-1].decoder()
200 
201  def decode_int_value(self, ch):
202  ch = ord(ch)
203  c = self.stackstack[-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_valuestart_value(0)
216  self.stackstack[-1].multiplier = 1
217  def init_int_neg(self):
218  self.start_valuestart_value(0)
219  self.stackstack[-1].multiplier = -1
220  def decode_int(self, ch):
221  if self.decode_int_valuedecode_int_value(ch):
222  self.value_donevalue_done()
223 
224  def init_float(self, multiplier1, multiplier2):
225  self.start_valuestart_value(0)
226  self.stackstack[-1].multiplier = multiplier1
227  self.stackstack[-1].multiplier2 = multiplier2
228  def init_float_pos_pos(self):
229  self.init_floatinit_float(1, 1)
230  def init_float_pos_neg(self):
231  self.init_floatinit_float(1, -1)
232  def init_float_neg_pos(self):
233  self.init_floatinit_float(-1, 1)
234  def init_float_neg_neg(self):
235  self.init_floatinit_float(-1, -1)
236  def decode_float_mantissa(self, ch):
237  if self.decode_int_valuedecode_int_value(ch):
238  self.mantissamantissa = self.stackstack[-1].value
239  self.stackstack[-1].value = 0
240  self.stackstack[-1].multiplier = self.stackstack[-1].multiplier2
241  self.stackstack[-1].decoder = self.decode_float_exponentdecode_float_exponent
242  def decode_float_exponent(self, ch):
243  if self.decode_int_valuedecode_int_value(ch):
244  self.stackstack[-1].value = ldexp(self.mantissamantissa, self.stackstack[-1].value)
245  self.value_donevalue_done()
246 
247  init_length = init_int_pos
248 
249  def decode_string_length(self, ch):
250  if self.decode_int_valuedecode_int_value(ch):
251  self.stackstack[-1].remaining = int(self.stackstack[-1].value)
252  self.stackstack[-1].value = ""
253  if self.stackstack[-1].remaining:
254  self.stackstack[-1].decoder = self.decode_string_valuedecode_string_value
255  else:
256  self.value_donevalue_done()
257  def decode_string_value(self, ch):
258  self.stackstack[-1].value = self.stackstack[-1].value + ch
259  self.stackstack[-1].remaining = self.stackstack[-1].remaining - 1
260  if not self.stackstack[-1].remaining:
261  self.value_donevalue_done()
262 
263 
264  def init_collection(self, initial_value):
265  self.stackstack[-1].remaining = int(self.stackstack[-1].value)
266  self.stackstack[-1].value = initial_value
267  if self.stackstack[-1].remaining:
268  self.stackstack[-1].data_flag = 0
269  self.stackstack[-1].decoder = self.decode_collection_valuedecode_collection_value
270  else:
271  self.value_donevalue_done()
272  def decode_collection_value(self):
273  self.stackstack[-1].remaining = self.stackstack[-1].remaining - 1
274  if not self.stackstack[-1].remaining:
275  self.value_donevalue_done()
276 
277 
278  def decode_list_length(self, ch):
279  if self.decode_int_valuedecode_int_value(ch):
280  self.init_collectioninit_collection([])
281 
282  def decode_map_length(self, ch):
283  if self.decode_int_valuedecode_int_value(ch):
284  self.stackstack[-1].is_mapping = 1
285  self.init_collectioninit_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 
313 def 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