added update for Italian translation by Apmox
[twcon.git] / scripts / netobj.py
blobd8c5a7cd66166d41df0bcf112cf3b084a520dfe3
1 import sys, os
3 line_count = 0
5 class variable:
6 name = "unknown"
7 def __init__(self, args, name):
8 global line_count
9 self.name = name
10 self.line = line_count
11 def emit_declaration(self):
12 return ["\tint %s;" % self.name]
13 def linedef(self):
14 return "#line %d" % self.line
15 def emit_secure(self, parent):
16 return []
17 def emit_unpack(self):
18 return ["msg.%s = msg_unpack_int();" % self.name]
19 def emit_unpack_check(self):
20 return []
21 def emit_pack(self):
22 return ["\t\tmsg_pack_int(%s);" % self.name]
24 class var_any(variable):
25 def __init__(self, args, name):
26 variable.__init__(self, args, name)
28 class var_range(variable):
29 def __init__(self, args, name):
30 variable.__init__(self, args, name)
31 self.min = args[0]
32 self.max = args[1]
33 def emit_unpack_check(self):
34 return ["if(msg.%s < %s || msg.%s > %s) { msg_failed_on = \"%s\"; return 0; }" % (self.name, self.min, self.name, self.max, self.name)]
35 def emit_secure(self, parent):
36 return [self.linedef(), "obj->%s = netobj_clamp_int(\"%s.%s\", obj->%s, %s, %s);" % (self.name, parent.name, self.name, self.name, self.min, self.max)]
38 class var_string(variable):
39 def __init__(self, args, name):
40 variable.__init__(self, args, name)
42 class var_string(variable):
43 def __init__(self, args, name):
44 variable.__init__(self, args, name)
45 def emit_declaration(self):
46 return ["\tconst char *%s;" % self.name]
47 def emit_unpack(self):
48 return ["msg.%s = msg_unpack_string();" % self.name]
49 def emit_pack(self):
50 return ["\t\tmsg_pack_string(%s, -1);" % self.name]
52 class object:
53 def __init__(self, line):
54 fields = line.split()
55 self.name = fields[1]
56 self.extends = None
57 if len(fields) == 4 and fields[2] == "extends":
58 self.extends = fields[3]
59 self.enum_name = "NETOBJTYPE_%s" % self.name.upper()
60 self.struct_name = "NETOBJ_%s" % self.name.upper()
61 self.members = []
63 def parse(self, lines):
64 global line_count
65 for index in xrange(0, len(lines)):
66 line_count += 1
67 line = lines[index]
68 if not len(line):
69 continue
71 if line == "end":
72 return lines[index+1:]
73 else:
74 # check for argument
75 fields = line.split(")", 1)
76 if len(fields) == 2:
77 names = [line.strip() for line in fields[1].split(",")]
78 l = fields[0].split("(", 1)
79 type = l[0]
80 args = [line.strip() for line in l[1].split(",")]
81 else:
82 l = fields[0].split(None, 1)
83 type = l[0]
84 args = []
85 names = [line.strip() for line in l[1].split(",")]
87 for name in names:
88 create_string = 'var_%s(%s, "%s")' % (type, args, name)
89 new_member = eval(create_string)
90 self.members += [new_member]
92 raise BaseException("Parse error")
94 def emit_declaration(self):
95 lines = []
96 if self.extends:
97 lines += ["struct %s : public NETOBJ_%s\n {" % (self.struct_name, self.extends.upper())]
98 else:
99 lines += ["struct %s\n {" % self.struct_name]
100 for m in self.members:
101 lines += m.emit_declaration()
102 lines += ["};"]
103 return lines
105 def emit_secure(self):
106 lines = []
107 for m in self.members:
108 lines += m.emit_secure(self)
109 return lines
111 class message:
112 def __init__(self, line):
113 fields = line.split()
114 self.name = fields[1]
115 self.enum_name = "NETMSGTYPE_%s" % self.name.upper()
116 self.struct_name = "NETMSG_%s" % self.name.upper()
117 self.members = []
119 def parse(self, lines):
120 global line_count
121 for index in xrange(0, len(lines)):
122 line_count += 1
123 line = lines[index]
124 if not len(line):
125 continue
127 if line == "end":
128 return lines[index+1:]
129 else:
130 # check for argument
131 fields = line.split(")", 1)
132 if len(fields) == 2:
133 names = [line.strip() for line in fields[1].split(",")]
134 l = fields[0].split("(", 1)
135 type = l[0]
136 args = [line.strip() for line in l[1].split(",")]
137 else:
138 l = fields[0].split(None, 1)
139 type = l[0]
140 args = []
141 names = [line.strip() for line in l[1].split(",")]
143 for name in names:
144 create_string = 'var_%s(%s, "%s")' % (type, args, name)
145 new_member = eval(create_string)
146 self.members += [new_member]
148 raise BaseException("Parse error")
150 def emit_declaration(self):
151 lines = []
152 lines += ["struct %s\n {" % self.struct_name]
153 for m in self.members:
154 lines += m.emit_declaration()
155 lines += ["\tvoid pack(int flags)"]
156 lines += ["\t{"]
157 lines += ["\t\tmsg_pack_start(%s, flags);" % self.enum_name]
158 for m in self.members:
159 lines += m.emit_pack()
160 lines += ["\t\tmsg_pack_end();"]
161 lines += ["\t}"]
162 lines += ["};"]
163 return lines
165 def emit_unpack(self):
166 lines = []
167 for m in self.members:
168 lines += m.emit_unpack()
169 for m in self.members:
170 lines += m.emit_unpack_check()
171 return lines
173 def emit_pack(self):
174 lines = []
175 for m in self.members:
176 lines += m.emit_pack()
177 return lines
180 class event(object):
181 def __init__(self, line):
182 object.__init__(self, line)
183 self.enum_name = "NETEVENTTYPE_%s" % self.name.upper()
184 self.struct_name = "NETEVENT_%s" % self.name.upper()
186 class raw_reader:
187 def __init__(self):
188 self.raw_lines = []
189 def parse(self, lines):
190 global line_count
191 for index in xrange(0, len(lines)):
192 line_count += 1
193 line = lines[index]
194 if not len(line):
195 continue
197 if line == "end":
198 return lines[index+1:]
199 else:
200 self.raw_lines += [line]
202 raise BaseException("Parse error")
204 class proto:
205 def __init__(self):
206 self.objects = []
207 self.messages = []
208 self.source_raw = []
209 self.header_raw = []
211 def load(filename):
212 # read the file
213 global line_count
214 line_count = 0
215 lines = [line.split("//", 2)[0].strip() for line in file(filename).readlines()]
217 p = proto()
219 while len(lines):
220 line_count += 1
221 line = lines[0]
223 if not len(line):
224 del lines[0]
225 continue
227 fields = line.split(None, 1)
229 del lines[0]
231 if fields[0] == "object":
232 new_obj = object(line)
233 lines = new_obj.parse(lines)
234 p.objects += [new_obj]
235 elif fields[0] == "message":
236 new_msg = message(line)
237 lines = new_msg.parse(lines)
238 p.messages += [new_msg]
239 elif fields[0] == "event":
240 new_obj = event(line)
241 lines = new_obj.parse(lines)
242 p.objects += [new_obj]
243 elif fields[0] == "raw_source":
244 raw = raw_reader()
245 lines = raw.parse(lines)
246 p.source_raw += raw.raw_lines
247 elif fields[0] == "raw_header":
248 raw = raw_reader()
249 lines = raw.parse(lines)
250 p.header_raw += raw.raw_lines
251 else:
252 print "error, strange line:", line
254 return p
256 def emit_header_file(f, p):
257 for l in p.header_raw:
258 print >>f, l
260 if 1: # emit the enum table for objects
261 print >>f, "enum {"
262 print >>f, "\tNETOBJTYPE_INVALID=0,"
263 for obj in p.objects:
264 print >>f, "\t%s," % obj.enum_name
265 print >>f, "\tNUM_NETOBJTYPES"
266 print >>f, "};"
267 print >>f, ""
269 if 1: # emit the enum table for messages
270 print >>f, "enum {"
271 print >>f, "\tNETMSGTYPE_INVALID=0,"
272 for msg in p.messages:
273 print >>f, "\t%s," % msg.enum_name
274 print >>f, "\tNUM_NETMSGTYPES"
275 print >>f, "};"
276 print >>f, ""
278 print >>f, "int netobj_secure(int type, void *data, int size);"
279 print >>f, "const char *netobj_get_name(int type);"
280 print >>f, "int netobj_num_corrections();"
281 print >>f, "const char *netobj_corrected_on();"
282 print >>f, ""
283 print >>f, "void *netmsg_secure_unpack(int type);"
284 print >>f, "const char *netmsg_get_name(int type);"
285 print >>f, "const char *netmsg_failed_on();"
286 print >>f, ""
288 for obj in p.objects:
289 for l in obj.emit_declaration():
290 print >>f, l
291 print >>f, ""
293 for msg in p.messages:
294 for l in msg.emit_declaration():
295 print >>f, l
296 print >>f, ""
298 def emit_source_file(f, p, protofilename):
299 print >>f, "#line 1 \"%s\"" % os.path.abspath(protofilename).replace("\\", "\\\\")
301 for l in p.source_raw:
302 print >>f, l
304 print >>f, "const char *msg_failed_on = \"\";"
305 print >>f, "const char *obj_corrected_on = \"\";"
306 print >>f, "static int num_corrections = 0;"
307 print >>f, "int netobj_num_corrections() { return num_corrections; }"
308 print >>f, "const char *netobj_corrected_on() { return obj_corrected_on; }"
309 print >>f, "const char *netmsg_failed_on() { return msg_failed_on; }"
310 print >>f, ""
311 print >>f, "static int netobj_clamp_int(const char *error_msg, int v, int min, int max)"
312 print >>f, "{"
313 print >>f, "\tif(v<min) { obj_corrected_on = error_msg; num_corrections++; return min; }"
314 print >>f, "\tif(v>max) { obj_corrected_on = error_msg; num_corrections++; return max; }"
315 print >>f, "\treturn v;"
316 print >>f, "}"
317 print >>f, ""
319 if 1: # names
320 print >>f, "static const char *object_names[] = {"
321 print >>f, "\t" + '"invalid",'
322 for obj in p.objects:
323 print >>f, '\t"%s",' % obj.name
324 print >>f, '\t""'
325 print >>f, "};"
326 print >>f, ""
328 if 1: # secure functions
329 print >>f, "static int secure_object_invalid(void *data, int size) { return 0; }"
330 for obj in p.objects:
331 print >>f, "static int secure_%s(void *data, int size)" % obj.name
332 print >>f, "{"
333 print >>f, "\t%s *obj = (%s *)data;" % (obj.struct_name, obj.struct_name)
334 print >>f, "\t(void)obj;" # to get rid of "unused variable" warning
335 print >>f, "\tif(size != sizeof(%s)) return -1;" % obj.struct_name
336 if obj.extends:
337 print >>f, "\tif(secure_%s(data, sizeof(NETOBJ_%s)) != 0) return -1;" % (obj.extends, obj.extends.upper())
339 for l in obj.emit_secure():
340 print >>f, "\t" + l
341 print >>f, "\treturn 0;";
342 print >>f, "}"
343 print >>f, ""
345 if 1: # secure function table
346 print >>f, "typedef int(*SECUREFUNC)(void *data, int size);"
347 print >>f, "static SECUREFUNC secure_funcs[] = {"
348 print >>f, "\t" + 'secure_object_invalid,'
349 for obj in p.objects:
350 print >>f, "\tsecure_%s," % obj.name
351 print >>f, "\t" + '0x0'
352 print >>f, "};"
353 print >>f, ""
355 if 1:
356 print >>f, "int netobj_secure(int type, void *data, int size)"
357 print >>f, "{"
358 print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return -1;"
359 print >>f, "\treturn secure_funcs[type](data, size);"
360 print >>f, "};"
361 print >>f, ""
363 if 1:
364 print >>f, "const char *netobj_get_name(int type)"
365 print >>f, "{"
366 print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return \"(invalid)\";"
367 print >>f, "\treturn object_names[type];"
368 print >>f, "};"
369 print >>f, ""
371 if 1: # names
372 print >>f, "static const char *message_names[] = {"
373 print >>f, "\t" + '"invalid",'
374 for msg in p.messages:
375 print >>f, '\t"%s",' % msg.name
376 print >>f, '\t""'
377 print >>f, "};"
378 print >>f, ""
380 if 1: # secure functions
381 print >>f, "static void *secure_unpack_invalid() { return 0; }"
382 for msg in p.messages:
383 print >>f, "static void *secure_unpack_%s()" % msg.name
384 print >>f, "{"
385 print >>f, "\tstatic %s msg;" % msg.struct_name
386 for l in msg.emit_unpack():
387 print >>f, "\t" + l
388 print >>f, "\treturn &msg;";
389 print >>f, "}"
390 print >>f, ""
392 if 1: # secure function table
393 print >>f, "typedef void *(*SECUREUNPACKFUNC)();"
394 print >>f, "static SECUREUNPACKFUNC secure_unpack_funcs[] = {"
395 print >>f, "\t" + 'secure_unpack_invalid,'
396 for msg in p.messages:
397 print >>f, "\tsecure_unpack_%s," % msg.name
398 print >>f, "\t" + '0x0'
399 print >>f, "};"
400 print >>f, ""
402 if 1:
403 print >>f, "void *netmsg_secure_unpack(int type)"
404 print >>f, "{"
405 print >>f, "\tvoid *msg;"
406 print >>f, "\tmsg_failed_on = \"\";"
407 print >>f, "\tif(type < 0 || type >= NUM_NETMSGTYPES) return 0;"
408 print >>f, "\tmsg = secure_unpack_funcs[type]();"
409 print >>f, "\tif(msg_unpack_error()) return 0;"
410 print >>f, "\treturn msg;"
411 print >>f, "};"
412 print >>f, ""
414 if 1:
415 print >>f, "const char *netmsg_get_name(int type)"
416 print >>f, "{"
417 print >>f, "\tif(type < 0 || type >= NUM_NETMSGTYPES) return \"(invalid)\";"
418 print >>f, "\treturn message_names[type];"
419 print >>f, "};"
420 print >>f, ""
422 if sys.argv[1] == "header":
423 p = load(sys.argv[2])
424 emit_header_file(file(sys.argv[3], "w"), p)
425 elif sys.argv[1] == "source":
426 p = load(sys.argv[2])
427 emit_source_file(file(sys.argv[3], "w"), p, sys.argv[2])
428 else:
429 print "invalid command"
430 sys.exit(-1)