Vearie

BZ2 CFG File Parser (Old)

Nov 20th, 2018 (edited)
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.64 KB | None | 0 0
  1. # BZ2 Shell Interface Dimensions
  2. WIDTH, HEIGHT = 640, 480 # 1920, 1080
  3.  
  4. ignore_missing_close_braces = True
  5. ignore_missing_open_braces = False
  6.  
  7. class CFG_ParseError(Exception): pass
  8.  
  9. def p(param):
  10.     return ", ".join(map(repr, param))
  11.  
  12. class Param():
  13.     def __init__(self, value, is_quote_value = None):
  14.         self.value = value
  15.         self.is_quote_value = is_quote_value
  16.    
  17.     def __bool__(self):
  18.         return len(self.value) > 0
  19.    
  20.     def append(self, data):
  21.         self.value += data
  22.    
  23.     def convert(self):
  24.         def isall(value, character_set):
  25.             for c in value:
  26.                 if not c in character_set:
  27.                     return False
  28.            
  29.             return bool(value)
  30.        
  31.         if self.is_quote_value: return self.value
  32.         elif isall(self.value, "+-1234567890"):
  33.             return int(self.value)
  34.         elif isall(self.value, "+-1234567890e."):
  35.             return float(self.value)
  36.         else:
  37.             return None
  38.  
  39. class Container:
  40.     def __init__(self, name, parameters = []):
  41.         self.name = name
  42.         self.param = parameters
  43.         self.parent = None
  44.        
  45.         self.attribute = [] # List of attributes ("AttributeName", [param1, param2])
  46.         self.container = [] # List of subcontainers
  47.    
  48.     def fix_attr(self, name):
  49.         find = name.casefold()
  50.        
  51.         if find == "Geometry".casefold():
  52.             return name[0:4]
  53.         elif find == "Position".casefold():
  54.             return name[0:3]
  55.        
  56.         return name
  57.    
  58.     def get_attr(self, name, default = None):
  59.         find = self.fix_attr(name).casefold()
  60.        
  61.         for attr in self.attribute:
  62.             if attr[0].casefold() == find:
  63.                 return attr[1]
  64.        
  65.         return default
  66.    
  67.     def set_attr(self, name, param):
  68.         find = name.casefold()
  69.        
  70.         for index, attr in enumerate(self.attribute):
  71.             if attr[0].casefold() == find:
  72.                 self.attribute[index] = (self.fix_attr(name), param)
  73.                 return
  74.        
  75.         self.attribute += [(self.fix_attr(name), param)]
  76.    
  77.     def __str__(self):
  78.         return "Container: %s(%s) - %d Attributes, %d Containers" % (
  79.                 self.name,
  80.                 p(self.param),
  81.                 len(self.attribute),
  82.                 len(self.container)
  83.             )
  84.  
  85. def read(cfg_path):
  86.     progressive_debug_prints = False
  87.    
  88.     READING_NAME = 0
  89.     READING_PARAMS = 1
  90.     EXPECTING_COMMENT = 2
  91.     EXPECTING_CONTAINER_OR_END = 3
  92.    
  93.     with open(cfg_path, "r") as cfg:
  94.         valid_name = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_"
  95.         valid_param = "0123456789-.e"
  96.         valid_quote = "\"'"
  97.        
  98.         skip_character = (
  99.             " \t\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10"
  100.             "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
  101.         )
  102.        
  103.         container = [Container("ROOT")]
  104.         brl = 0
  105.        
  106.         state = [READING_NAME]
  107.         name, param, quote = "", [], None
  108.        
  109.         for row, line in enumerate(cfg):
  110.             for col, c in enumerate(line.strip()):
  111.                 # Space/tab/etc...
  112.                 if not quote and c in skip_character:
  113.                     continue
  114.                
  115.                 if state[-1] == EXPECTING_COMMENT:
  116.                     # Ensure double slash, otherwise invalid.
  117.                     if c == "/":
  118.                         state.pop()
  119.                         break
  120.                
  121.                 elif state[-1] == READING_NAME:
  122.                     # Add character to name value
  123.                     if c in valid_name:
  124.                         name += c
  125.                         continue
  126.                    
  127.                     # Comment, if it's the first piece of data
  128.                     elif c == "/" and not name:
  129.                         state.append(EXPECTING_COMMENT)
  130.                         continue
  131.                    
  132.                     # Beginning first parameter
  133.                     elif c == "(":
  134.                         state.append(READING_PARAMS)
  135.                         param += [Param("")]
  136.                         continue
  137.                    
  138.                     # Closing brace of container we are in
  139.                     elif c == "}":
  140.                         brl -= 1
  141.                        
  142.                         if brl >= 0:
  143.                             container.pop()
  144.                             if progressive_debug_prints:
  145.                                 print("\t"*brl + "}" + "\n" + "\t"*brl)
  146.                             continue
  147.                        
  148.                         if ignore_missing_close_braces:
  149.                             brl = 0
  150.                             continue
  151.                        
  152.                         raise CFG_ParseError("%s:%d:%d: Too Many Closing Braces" % (cfg_path, row+1, col+1))
  153.                
  154.                 elif state[-1] == READING_PARAMS:
  155.                     # We are currently reading quoted data (string)
  156.                     if quote:
  157.                         # Matched terminating quote
  158.                         if c == quote:
  159.                             quote = None
  160.                             continue
  161.                        
  162.                         # Note: We don't need to worry about \ escapes, it's not supported anyway.
  163.                         param[-1].append(c)
  164.                         continue
  165.                    
  166.                     # Parameter data (hopefully an integer)
  167.                     elif c in valid_param:
  168.                         param[-1].append(c)
  169.                         continue
  170.                    
  171.                     # Encountered quote
  172.                     elif c in valid_quote:
  173.                         # Was there already valid data before this quote encounter?
  174.                         if param[-1]:
  175.                             raise CFG_ParseError("%s:%d:%d: Unexpected Quote" % (cfg_path, row+1, col+1))
  176.                        
  177.                         param[-1].is_quote_value = True
  178.                         quote = c
  179.                         continue
  180.                    
  181.                     # Next parameter
  182.                     elif c == ",":
  183.                         param += [Param("")]
  184.                         continue
  185.                    
  186.                     # End of parameters
  187.                     elif c == ")":
  188.                         # Remove assumed first parameter if there were none in the cfg.
  189.                         if (len(param) == 1
  190.                         and not param[-1]
  191.                         and not param[-1].is_quote_value):
  192.                             param.pop()
  193.                        
  194.                         state.pop()
  195.                         state.append(EXPECTING_CONTAINER_OR_END)
  196.                         continue
  197.                    
  198.                 elif state[-1] == EXPECTING_CONTAINER_OR_END:
  199.                     # End of attribute
  200.                     if c == ";":
  201.                         if progressive_debug_prints:
  202.                             print("\t"*brl + "%s(%s);" % (name, ", ".join([str(x) for x in param])))
  203.                        
  204.                         param = [p.convert() for p in param]
  205.                         container[-1].set_attr(name, param)
  206.                        
  207.                         state.pop()
  208.                         name, param = "", []
  209.                         continue
  210.                    
  211.                     # Start of a container
  212.                     elif c == "{":
  213.                         # Add container to parent container (or root container).
  214.                         brl += 1
  215.                         if progressive_debug_prints:
  216.                             print("\t"*(brl-1) + "%s(%s) {" % (name, ", ".join([str(x) for x in param])))
  217.                        
  218.                         param = [p.convert() for p in param]
  219.                         container += [Container(name, param)]
  220.                        
  221.                         # Make current container a child of last container
  222.                         container[brl-1].container += [container[brl]]
  223.                         container[brl].parent = container[brl-1]
  224.                        
  225.                         state.pop()
  226.                         name, param = "", []
  227.                         continue
  228.                
  229.                 print("_"*64, "\nDebug Help:", quote, brl)
  230.                 raise CFG_ParseError(
  231.                     "%s:%d:%d: %s - Unexpected Character %r" % (
  232.                             cfg_path, row+1, col+1, str(state[-1]), c
  233.                         )
  234.                     )
  235.        
  236.         # Ensure we had a matching closing brace for every opening brace.
  237.         if brl and not ignore_missing_open_braces:
  238.             # Note: You may disable this but it could cause silently
  239.             # malformed results.
  240.             raise CFG_ParseError("%s - Too Many Opening Braces" % cfg_path)
  241.        
  242.         # Return root container
  243.         return container[0]
  244.  
  245. def PrintConfig(cfg, brl = -1):
  246.     if type(cfg) == str:
  247.         cfg = read(cfg)
  248.    
  249.     # Skip root  container
  250.     if brl < 0:
  251.         for subcfg in cfg.container:
  252.             PrintConfig(subcfg, brl+1)
  253.         return
  254.    
  255.     print("\t"*brl + "%s(%s) {" % (cfg.name, p(cfg.param)))
  256.    
  257.     for attr in cfg.attribute:
  258.         print("\t"*(brl+1) + "%s(%s);" % (attr[0], p(attr[1])))
  259.     else:
  260.         if len(cfg.container): print("\t"*(brl+1))
  261.    
  262.     for subcfg in cfg.container:
  263.         PrintConfig(subcfg, brl+1)
  264.    
  265.     print("\t"*brl + "}\n" + "\t"*brl)
  266.  
  267. if __name__ == "__main__":
  268.     PrintConfig("config/bzshell.cfg")
Add Comment
Please, Sign In to add comment