288 lines
12 KiB
Python
288 lines
12 KiB
Python
"""
|
|
@file template_parser.py
|
|
@date 2008-09-16
|
|
Contributors can be viewed at:
|
|
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/CONTRIBUTORS.txt
|
|
|
|
$LicenseInfo:firstyear=2008&license=apachev2$
|
|
|
|
Copyright 2008, Linden Research, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License").
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
or in
|
|
http://svn.secondlife.com/svn/linden/projects/2008/pyogp/LICENSE.txt
|
|
|
|
$/LicenseInfo$
|
|
"""
|
|
|
|
#standard libraries
|
|
import struct
|
|
import string
|
|
import re
|
|
import pprint
|
|
|
|
#local libraries
|
|
import template
|
|
from data import msg_tmpl
|
|
from types import MsgFrequency, MsgTrust, MsgEncoding
|
|
from types import MsgDeprecation, MsgBlockType, MsgType, sizeof
|
|
|
|
class MessageTemplateParser(object):
|
|
"""a parser which parses the message template and creates MessageTemplate objects
|
|
which are stored in self.message_templates
|
|
"""
|
|
def __init__(self, template_file):
|
|
if template_file == None:
|
|
raise exc.MessageTemplateNotFound("initializing template parser")
|
|
|
|
self.template_file = template_file
|
|
self.message_templates = []
|
|
self.version = ''
|
|
self.count = 0
|
|
self._parse_template_file()
|
|
|
|
def _add_template(self, new_template):
|
|
self.count += 1
|
|
self.message_templates.append(new_template)
|
|
|
|
def _parse_template_file(self):
|
|
count = 0
|
|
|
|
self.template_file.seek(0)
|
|
lines = self.template_file
|
|
#results = re.match("^\t([^\t{}]+.+)",line) #gets packet headers
|
|
#results = re.match("^\t\t([^{}]+.+)",line) #gets packet blocks
|
|
#results = re.match("^\t\t([{}]+.+)",line) #gets block data
|
|
|
|
current_template = None
|
|
current_block = None
|
|
|
|
#we have to go through all the packets and parse them
|
|
while(True):
|
|
try:
|
|
line = lines.next()
|
|
except StopIteration:
|
|
break
|
|
|
|
if self.version == '':
|
|
version_test = re.match("version.(.+)",line) #gets packet headers
|
|
if version_test != None:
|
|
parts = version_test.group(1)
|
|
parts = parts.split()
|
|
self.version = float(parts[0])
|
|
|
|
#get packet header, starting a new packet
|
|
# ToDo: this regex needs to accomodate the case where 4 spaces are used in place of a tab and start of line
|
|
packet_header = re.match("^\t([^\t{}]+.+)",line) #gets packet headers
|
|
if packet_header != None:
|
|
parts = packet_header.group(1)
|
|
parts = parts.split()
|
|
|
|
current_template = template.MessageTemplate(parts[0])
|
|
frequency = None
|
|
if parts[1] == 'Low':
|
|
frequency = MsgFrequency.LOW_FREQUENCY_MESSAGE
|
|
elif parts[1] == 'Medium':
|
|
frequency = MsgFrequency.MEDIUM_FREQUENCY_MESSAGE
|
|
elif parts[1] == 'High':
|
|
frequency = MsgFrequency.HIGH_FREQUENCY_MESSAGE
|
|
elif parts[1] == 'Fixed':
|
|
frequency = MsgFrequency.FIXED_FREQUENCY_MESSAGE
|
|
|
|
current_template.frequency = frequency
|
|
|
|
msg_num = string.atoi(parts[2],0)
|
|
if frequency == MsgFrequency.FIXED_FREQUENCY_MESSAGE:
|
|
#have to do this because Fixed messages are stored as a long in the template
|
|
binTemp = struct.pack('>L', string.atol(parts[2],0))
|
|
#msg_num_hex = binTemp
|
|
msg_num = struct.unpack('>h','\x00' + binTemp[3])[0]
|
|
elif frequency == MsgFrequency.LOW_FREQUENCY_MESSAGE:
|
|
msg_num_hex = struct.pack('>BBh',0xff,0xff, msg_num)
|
|
elif frequency == MsgFrequency.MEDIUM_FREQUENCY_MESSAGE:
|
|
msg_num_hex = struct.pack('>BB',0xff, msg_num)
|
|
elif frequency == MsgFrequency.HIGH_FREQUENCY_MESSAGE:
|
|
msg_num_hex = struct.pack('>B', msg_num)
|
|
|
|
current_template.msg_num = msg_num
|
|
current_template.msg_num_hex = msg_num_hex
|
|
|
|
msg_trust = None
|
|
if parts[3] == 'Trusted':
|
|
msg_trust = MsgTrust.LL_TRUSTED
|
|
elif parts[3] == 'NotTrusted':
|
|
msg_trust = MsgTrust.LL_NOTRUST
|
|
|
|
current_template.msg_trust = msg_trust
|
|
|
|
msg_encoding = None
|
|
if parts[4] == 'Unencoded':
|
|
msg_encoding = MsgEncoding.LL_UNENCODED
|
|
elif parts[4] == 'Zerocoded':
|
|
msg_encoding = MsgEncoding.LL_ZEROCODED
|
|
|
|
current_template.msg_encoding = msg_encoding
|
|
|
|
msg_dep = None
|
|
if len(parts) > 5:
|
|
if parts[5] == 'Deprecated':
|
|
msg_dep = MsgDeprecation.LL_DEPRECATED
|
|
elif parts[5] == 'UDPDeprecated':
|
|
msg_dep = MsgDeprecation.LL_UDPDEPRECATED
|
|
elif parts[5] == 'NotDeprecated':
|
|
msg_dep = MsgDeprecation.LL_NOTDEPRECATED
|
|
else:
|
|
msg_dep = MsgDeprecation.LL_NOTDEPRECATED
|
|
|
|
current_template.msg_deprecation = msg_dep
|
|
|
|
self._add_template(current_template)
|
|
|
|
block_header = re.match("^\t\t([^{}]+.+)",line) #gets packet block header
|
|
if block_header != None:
|
|
parts = block_header.group(1)
|
|
parts = parts.split()
|
|
|
|
current_block = template.MessageTemplateBlock(parts[0])
|
|
|
|
block_type = None
|
|
block_num = 0
|
|
|
|
if parts[1] == 'Single':
|
|
block_type = MsgBlockType.MBT_SINGLE
|
|
elif parts[1] == 'Multiple':
|
|
block_type = MsgBlockType.MBT_MULTIPLE
|
|
block_num = int(parts[2])
|
|
elif parts[1] == 'Variable':
|
|
block_type = MsgBlockType.MBT_VARIABLE
|
|
|
|
#LDE 230ct2008 block_type vs block.type issues...
|
|
current_block.block_type = block_type
|
|
current_block.number = block_num
|
|
|
|
current_template.add_block(current_block)
|
|
|
|
block_data = re.match("^\t\t([{}]+.+)",line) #gets block data
|
|
if block_data != None:
|
|
parts = block_data.group(1)
|
|
parts = parts.split()
|
|
parts.remove('{')
|
|
parts.remove('}')
|
|
|
|
type_string = parts[1]
|
|
var_type = None
|
|
var_size = -1
|
|
if type_string == 'U8':
|
|
var_type = MsgType.MVT_U8
|
|
elif type_string == 'U16':
|
|
var_type = MsgType.MVT_U16
|
|
elif type_string == 'U32':
|
|
var_type = MsgType.MVT_U32
|
|
elif type_string == 'U64':
|
|
var_type = MsgType.MVT_U64
|
|
elif type_string == 'S8':
|
|
var_type = MsgType.MVT_S8
|
|
elif type_string == 'S16':
|
|
var_type = MsgType.MVT_S16
|
|
elif type_string == 'S32':
|
|
var_type = MsgType.MVT_S32
|
|
elif type_string == 'S64':
|
|
var_type = MsgType.MVT_S64
|
|
elif type_string == 'F32':
|
|
var_type = MsgType.MVT_F32
|
|
elif type_string == 'F64':
|
|
var_type = MsgType.MVT_F64
|
|
elif type_string == 'LLVector3':
|
|
var_type = MsgType.MVT_LLVector3
|
|
elif type_string == 'LLVector3d':
|
|
var_type = MsgType.MVT_LLVector3d
|
|
elif type_string == 'LLVector4':
|
|
var_type = MsgType.MVT_LLVector4
|
|
elif type_string == 'LLQuaternion':
|
|
var_type = MsgType.MVT_LLQuaternion
|
|
elif type_string == 'LLUUID':
|
|
var_type = MsgType.MVT_LLUUID
|
|
elif type_string == 'BOOL':
|
|
var_type = MsgType.MVT_BOOL
|
|
elif type_string == 'IPADDR':
|
|
var_type = MsgType.MVT_IP_ADDR
|
|
elif type_string == 'IPPORT':
|
|
var_type = MsgType.MVT_IP_PORT
|
|
elif type_string == 'Fixed' or type_string == 'Variable':
|
|
if type_string == 'Fixed':
|
|
var_type = MsgType.MVT_FIXED
|
|
elif type_string == 'Variable':
|
|
var_type = MsgType.MVT_VARIABLE
|
|
|
|
var_size = int(parts[2])
|
|
if var_size <= 0:
|
|
raise exc.MessageTemplateParsingError("variable size %s does not match %s" % (var_size, type_string))
|
|
#if the size hasn't been read yet, then read it from message_types
|
|
if var_size == -1:
|
|
var_size = sizeof(var_type)
|
|
|
|
#LDE 23oct2008 add var+type to creation of MTV object for subsequent formmating goodness
|
|
current_var = template.MessageTemplateVariable(parts[0], var_type, var_size)
|
|
current_block.add_variable(current_var)
|
|
|
|
self.template_file.seek(0)
|
|
def print_packet_names(packet_list):
|
|
frequency_counter = {"low":0, 'medium':0, "high":0, 'fixed':0}
|
|
counter = 0
|
|
for packet in packet_list:
|
|
print '================================================================================='
|
|
counter += 1
|
|
frequency_counter[packet.get_frequency_as_string()]+=1
|
|
#if packet.get_frequency_as_string() == "low":
|
|
print counter, packet.get_name() + ' ' + packet.get_frequency_as_string()
|
|
print '================================================================================='
|
|
print
|
|
for counters in frequency_counter:
|
|
print counters, frequency_counter[counters]
|
|
print
|
|
|
|
def print_packet_list(packet_list):
|
|
for packet in packet_list:
|
|
print '================================================================================='
|
|
print packet.get_name() + ' ' + packet.get_frequency_as_string() + ' ' + \
|
|
str(packet.get_message_number()) + ' ' + packet.get_message_hex_num() + \
|
|
' ' + packet.get_message_trust_as_string() + ' ' + \
|
|
packet.get_message_encoding_as_string() + ' ' + packet.get_deprecation_as_string()
|
|
|
|
for block in packet.get_blocks():
|
|
|
|
print '\t' + str(block.get_name()) + ' ' + block.get_block_type_as_string() + ' ' + \
|
|
str(block.get_block_number())
|
|
for variable in block.get_variables():
|
|
sz = len(variable.get_name())
|
|
print '\t\t' + variable.get_name().ljust(20) +"\t" + variable.get_type_as_string()
|
|
|
|
def get_all_types(packet_list):
|
|
type_set = set([])
|
|
for packet in packet_list:
|
|
for block in packet.get_blocks():
|
|
for variable in block.get_variables():
|
|
type_set.add(variable.get_type_as_string()) #LDE 23oct2008 display using _as_string call
|
|
|
|
type_list = list(type_set)
|
|
type_list.sort()
|
|
return type_list
|
|
|
|
def main():
|
|
"""tidied up this test which didn't seem to be working for me at first til I made a few changes"""
|
|
parser = MessageTemplateParser(msg_tmpl)
|
|
#parser._parse_template_file() #LDE 23oct2008 part of tidying up thing above
|
|
templates = parser.message_templates
|
|
print_packet_names(templates)
|
|
print_packet_list(templates)
|
|
|
|
p_typelist = get_all_types(templates)
|
|
pprint.pprint(p_typelist)
|
|
return
|
|
|
|
if __name__ == "__main__":
|
|
main()
|