Package Peach :: Package Engine :: Module parser
[hide private]

Source Code for Module Peach.Engine.parser

   1   
   2  ''' 
   3  Peach XML Parser.  Sucks in the crazy XML and returns a top level context 
   4  object that contians things like templates, namespaces, etc. 
   5   
   6  @author: Michael Eddington 
   7  @version: $Id: parser.py 1118 2008-08-07 01:53:33Z meddingt $ 
   8  ''' 
   9   
  10  # 
  11  # Copyright (c) 2007-2008 Michael Eddington 
  12  # 
  13  # Permission is hereby granted, free of charge, to any person obtaining a copy  
  14  # of this software and associated documentation files (the "Software"), to deal 
  15  # in the Software without restriction, including without limitation the rights  
  16  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
  17  # copies of the Software, and to permit persons to whom the Software is  
  18  # furnished to do so, subject to the following conditions: 
  19  # 
  20  # The above copyright notice and this permission notice shall be included in     
  21  # all copies or substantial portions of the Software. 
  22  # 
  23  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
  24  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
  25  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
  26  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
  27  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  28  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  29  # SOFTWARE. 
  30  # 
  31   
  32  # Authors: 
  33  #   Michael Eddington (mike@phed.org) 
  34   
  35  # $Id: parser.py 1118 2008-08-07 01:53:33Z meddingt $ 
  36   
  37  import sys, re, types 
  38  import traceback 
  39  from Peach.Engine.dom import * 
  40  from Peach.Engine import dom 
  41  from Peach.Mutators import * 
  42  from Peach.Engine.common import * 
  43   
  44  try: 
  45          import Ft.Xml.Domlette 
  46          from Ft.Xml.Catalog import GetDefaultCatalog 
  47          from Ft.Xml.InputSource import InputSourceFactory 
  48          from Ft.Lib.Resolvers import SchemeRegistryResolver 
  49          from Ft.Lib import Uri 
  50          from Ft.Xml import Parse 
  51          from Ft.Xml.Sax import DomBuilder 
  52          from Ft.Xml import Sax, CreateInputSource 
  53  except: 
  54          raise PeachException("Error loading 4Suite XML library.  This library\ncan be installed from the dependencies folder or\ndownloaded from http://4suite.org/.\n\n") 
  55   
  56  from uuid import uuid1 
  57   
58 -def PeachStr(s):
59 ''' 60 Our implementation of str() which does not 61 convert None to 'None'. 62 ''' 63 64 if s == None: 65 return None 66 67 return str(s)
68
69 -class PeachResolver(SchemeRegistryResolver):
70 - def __init__(self):
71 SchemeRegistryResolver.__init__(self)
72
73 - def resolve(self, uri, base=None):
74 scheme = Uri.GetScheme(uri) 75 if scheme == None: 76 if base != None: 77 scheme = Uri.GetScheme(base) 78 if scheme == None: 79 #Another option is to fall back to Base class behavior 80 raise Uri.UriException(Uri.UriException.SCHEME_REQUIRED, 81 base=base, ref=uri) 82 83 # Add the files path to our sys.path 84 85 if scheme == 'file': 86 filename = uri[5:] 87 try: 88 index = filename.rindex('\\') 89 sys.path.append(filename[: 0 - (index+1)]) 90 #print "Adding [%s]" % filename[: 0 - (index+1)] 91 92 except: 93 try: 94 index = filename.rindex('/') 95 sys.path.append(filename[: 0 - (index+1)]) 96 #print "Adding [%s]" % filename[: 0 - (index+1)] 97 98 except: 99 #print "Adding [.][%s]" % uri 100 sys.path.append('.') 101 102 try: 103 func = self.handlers.get(scheme) 104 if func == None: 105 func = self.handlers.get(None) 106 if func == None: 107 return Uri.UriResolverBase.resolve(self, uri, base) 108 109 return func(uri, base) 110 111 except: 112 113 if scheme != 'file': 114 raise PeachException("Peach was unable to locate [%s]" % uri) 115 116 # Lets try looking in our sys.path 117 118 paths = [] 119 for path in sys.path: 120 paths.append(path) 121 paths.append("%s/Peach/Engine" % path) 122 123 for path in paths: 124 newuri = uri[:5] + path + '/' + uri[5:] 125 #print "Trying: [%s]" % newuri 126 127 try: 128 func = self.handlers.get(scheme) 129 if func == None: 130 func = self.handlers.get(None) 131 if func == None: 132 return Uri.UriResolverBase.resolve(self, newuri, base) 133 134 return func(uri, base) 135 except: 136 pass 137 138 raise PeachException("Peach was unable to locate [%s]" % uri)
139 140
141 -class ParseTemplate:
142 ''' 143 The Peach 2.0 XML -> Peach DOM parser. Uses 4Suite XML 144 library. 145 ''' 146
147 - def parse(self, uri):
148 ''' 149 Parse a Peach XML file pointed to by uri. 150 ''' 151 152 factory = InputSourceFactory(resolver=PeachResolver(), catalog=GetDefaultCatalog()) 153 isrc = factory.fromUri(uri) 154 doc = Ft.Xml.Domlette.NonvalidatingReader.parse(isrc) 155 156 return self.HandleDocument(doc)
157
158 - def parseString(self, xml):
159 ''' 160 Parse a string as Peach XML. 161 ''' 162 163 doc = Ft.Xml.Domlette.NonvalidatingReader.parseString(xml) 164 return self.HandleDocument(doc)
165
166 - def GetClassesInModule(self, module):
167 ''' 168 Return array of class names in module 169 ''' 170 171 classes = [] 172 for item in dir(module): 173 i = getattr(module, item) 174 if type(i) == types.ClassType and item[0] != '_': 175 classes.append(item) 176 177 return classes
178
179 - def HandleDocument(self, doc):
180 181 self.StripComments(doc) 182 self.StripText(doc) 183 184 ePeach = doc.firstChild 185 186 peach = dom.Peach() 187 peach.node = doc 188 self.context = peach 189 peach.mutators = None 190 191 setattr(peach, 'templates', ElementWithChildren()) 192 setattr(peach, 'data', ElementWithChildren()) 193 setattr(peach, 'agents', ElementWithChildren()) 194 setattr(peach, 'namespaces', ElementWithChildren()) 195 setattr(peach, 'tests', ElementWithChildren()) 196 setattr(peach, 'runs', ElementWithChildren()) 197 198 if ePeach.nodeName != 'Peach': 199 raise PeachException("First element in document must be Peach") 200 201 # Peach attributes 202 203 setattr(peach, 'version', self._getAttribute(ePeach, 'version')) 204 setattr(peach, 'author', self._getAttribute(ePeach, 'author')) 205 setattr(peach, 'description', self._getAttribute(ePeach, 'description')) 206 207 # The good stuff -- We are going todo multiple passes here to increase the likely hood 208 # that things will turn out okay. 209 210 # Pass 1 -- Include and PythonPath 211 for child in ePeach.childNodes: 212 213 if child.nodeName == 'Include': 214 # Include this file 215 216 nsName = self._getAttribute(child, 'ns') 217 nsSrc = self._getAttribute(child, 'src') 218 219 parser = ParseTemplate() 220 ns = parser.parse(nsSrc) 221 222 ns.name = nsName + ':' + nsSrc 223 ns.nsName = nsName 224 ns.nsSrc = nsSrc 225 ns.elementType = 'namespace' 226 ns.toXml = new.instancemethod(NamespaceToXml, ns, ns.__class__) 227 228 nss = Namespace() 229 nss.ns = ns 230 nss.nsName = nsName 231 nss.nsSrc = nsSrc 232 nss.name = nsName + ":" + nsSrc 233 nss.parent = peach 234 ns.parent = nss 235 236 peach.append(nss) 237 peach.namespaces.append(ns) 238 setattr(peach.namespaces, nsName, ns) 239 240 elif child.nodeName == 'PythonPath': 241 # Add a search path 242 243 p = self.HandlePythonPath(child, peach) 244 peach.append(p) 245 sys.path.append(p.name) 246 247 # Pass 2 -- Import 248 for child in ePeach.childNodes: 249 250 if child.nodeName == 'Import': 251 # Import module 252 253 if not child.hasAttributeNS(None, 'import'): 254 raise PeachException("Import element did not have import attribute!") 255 256 importStr = self._getAttribute(child, 'import') 257 258 if child.hasAttributeNS(None, 'from'): 259 fromStr = self._getAttribute(child, 'from') 260 261 if importStr == "*": 262 module = __import__(PeachStr(fromStr), globals(), locals(), [ PeachStr(importStr) ], -1) 263 264 try: 265 # If we are a module with other modules in us then we have an __all__ 266 for item in module.__all__: 267 globals()["PeachXml_"+item] = getattr(module, item) 268 269 except: 270 # Else we just have some classes in us with no __all__ 271 for item in self.GetClassesInModule(module): 272 globals()["PeachXml_"+item] = getattr(module, item) 273 274 else: 275 module = __import__(PeachStr(fromStr), globals(), locals(), [ PeachStr(importStr) ], -1) 276 for item in importStr.split(','): 277 item = item.strip() 278 globals()["PeachXml_"+item] = getattr(module, item) 279 280 else: 281 globals()["PeachXml_"+importStr] = __import__(PeachStr(importStr), globals(), locals(), [], -1) 282 283 Holder.globals = globals() 284 Holder.locals = locals() 285 286 i = Element() 287 i.elementType = 'import' 288 i.importStr = self._getAttribute(child, 'import') 289 i.fromStr = self._getAttribute(child, 'from') 290 291 peach.append(i) 292 293 # Pass 3 -- Template 294 for child in ePeach.childNodes: 295 296 if child.nodeName == "Python": 297 code = self._getAttribute(child, "code") 298 if code != None: 299 exec(code) 300 301 elif child.nodeName == 'DataModel' or child.nodeName == 'Template': 302 # do something 303 template = self.HandleTemplate(child, peach) 304 template.node = child 305 peach.append(template) 306 peach.templates.append(template) 307 setattr(peach.templates, template.name, template) 308 309 # Pass 4 -- Data, Agent 310 for child in ePeach.childNodes: 311 312 if child.nodeName == 'Data': 313 # do data 314 data = self.HandleData(child, peach) 315 data.node = child 316 peach.append(data) 317 peach.data.append(data) 318 setattr(peach.data, data.name, data) 319 320 elif child.nodeName == 'Agent': 321 agent = self.HandleAgent(child, None) 322 agent.node = child 323 peach.append(agent) 324 peach.agents.append(agent) 325 setattr(peach.agents, agent.name, agent) 326 327 elif child.nodeName == 'StateModel' or child.nodeName == 'StateMachine': 328 stateMachine = self.HandleStateMachine(child, peach) 329 stateMachine.node = child 330 peach.append(stateMachine) 331 332 elif child.nodeName == 'Mutators': 333 mutators = self.HandleMutators(child, peach) 334 peach.mutators = mutators 335 336 # Pass 5 -- Tests 337 for child in ePeach.childNodes: 338 339 if child.nodeName == 'Test': 340 341 tests = self.HandleTest(child, None) 342 tests.node = child 343 peach.append(tests) 344 peach.tests.append(tests) 345 setattr(peach.tests, tests.name, tests) 346 347 elif child.nodeName == 'Run': 348 349 run = self.HandleRun(child, None) 350 run.node = child 351 peach.append(run) 352 peach.runs.append(run) 353 setattr(peach.runs, run.name, run) 354 355 # We suck, so fix this up 356 peach._FixParents() 357 peach.verifyDomMap() 358 #peach.printDomMap() 359 360 return peach
361
362 - def StripComments(self, node):
363 364 for child in node.childNodes: 365 366 if child.nodeName == '#comment': 367 node.removeChild(child) 368 else: 369 self.StripComments(child)
370
371 - def StripText(self, node):
372 373 for child in node.childNodes: 374 375 if child.nodeName == '#text': 376 node.removeChild(child) 377 else: 378 self.StripText(child)
379
380 - def GetRef(self, str, parent = None, childAttr = 'templates'):
381 ''' 382 Get the object indicated by ref. Currently the object must have 383 been defined prior to this point in the XML 384 ''' 385 386 #print "GetRef(%s) -- Starting" % str 387 388 origStr = str 389 baseObj = self.context 390 hasNamespace = False 391 isTopName = True 392 found = False 393 394 # Parse out a namespace 395 396 if str.find(":") > -1: 397 ns, tmp = str.split(':') 398 str = tmp 399 400 #print "GetRef(%s): Found namepsace: %s" % (str, ns) 401 402 # Check for namespace 403 if hasattr(self.context.namespaces, ns): 404 baseObj = getattr(self.context.namespaces, ns) 405 else: 406 #print self 407 raise PeachException("Unable to locate namespace: " + origStr) 408 409 hasNamespace = True 410 411 for name in str.split('.'): 412 413 #print "GetRef(%s): Looking for part %s" % (str, name) 414 415 found = False 416 417 if not hasNamespace and isTopName and parent != None: 418 # check parent, walk up from current parent to top 419 # level parent checking at each level. 420 421 while parent != None and not found: 422 423 #print "GetRef(%s): Parent.name: %s" % (name, parent.name) 424 425 if hasattr(parent, 'name') and parent.name == name: 426 baseObj = parent 427 found = True 428 429 elif hasattr(parent, name): 430 baseObj = getattr(parent, name) 431 found = True 432 433 elif hasattr(parent.children, name): 434 baseObj = getattr(parent.children, name) 435 found = True 436 437 elif hasattr(parent, childAttr) and hasattr( getattr(parent, childAttr), name): 438 baseObj = getattr( getattr(parent, childAttr), name) 439 found = True 440 441 else: 442 parent = parent.parent 443 444 # check base obj 445 elif hasattr(baseObj, name): 446 baseObj = getattr(baseObj, name) 447 found = True 448 449 # check childAttr 450 elif hasattr(baseObj, childAttr): 451 obj = getattr(baseObj, childAttr) 452 if hasattr(obj, name): 453 baseObj = getattr(obj, name) 454 found = True 455 456 else: 457 raise PeachException("Could not resolve ref %s" % origStr) 458 459 # check childAttr 460 if found == False and hasattr(baseObj, childAttr): 461 obj = getattr(baseObj, childAttr) 462 if hasattr(obj, name): 463 baseObj = getattr(obj, name) 464 found = True 465 466 # check across namespaces if we can't find it in ours 467 if isTopName and found == False: 468 for child in baseObj: 469 if child.elementType != 'namespace': 470 continue 471 472 #print "GetRef(%s): CHecking namepsace: %s" % (str, child.name) 473 ret = self._SearchNamespaces(child, name, childAttr) 474 if ret: 475 #print "GetRef(%s) Found part %s in namespace" % (str, name) 476 baseObj = ret 477 found = True 478 479 isTopName = False 480 481 if found == False: 482 raise PeachException("Unable to resolve reference: %s" % origStr) 483 484 return baseObj
485
486 - def _SearchNamespaces(self, obj, name, attr):
487 ''' 488 Used by GetRef to search across namespaces 489 ''' 490 491 #print "_SearchNamespaces(%s, %s)" % (obj.name, name) 492 #print "dir(obj): ", dir(obj) 493 494 # Namespaces are stuffed under this variable 495 # if we have it we should be it :) 496 if hasattr(obj, 'ns'): 497 obj = obj.ns 498 499 if hasattr(obj, name): 500 return getattr(obj, name) 501 502 elif hasattr(obj, attr) and hasattr(getattr(obj, attr), name): 503 return getattr(getattr(obj, attr), name) 504 505 for child in obj: 506 if child.elementType != 'namespace': 507 continue 508 509 ret = self._SearchNamespaces(child, name, attr) 510 if ret != None: 511 return ret 512 513 return None
514
515 - def GetDataRef(self, str):
516 ''' 517 Get the data object indicated by ref. Currently the object must 518 have been defined prior to this point in the XML. 519 ''' 520 521 origStr = str 522 baseObj = self.context 523 524 # Parse out a namespace 525 526 if str.find(":") > -1: 527 ns, tmp = str.split(':') 528 str = tmp 529 530 #print "GetRef(): Found namepsace:",ns 531 532 # Check for namespace 533 if hasattr(self.context.namespaces, ns): 534 baseObj = getattr(self.context.namespaces, ns) 535 else: 536 raise PeachException("Unable to locate namespace") 537 538 for name in str.split('.'): 539 540 # check base obj 541 if hasattr(baseObj, name): 542 baseObj = getattr(baseObj, name) 543 544 # check templates 545 elif hasattr(baseObj, 'data') and hasattr(baseObj.data, name): 546 baseObj = getattr(baseObj.data, name) 547 548 else: 549 raise PeachException("Could not resolve ref", origStr) 550 551 return baseObj
552 553 _regsHex = ( 554 re.compile(r"^([,\s]*\\x([a-zA-Z0-9]{2})[,\s]*)"), 555 re.compile(r"^([,\s]*%([a-zA-Z0-9]{2})[,\s]*)"), 556 re.compile(r"^([,\s]*0x([a-zA-Z0-9]{2})[,\s]*)"), 557 re.compile(r"^([,\s]*x([a-zA-Z0-9]{2})[,\s]*)"), 558 re.compile(r"^([,\s]*([a-zA-Z0-9]{2})[,\s]*)") 559 ) 560
561 - def GetValueFromNode(self, node):
562 563 value = None 564 type = 'literal' 565 566 if node.hasAttributeNS(None, 'valueType'): 567 type = self._getAttribute(node, 'valueType') 568 if not (type == 'literal' or type == 'hex'): 569 type = 'literal' 570 571 if node.hasAttributeNS(None, 'value'): 572 value = self._getAttribute(node, 'value') 573 #value = value.replace("\r", "") 574 #value = value.replace("\n", "") 575 576 #print "FROM VALUE: " + value 577 578 # Convert variouse forms of hex into a binary string 579 if type == 'hex': 580 581 ret = '' 582 583 for i in range(len(self._regsHex)): 584 match = self._regsHex[i].search(value) 585 if match != None: 586 while match != None: 587 ret += chr(int(match.group(2),16)) 588 value = self._regsHex[i].sub('', value) 589 match = self._regsHex[i].search(value) 590 break 591 592 return ret 593 594 #print "GetValueFromNode" 595 if value != None and (self._getAttribute(node, 'valueType') == 'string' or not node.hasAttributeNS(None, 'valueType')): 596 value = re.sub(r"([^\\])\\n", r"\1\n", value) 597 value = re.sub(r"([^\\])\\r", r"\1\r", value) 598 value = re.sub(r"([^\\])\\t", r"\1\t", value) 599 value = re.sub(r"([^\\])\\\\", r"\1\\", value) 600 value = re.sub(r"([^\\])\\n", r"\1\n", value) 601 value = re.sub(r"([^\\])\\r", r"\1\r", value) 602 value = re.sub(r"([^\\])\\t", r"\1\t", value) 603 value = re.sub(r"([^\\])\\\\", r"\1\\", value) 604 value = re.sub(r"^\\n", r"\n", value) 605 value = re.sub(r"^\\r", r"\r", value) 606 value = re.sub(r"^\\t", r"\t", value) 607 value = re.sub(r"^\\\\", r"\\", value) 608 609 return value
610
611 - def GetValueFromNodeNumber(self, node):
612 613 value = None 614 type = 'literal' 615 616 if node.hasAttributeNS(None, 'valueType'): 617 type = self._getAttribute(node, 'valueType') 618 if not (type == 'literal' or type == 'hex'): 619 type = 'literal' 620 621 if node.hasAttributeNS(None, 'value'): 622 value = self._getAttribute(node, 'value') 623 624 # Convert variouse forms of hex into a binary string 625 if type == 'hex': 626 627 ret = '' 628 629 for i in range(len(self._regsHex)): 630 match = self._regsHex[i].search(value) 631 if match != None: 632 while match != None: 633 ret += match.group(2) 634 value = self._regsHex[i].sub('', value) 635 match = self._regsHex[i].search(value) 636 break 637 638 return long(ret, 16) 639 640 elif type == 'literal': 641 value = eval(value) 642 643 #if value != None and (self._getAttribute(node, 'valueType') or not node.hasAttributeNS(None, 'valueType')): 644 # value = value.replace("\\r", "\r") 645 # value = value.replace("\\n", "\n") 646 # value = value.replace("\\t", "\t") 647 # value = value.replace("\\\\", "\\") 648 649 return value
650 651 # Handlers for Template ################################################### 652
653 - def HandleTemplate(self, node, parent):
654 ''' 655 Parse an element named Template. Can handle actual 656 Template elements and also reference Template elements. 657 658 e.g.: 659 660 <Template name="Xyz"> ... </Template> 661 662 or 663 664 <Template ref="Xyz" /> 665 ''' 666 667 template = None 668 669 # ref 670 671 if node.hasAttributeNS(None, 'ref'): 672 673 # We have a base template 674 obj = self.GetRef( self._getAttribute(node, 'ref') ) 675 676 template = obj.copy(parent) 677 template.ref = self._getAttribute(node, 'ref') 678 template.parent = parent 679 680 else: 681 template = Template(self._getAttribute(node, 'name')) 682 template.ref = None 683 template.parent = parent 684 685 # name 686 687 if node.hasAttributeNS(None, 'name'): 688 templateName = self._getAttribute(node, 'name') 689 template.name = templateName 690 691 template.elementType = 'template' 692 template.node = node 693 694 # children 695 696 for child in node.childNodes: 697 698 if child.nodeName == 'Block': 699 self.HandleBlock(child, template) 700 elif child.nodeName == 'String': 701 self.HandleString(child, template) 702 elif child.nodeName == 'Number': 703 self.HandleNumber(child, template) 704 elif child.nodeName == 'Flags': 705 self.HandleFlags(child, template) 706 elif child.nodeName == 'Blob': 707 self.HandleBlob(child, template) 708 elif child.nodeName == 'Transformer': 709 template.transformer = self.HandleTransformer(child, template) 710 elif child.nodeName == 'Sequence': 711 self.HandleSequence(child, template) 712 elif child.nodeName == 'Choice': 713 self.HandleChoice(child, template) 714 elif child.nodeName == 'Fixup': 715 self.HandleFixup(child, template) 716 else: 717 raise str("found unexpected node in Template: %s" % child.nodeName) 718 719 #template.printDomMap() 720 return template
721
722 - def HandleCommonTemplate(self, node, elem):
723 ''' 724 Handle the common children of data elements like String and Number. 725 ''' 726 727 elem.onArrayNext = self._getAttribute(node, "onArrayNext") 728 729 for child in node: 730 731 if child.nodeName == 'Relation': 732 relation = self.HandleRelation(child, elem) 733 elem.relations.append(relation) 734 elem.append(relation) 735 736 elif child.nodeName == 'Transformer': 737 elem.transformer = self.HandleTransformer(child, elem) 738 739 elif child.nodeName == 'Fixup': 740 self.HandleFixup(child, elem) 741 742 elif child.nodeName == 'Hint': 743 self.HandleHint(child, elem) 744 745 else: 746 raise str("found unexpected child node: %s" % child.nodeName)
747
748 - def HandleTransformer(self, node, parent):
749 ''' 750 Handle Transformer element 751 ''' 752 753 transformer = Transformer(parent) 754 755 childTransformer = None 756 params = [] 757 758 # class 759 760 if not node.hasAttributeNS(None, "class"): 761 raise PeachException("Transformer element missing class attribute") 762 763 generatorClass = self._getAttribute(node, "class") 764 transformer.classStr = generatorClass 765 766 # children 767 768 for child in node.childNodes: 769 770 if child.nodeName == 'Transformer': 771 if childTransformer != None: 772 raise PeachException("A transformer can only have one child transformer") 773 774 childTransformer = self.HandleTransformer(child, transformer) 775 continue 776 777 if child.nodeName == 'Param': 778 param = self.HandleParam(child, transformer) 779 transformer.append(param) 780 params.append([param.name, param.defaultValue]) 781 782 code = "PeachXml_"+generatorClass + '(' 783 784 isFirst = True 785 for param in params: 786 if not isFirst: 787 code += ', ' 788 else: 789 isFirst = False 790 791 code += PeachStr(param[1]) 792 793 code += ')' 794 795 trans = eval(code, globals(), locals()) 796 797 if childTransformer != None: 798 trans.setAnotherTransformer(childTransformer.transformer) 799 800 transformer.transformer = trans 801 802 if parent != None: 803 parent.transformer = transformer 804 parent.append(transformer) 805 806 return transformer
807
808 - def HandleFixup(self, node, parent):
809 ''' 810 Handle Fixup element 811 ''' 812 813 fixup = Fixup(parent) 814 815 params = [] 816 817 # class 818 819 if not node.hasAttributeNS(None, "class"): 820 raise PeachException("Fixup element missing class attribute") 821 822 fixup.classStr = self._getAttribute(node, "class") 823 824 # children 825 826 for child in node.childNodes: 827 828 if child.nodeName == 'Param': 829 param = self.HandleParam(child, fixup) 830 fixup.append(param) 831 params.append([param.name, param.defaultValue]) 832 833 code = "PeachXml_"+fixup.classStr + '(' 834 835 isFirst = True 836 for param in params: 837 if not isFirst: 838 code += ', ' 839 else: 840 isFirst = False 841 842 code += PeachStr(param[1]) 843 844 code += ')' 845 846 fixup.fixup = eval(code, globals(), locals()) 847 848 if parent != None: 849 parent.fixup = fixup 850 parent.append(fixup) 851 852 return fixup
853
854 - def HandleRelation(self, node, elem):
855 856 if not node.hasAttributeNS(None, "type"): 857 raise PeachException("Relation element does not have type attribute") 858 859 type = self._getAttribute(node, "type") 860 of = self._getAttribute(node, "of") 861 From = self._getAttribute(node, "from") 862 name = self._getAttribute(node, "name") 863 when = self._getAttribute(node, "when") 864 expressionGet = self._getAttribute(node, "expressionGet") 865 expressionSet = self._getAttribute(node, "expressionSet") 866 867 if of == None and From == None and when == None: 868 raise PeachException("Relation element does not have of, from, or when attribute.") 869 870 if type not in ['size', 'count', 'index', 'when']: 871 raise PeachException("Unknown type value in Relation element") 872 873 relation = Relation(name, elem) 874 relation.of = of 875 relation.From = From 876 relation.type = type 877 relation.node = node 878 relation.when = when 879 relation.expressionGet = expressionGet 880 relation.expressionSet = expressionSet 881 882 # Logic checks 883 if type == 'size' and of == None: 884 raise PeachException("Size relation only supports of attribute, not from.") 885 886 return relation
887
888 - def _HandleOccurs(self, node, element):
889 ''' 890 Grab min, max, and generated Occurs attributes 891 ''' 892 893 if node.hasAttributeNS(None, 'generatedOccurs'): 894 element.generatedOccurs = self._getAttribute(node, 'generatedOccurs') 895 else: 896 element.generatedOccurs = 10 897 898 minOccurs = self._getAttribute(node, 'minOccurs') 899 maxOccurs = self._getAttribute(node, 'maxOccurs') 900 901 if minOccurs == None: 902 minOccurs = 1 903 else: 904 minOccurs = eval(minOccurs) 905 906 if maxOccurs == None: 907 maxOccurs = 1 908 else: 909 maxOccurs = eval(maxOccurs) 910 911 if minOccurs != None and maxOccurs != None: 912 element.minOccurs = int(minOccurs) 913 element.maxOccurs = int(maxOccurs) 914 915 elif minOccurs != None and maxOccurs == None: 916 element.minOccurs = int(minOccurs) 917 element.maxOccurs = 1024 918 919 elif maxOccurs != None and minOccurs == None: 920 element.minOccurs = 0 921 element.maxOccurs = int(maxOccurs) 922 923 else: 924 element.minOccurs = 1 925 element.maxOccurs = 1
926
927 - def HandleBlock(self, node, parent):
928 929 # name 930 931 if node.hasAttributeNS(None, 'name'): 932 name = self._getAttribute(node, 'name') 933 else: 934 name = None 935 936 # ref 937 938 if node.hasAttributeNS(None, 'ref'): 939 940 if name == None or len(name) == 0: 941 name = Element.getUniqueName() 942 943 # We have a base template 944 obj = self.GetRef( self._getAttribute(node, 'ref'), parent ) 945 946 block = obj.copy(parent) 947 block.name = name 948 block.parent = parent 949 block.ref = self._getAttribute(node, 'ref') 950 951 # Block may not be a block! 952 block.toXml = new.instancemethod(BlockToXml, block, block.__class__) 953 block.elementType = 'block' 954 955 else: 956 block = dom.Block(name, parent) 957 block.ref = None 958 959 block.node = node 960 961 # alignment 962 963 try: 964 alignment = self._getAttribute(node, 'alignment') 965 if len(alignment) == 0: 966 alignment = None 967 except: 968 alignment = None 969 970 if alignment != None: 971 block.isAligned = True 972 block.alignment = int(alignment)**2 973 974 # minOccurs and maxOccurs 975 976 self._HandleOccurs(node, block) 977 978 # children 979 980 for child in node.childNodes: 981 982 if child.nodeName == 'Block': 983 self.HandleBlock(child, block) 984 elif child.nodeName == 'String': 985 self.HandleString(child, block) 986 elif child.nodeName == 'Number': 987 self.HandleNumber(child, block) 988 elif child.nodeName == 'Flags': 989 self.HandleFlags(child, block) 990 elif child.nodeName == 'Blob': 991 self.HandleBlob(child, block) 992 elif child.nodeName == 'Choice': 993 self.HandleChoice(child, block) 994 elif child.nodeName == 'Transformer': 995 block.transformer = self.HandleTransformer(child, block) 996 elif child.nodeName == 'Relation': 997 relation = self.HandleRelation(child, block) 998 block.relations.append(relation) 999 block.append(relation) 1000 elif child.nodeName == 'Fixup': 1001 self.HandleFixup(child, block) 1002 elif child.nodeName == 'Hint': 1003 self.HandleHint(child, block) 1004 1005 else: 1006 raise PeachException(PeachStr("found unexpected node in Block: %s" % child.nodeName)) 1007 1008 # Add to parent 1009 1010 parent.append(block) 1011 return block
1012
1013 - def HandleMutators(self, node, parent):
1014 # name 1015 1016 if node.hasAttributeNS(None, 'name'): 1017 name = self._getAttribute(node, 'name') 1018 else: 1019 name = None 1020 1021 mutators = dom.Mutators(name, parent) 1022 mutators.node = node 1023 1024 # children 1025 1026 for child in node.childNodes: 1027 1028 if child.nodeName != 'Mutator': 1029 raise PeachException(PeachStr("Found unexpected node in Mutators element: %s" % child.NodeName)) 1030 1031 if not child.hasAttributeNS(None, 'class'): 1032 raise PeachException("Mutator element does not have required class attribute") 1033 1034 className = "PeachXml_" + self._getAttribute(child, 'class') + "(self.context)" 1035 1036 mutator = Mutator(self._getAttribute(child, 'class'), mutators) 1037 mutator.mutator = eval(className, globals(), locals()) 1038 mutators.append(mutator) 1039 1040 parent.append(mutators) 1041 return mutators
1042 1043
1044 - def HandleChoice(self, node, parent):
1045 1046 # name 1047 1048 if node.hasAttributeNS(None, 'name'): 1049 name = self._getAttribute(node, 'name') 1050 else: 1051 name = None 1052 1053 # ref 1054 1055 if node.hasAttributeNS(None, 'ref'): 1056 1057 if name == None or len(name) == 0: 1058 name = Element.getUniqueName() 1059 1060 # We have a base template 1061 obj = self.GetRef( self._getAttribute(node, 'ref'), parent ) 1062 1063 #print "About to deep copy: ", obj, " for ref: ", self._getAttribute(node, 'ref') 1064 1065 block = obj.copy(parent) 1066 block.name = name 1067 block.parent = parent 1068 block.ref = self._getAttribute(node, 'ref') 1069 1070 else: 1071 block = Choice(name, parent) 1072 block.ref = None 1073 1074 block.elementType = 'choice' 1075 block.node = node 1076 1077 # minOccurs and maxOccurs 1078 self._HandleOccurs(node, block) 1079 1080 # children 1081 1082 for child in node.childNodes: 1083 1084 if child.nodeName == 'Block': 1085 self.HandleBlock(child, block) 1086 elif child.nodeName == 'String': 1087 self.HandleString(child, block) 1088 elif child.nodeName == 'Number': 1089 self.HandleNumber(child, block) 1090 elif child.nodeName == 'Flags': 1091 self.HandleFlags(child, block) 1092 elif child.nodeName == 'Blob': 1093 self.HandleBlob(child, block) 1094 elif child.nodeName == 'Transformer': 1095 block.transformer = self.HandleTransformer(child, block) 1096 elif child.nodeName == 'Sequence': 1097 self.HandleSequence(child, block) 1098 elif child.nodeName == 'Choice': 1099 self.HandleChoice(child, block) 1100 else: 1101 raise PeachException(PeachStr("found unexpected node in Sequence: %s" % child.nodeName)) 1102 1103 parent.append(block) 1104 return block
1105
1106 - def _getAttribute(self, node, name):
1107 1108 if not node.hasAttributeNS(None, name): 1109 return None 1110 1111 return PeachStr(node.getAttributeNS(None, name))
1112
1113 - def _getValueType(self, node):
1114 1115 valueType = self._getAttribute(node, 'valueType') 1116 if valueType == None: 1117 return 'string' 1118 1119 return valueType
1120
1121 - def HandleString(self, node, parent):
1122 1123 # name 1124 1125 if node.hasAttributeNS(None, 'name'): 1126 name = self._getAttribute(node, 'name') 1127 else: 1128 name = None 1129 1130 string = String(name, parent) 1131 string.node = node 1132 1133 # value 1134 1135 string.defaultValue = PeachStr(self.GetValueFromNode(node)) 1136 string.valueType = self._getValueType(node) 1137 #print "HandleString(%s): Before handletype: [%s]" % (string.name, string.defaultValue) 1138 string.defaultValue = self._HandleValueType(string.defaultValue, string.valueType) 1139 #print "HandleString(%s): After handletype: [%s]" % (string.name, string.defaultValue) 1140 1141 # tokens 1142 1143 if node.hasAttributeNS(None, 'tokens'): 1144 string.tokens = self._getAttribute(node, 'tokens') 1145 else: 1146 string.tokens = None 1147 1148 # padCharacter 1149 1150 if node.hasAttributeNS(None, 'padCharacter'): 1151 val = str(self._getAttribute(node, 'padCharacter')) 1152 val = val.replace("'", "\\'") 1153 string.padCharacter = eval("'''" + val + "'''") 1154 1155 # type 1156 1157 type = self._getAttribute(node, 'type') 1158 if type == None or len(type) == 0: 1159 string.type = 'char' 1160 1161 elif not (type == 'char' or type == 'wchar' or type == 'utf8'): 1162 raise PeachException("Unknown type of String") 1163 1164 else: 1165 string.type = type 1166 1167 if type == 'wchar': 1168 string.padCharacter = string.padCharacter * 2 1169 1170 # isStatic 1171 1172 isStatic = self._getAttribute(node, 'isStatic') 1173 if isStatic == None or len(isStatic) == 0: 1174 string.isStatic = False 1175 1176 elif isStatic.lower() == 'true': 1177 string.isStatic = True 1178 1179 elif isStatic.lower() == 'false': 1180 string.isStatic = False 1181 1182 else: 1183 raise PeachException("Unknown isStatic of String") 1184 1185 1186 # nullTerminated (optional) 1187 1188 nullTerminated = self._getAttribute(node, 'nullTerminated') 1189 if nullTerminated == None or len(nullTerminated) == 0: 1190 nullTerminated = 'false' 1191 1192 if nullTerminated.lower() == 'true': 1193 string.nullTerminated = True 1194 elif nullTerminated.lower() == 'false': 1195 string.nullTerminated = False 1196 else: 1197 raise PeachException("nullTerminated should be true or false") 1198 1199 # length (bytes) 1200 1201 if node.hasAttributeNS(None, 'lengthType') and self._getAttribute(node, 'lengthType') == 'calc': 1202 string.lengthType = self._getAttribute(node, 'lengthType') 1203 string.lengthCalc = self._getAttribute(node, 'length') 1204 string.length = -1 1205 1206 elif node.hasAttributeNS(None, 'length'): 1207 length = self._getAttribute(node, 'length') 1208 if length == None or len(length) == 0: 1209 length = None 1210 1211 try: 1212 if length != None: 1213 string.length = int(length) 1214 else: 1215 string.length = None 1216 except: 1217 raise PeachException("length must be a number or missing %s" % length) 1218 1219 # minOccurs and maxOccurs 1220 self._HandleOccurs(node, string) 1221 1222 # Handle any common children 1223 1224 self.HandleCommonTemplate(node, string) 1225 1226 parent.append(string) 1227 return string
1228
1229 - def HandleNumber(self, node, parent):
1230 1231 # name 1232 1233 if node.hasAttributeNS(None, 'name'): 1234 name = self._getAttribute(node, 'name') 1235 else: 1236 name = None 1237 1238 number = Number(name, parent) 1239 number.node = node 1240 1241 # value 1242 1243 number.defaultValue = PeachStr(self.GetValueFromNodeNumber(node)) 1244 number.valueType = self._getValueType(node) 1245 1246 if number.defaultValue != None: 1247 try: 1248 number.defaultValue = long(number.defaultValue) 1249 except: 1250 raise PeachException("Error: The default value for <Number> elements must be an integer.") 1251 1252 # size (bits) 1253 1254 size = self._getAttribute(node, 'size') 1255 number.size = int(size) 1256 1257 if not number.size in number._allowedSizes: 1258 raise PeachException("invalid size") 1259 1260 # endian (optional) 1261 1262 number.endian = self._getAttribute(node, 'endian') 1263 if number.endian == None or len(number.endian) == 0: 1264 number.endian = 'little' 1265 1266 if number.endian == 'network': 1267 number.endian = 'big' 1268 1269 if number.endian != 'little' and number.endian != 'big': 1270 raise PeachException("invalid endian %s" % number.endian) 1271 1272 1273 # isStatic 1274 1275 isStatic = self._getAttribute(node, 'isStatic') 1276 if isStatic == None or len(isStatic) == 0: 1277 number.isStatic = False 1278 1279 elif isStatic.lower() == 'true': 1280 number.isStatic = True 1281 1282 elif isStatic.lower() == 'false': 1283 number.isStatic = False 1284 1285 else: 1286 raise PeachException("Unknown isStatic of Number") 1287 1288 # signed (optional) 1289 1290 signed = self._getAttribute(node, 'signed') 1291 if signed == None or len(signed) == 0: 1292 signed = 'false' 1293 1294 if signed.lower() == 'true': 1295 number.signed = True 1296 elif signed.lower() == 'false': 1297 number.signed = False 1298 else: 1299 raise PeachException("signed must be true or false") 1300 1301 # minOccurs and maxOccurs 1302 self._HandleOccurs(node, number) 1303 1304 # Handle any common children 1305 1306 self.HandleCommonTemplate(node, number) 1307 1308 parent.append(number) 1309 return number
1310 1311
1312 - def HandleFlags(self, node, parent):
1313 if node.hasAttributeNS(None, 'name'): 1314 name = self._getAttribute(node, 'name') 1315 else: 1316 name = None 1317 1318 flags = dom.Flags(name, parent) 1319 flags.node = node 1320 1321 # length (in bits) 1322 1323 length = self._getAttribute(node, 'size') 1324 flags.length = int(length) 1325 if flags.length % 2 != 0: 1326 raise PeachException("length must be multiple of 2") 1327 1328 if flags.length not in [8, 16, 24, 32, 64]: 1329 raise PeachException("Flags size must be one of 8, 16, 24, 32, or 64.") 1330 1331 # endian 1332 1333 if node.hasAttributeNS(None, 'endian'): 1334 flags.endian = self._getAttribute(node, 'endian') 1335 1336 if not ( flags.endian == 'little' or flags.endian == 'big' ): 1337 raise PeachException("Invalid endian type on Flags element") 1338 1339 else: 1340 flags.endian = 'little' 1341 1342 # children 1343 1344 for child in node.childNodes: 1345 1346 if child.nodeName == 'Flag': 1347 self.HandleFlag(child, flags) 1348 else: 1349 raise PeachException(PeachStr("found unexpected node in Flags: %s" % child.nodeName)) 1350 1351 parent.append(flags) 1352 return flags
1353 1354
1355 - def HandleFlag(self, node, parent):
1356 if node.hasAttributeNS(None, 'name'): 1357 name = self._getAttribute(node, 'name') 1358 else: 1359 name = None 1360 1361 flag = Flag(name, parent) 1362 flag.node = node 1363 1364 # value 1365 1366 flag.defaultValue = PeachStr(self.GetValueFromNode(node)) 1367 flag.valueType = self._getValueType(node) 1368 1369 # position (in bits) 1370 1371 position = self._getAttribute(node, 'position') 1372 flag.position = int(position) 1373 1374 # length (in bits) 1375 1376 length = self._getAttribute(node, 'size') 1377 flag.length = int(length) 1378 1379 if flag.position > parent.length: 1380 raise PeachException("Invalid position, parent not big enough") 1381 1382 if flag.position + flag.length > parent.length: 1383 raise PeachException("Invalid length, parent not big enough") 1384 1385 1386 # Handle any common children 1387 1388 self.HandleCommonTemplate(node, flag) 1389 1390 parent.append(flag) 1391 return flag
1392 1393
1394 - def HandleBlob(self, node, parent):
1395 if node.hasAttributeNS(None, 'name'): 1396 name = self._getAttribute(node, 'name') 1397 else: 1398 name = None 1399 1400 blob = Blob(name, parent) 1401 blob.node = node 1402 1403 # value 1404 1405 blob.defaultValue = PeachStr(self.GetValueFromNode(node)) 1406 blob.valueType = self._getValueType(node) 1407 1408 #print "Value of blob: ", repr(blob.defaultValue) 1409 1410 # Hex handled elsewere. 1411 if blob.valueType == 'literal': 1412 blob.defaultValue = PeachStr(eval(blob.defaultValue)) 1413 1414 # length (in bytes) 1415 1416 if node.hasAttributeNS(None, 'lengthType') and self._getAttribute(node, 'lengthType') == 'calc': 1417 blob.lengthType = self._getAttribute(node, 'lengthType') 1418 blob.lengthCalc = self._getAttribute(node, 'length') 1419 blob.length = -1 1420 1421 elif node.hasAttributeNS(None, 'length'): 1422 length = self._getAttribute(node, 'length') 1423 if length != None and len(length) != 0: 1424 blob.length = int(length) 1425 else: 1426 blob.length = None 1427 1428 # isStatic 1429 1430 isStatic = self._getAttribute(node, 'isStatic') 1431 if isStatic == None or len(isStatic) == 0: 1432 blob.isStatic = False 1433 1434 elif isStatic.lower() == 'true': 1435 blob.isStatic = True 1436 1437 elif isStatic.lower() == 'false': 1438 blob.isStatic = False 1439 1440 else: 1441 raise PeachException("Unknown isStatic of Blob") 1442 1443 # padValue 1444 1445 if node.hasAttributeNS(None, 'padValue'): 1446 blob.padValue = self._getAttribute(node, 'padValue') 1447 else: 1448 blob.padValue = "\0" 1449 1450 # minOccurs and maxOccurs 1451 self._HandleOccurs(node, blob) 1452 1453 # Handle any common children 1454 1455 self.HandleCommonTemplate(node, blob) 1456 1457 parent.append(blob) 1458 return blob
1459 1460 1461 # Handlers for Data ################################################### 1462
1463 - def HandleData(self, node, parent):
1464 1465 data = None 1466 1467 # name 1468