| Home | Trees | Indices | Help |
|
|---|
|
|
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
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
71 SchemeRegistryResolver.__init__(self)
72
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
142 '''
143 The Peach 2.0 XML -> Peach DOM parser. Uses 4Suite XML
144 library.
145 '''
146
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
159 '''
160 Parse a string as Peach XML.
161 '''
162
163 doc = Ft.Xml.Domlette.NonvalidatingReader.parseString(xml)
164 return self.HandleDocument(doc)
165
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
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
363
364 for child in node.childNodes:
365
366 if child.nodeName == '#comment':
367 node.removeChild(child)
368 else:
369 self.StripComments(child)
370
372
373 for child in node.childNodes:
374
375 if child.nodeName == '#text':
376 node.removeChild(child)
377 else:
378 self.StripText(child)
379
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1107
1108 if not node.hasAttributeNS(None, name):
1109 return None
1110
1111 return PeachStr(node.getAttributeNS(None, name))
1112
1114
1115 valueType = self._getAttribute(node, 'valueType')
1116 if valueType == None:
1117 return 'string'
1118
1119 return valueType
1120
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
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
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
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
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