import sys from string import * # -- STLField ---------------------------------------------------------------- class STLField: def __init__ (self, parser, s): self.text = s self.parser = parser self.label = '' self.ID = '' self.follower = '' self.name = '' self.comment = '' self.offset = -1 self.size = -1 temp, tail = split (s, None, 1) if temp [-1] == ':': self.label = temp temp, tail = split (tail, None, 1) self.ID = temp if tail [0] == '"': temp, tail = split (tail, '"', 1) elif find (tail, ' ') != -1 or find (tail, '\t') != -1: temp, tail = split (tail, None, 1) else: temp = tail tail = '' self.follower = temp if find (tail, ';') != -1: temp, tail = split (tail, ';', 1) self.name = strip (temp) self.comment = strip (tail) else: self.name = strip (tail) def get_follower_count (self): if self.follower == '' or self.follower [0] == "'" or self.follower [0] == "`": return 1 else: return atoi (self.follower) def get_size (self): if self.size == -1: if self.ID in ['c', 'sc', 'b', 'i8', 'u8', '+']: self.size = self.get_follower_count() elif self.ID == '-': self.size = -self.get_follower_count() elif self.ID in ['w', 'i16', 'u16']: self.size = self.get_follower_count() * 2 elif self.ID in ['d', 'i32', 'u32', 'tu']: self.size = self.get_follower_count() * 4 elif self.ID == 't8': self.size = 1 elif self.ID == 't16': self.size = 2 elif self.ID in ['j32', 't32']: self.size = 4 elif self.ID == '*': self.size = self.get_follower_count() * self.parser.struc_map [self.name].get_size() else: raise RuntimeError, 'Unknown ID ' + self.ID return self.size # -- STLFieldGroup ----------------------------------------------------------- class STLFieldGroup: "A group of STL structure fields" def __init__ (self, parser, offset=0): self.parser = parser self.fields = [] # list containing STLField and STLCondGroup elements self.size = -1 self.cur_field = None self.offset = offset def add_line (self, s): s = strip (s) if len (s) == 0: return if s [0] == ';': self.cur_field.comment = self.cur_field.comment + s [1:] else: self.cur_field = STLField (self.parser, s) self.fields.append (self.cur_field) self.size = -1 # invalidate def add_group (self, group): self.fields.append (group) def get_size (self): offset = self.offset for field in self.fields: field.offset = offset offset = offset + field.get_size() self.size = offset return self.size # -- STLCondGroup ------------------------------------------------------------ class STLCondGroup: "A group of STL structure fields within an #IF block" def __init__ (self, parser, cond, comment, offset): self.cond = cond self.comment = comment self.if_part = STLFieldGroup (parser, offset) self.else_part = STLFieldGroup (parser, offset) self.in_else = 0 def set_else (self): if self.in_else == 1: raise SyntaxError, "already in #ELSE" self.in_else = 1 def add_line (self, s): if self.in_else == 0: self.if_part.add_line (s) else: self.else_part.add_line (s) def add_group (self, group): if self.in_else == 0: self.if_part.add_group (group) else: self.else_part.add_group (group) def get_size (self): # the meaning of offsets in conditional structures is dubious. # thus, we take the size of the smallest of #IF and #ELSE structures isize = self.if_part.get_size() esize = self.else_part.get_size() return min (isize, esize) # -- STLStructure ------------------------------------------------------------ class STLStructure: "A single STL structure definition" def __init__ (self, parser, heading): group = STLFieldGroup (parser) self.parser = parser self.name = heading self.cond_stack = [group] self.comment = [] # list of HTML lines printed before the structure self.have_field = 0 # comment lines before first field go to structure comment self.size = -1 self.finalized = 0 def add_line (self, s): s = strip (s) if s == '': return if s [0] == ';': if self.have_field == 0: self.comment.append (s [1:]) else: self.top.add_line (s) elif s [0] == '#': if find (s, ' ') != -1: directive, cond = split (s, None, 1) else: directive = s cond = '' directive = upper (directive) if directive == '#ELSE' or directive == '#ELSEIF': if not isinstance (self.cond_stack [-1], STLCondGroup): raise SyntaxError, '#ELSE or #ELSEIF before #IF' self.cond_stack [-1].set_else() if directive == '#IF' or directive == '#ELSEIF': comment = '' if find (cond, ';') != -1: cond, comment = split (cond, ';', 1) cond = strip (cond) offset = self.cond_stack [-1].get_size() newgroup = STLCondGroup (self.parser, cond, comment, offset) self.cond_stack [-1].add_group (newgroup) self.cond_stack.append (newgroup) if directive == '#FI': if len (self.cond_stack) <= 1: raise SyntaxError, 'unexpected #FI' del self.cond_stack [-1] else: self.cond_stack [-1].add_line (s) self.have_field = 1 def get_size (self): if self.size == -1: size = self.cond_stack [-1].get_size() if self.finalized == 1: self.size = size return size else: return self.size def finalize (self): if len (self.cond_stack) != 1: raise SyntaxError, "not enough #FI's" self.finalized = 1 # -- STLList ------------------------------------------------------------------- class STLListField: pass class STLList: "An STL field legend" def __init__ (self, heading): self.name = heading self.elements = [] def add_line (self, s): s = strip (s) if len (s) == 0: return if s [0] == ';': return elem = STLListField() temp, tail = split (s, None, 1) if upper (temp [0:2]) == '0X': elem.is_hex = 1 else: elem.is_hex = 0 elem.value = atoi (temp, 0) if find (letters, tail [0]) == -1: temp, tail = split (tail, None, 1) elem.max_value = atoi (temp, 0) elem.text = tail self.elements.append (elem) def finalize (self): pass # -- STLParser ----------------------------------------------------------------- class STLParser: "Parses a STL structure defininion file" def __init__ (self, fname): f=open (fname, 'r') have_signature = 0 self.structures = [] self.struc_map = {} self.lists = [] self.list_map = {} struc = None for s in f.readlines(): s = strip (s) if len (s) == 0: continue if have_signature == 0: if s != 'STL 4.00': print 'Invalid signature' exit have_signature = 1 continue if s[0] == '/': if struc != None: struc.finalize() if len (s) == 1: raise SyntaxError, 'missing structure name' if s [1] in ["'", "`"]: struc = STLList (s [2:]) self.lists.append (struc) self.list_map [struc.name] = struc else: struc = STLStructure (self, s [1:]) self.structures.append (struc) self.struc_map [struc.name] = struc elif struc != None: struc.add_line (s) struc.finalize() f.close # -- STL_HTMLWriter ---------------------------------------------------------- def upper_hex (number, digits=0): return '0x' + zfill (upper (hex (number) [2:]), digits) class STL_HTMLWriter: "Convert an STL structure definition to a HTML file" DOCTYPE = '\n' body_start = '\n' body_end = '' def __init__ (self, parser, out_fname): self.parser = parser self.out_fname = out_fname self.empty_else = 0 def write (self): self.out_file = open (self.out_fname, 'wt') self.out (self.DOCTYPE, self.body_start) for struc in parser.structures: self.write_structure (struc) for stllist in parser.lists: self.write_list (stllist) self.out (self.body_end) self.out_file.close def out (self, *lines): for l in lines: self.out_file.write (l) def write_table_start (self, heading, col_count): self.out ('\n') self.out ('\n') def write_table_end (self): self.out ('
', heading, '
\n

\n') def write_hyperlink (self, text, dest): self.out ('', text, '') def write_structure (self, struc): if struc.comment != []: for s in struc.comment: self.out (s) self.out ('\n') heading = '' + struc.name + ' (0x' heading = heading + upper_hex (struc.get_size()) + ' bytes)' self.write_table_start (heading, 4) self.write_field_group (struc.cond_stack [0]) self.write_table_end() def write_field_group (self, field_group): for field in field_group.fields: if isinstance (field, STLField): self.write_field (field) elif isinstance (field, STLCondGroup): self.out ('') if self.empty_else == 0: self.out ('If ') else: self.out ('Else if ') if field.comment != '': self.out (field.comment) else: self.out (field.cond) self.out ('') self.write_field_group (field.if_part) if len (field.else_part.fields) == 1 and isinstance (field.else_part.fields [0], STLCondGroup): self.empty_else = 1 self.write_field_group (field.else_part) else: self.empty_else = 0 if len (field.else_part.fields) > 0: self.out ('else') self.write_field_group (field.else_part) self.out ('end if') def write_field (self, field): if field.ID in ['+', '-']: return offset = upper_hex (field.offset, 4) self.out ('', offset, '\n') self.out ('', str (field.size), '\n') self.out ('') if field.ID [0] == 'j': # jumpanese - generate a hyperlink dest, temp = split (field.follower, '=', 1) self.write_hyperlink (field.name, '#' + dest) elif field.ID == '*': self.write_hyperlink (field.name, '#' + field.name) else: self.out (field.name) self.out ('') comment = replace (field.comment, "&", "&") comment = replace (comment, "<", "<") comment = replace (comment, ">", ">") comment = replace (comment, '"', """) self.out ('', comment, '') def write_list (self, stllist): heading = '' + stllist.name + '' self.write_table_start (heading, 2) for elem in stllist.elements: self.out ('') if elem.is_hex == 1: self.out (upper_hex (elem.value)) else: self.out (str (elem.value)) self.out ('', elem.text, '\n') self.write_table_end() # ---------------------------------------------------------------------------- if len(sys.argv) < 2: print 'Usage: STL2HTML ' exit parser = STLParser (sys.argv [1]) writer = STL_HTMLWriter (parser, sys.argv [2]) writer.write()