diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /devtools/bin/vsdotnetxmlparser.py | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'devtools/bin/vsdotnetxmlparser.py')
| -rw-r--r-- | devtools/bin/vsdotnetxmlparser.py | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/devtools/bin/vsdotnetxmlparser.py b/devtools/bin/vsdotnetxmlparser.py new file mode 100644 index 0000000..e9e643a --- /dev/null +++ b/devtools/bin/vsdotnetxmlparser.py @@ -0,0 +1,218 @@ + +import re +import os, ezxmlfile + + +# Until I find a better XML parser, this one acts like xml.parsers.expat but it preserves the \r's and \n's inside +# attribute strings in .vcproj files. +class VSDotNetXMLParserError: + pass + + +def GetLineNumber( data, filePos ): + lines = data.split( '\n' ) + testOffset = 0 + for i,x in enumerate( lines ): + testOffset += len(x) + 1 + if testOffset >= filePos: + return i+1 + return -1 + + +verbose = 0 + +class VSDotNetXMLParser: + def __init__( self ): + self.XmlDeclHandler = None + self.StartElementHandler = None + self.EndElementHandler = None + + self.reStartElement = re.compile( r'\s*<(?P<blockName>[^ /\t\n\r\f\v>]+)(?P<noAttrs>>)?' ) + self.reEndElement = re.compile( r'\s*</(?P<blockName>\S+)>' ) + self.reAttribute = re.compile( r'\s*(?P<attrName>\S+)="(?P<attrValue>.*?)"', re.DOTALL ) + self.reEndAttributes = re.compile( r'\s*>' ) + self.reEndAttributesNoSubElements = re.compile( r'\s*(\/|\?)>' ) + + def Parse( self, data, final ): + curFilePos = 0 + elementDepth = 0 + self.__bReadXMLHeader = 0 + + # First read the XML header. + while 1: + m = self.reStartElement.match( data, curFilePos ) + if m: + curFilePos = m.end() + + # Read the element name and get all its attributes. + elementName = m.group('blockName') + attributes = [] + + # No attributes? + if m.group('noAttrs') == '>': + elementDepth += 1 + self.__CallElementHandler( elementName, [], 0 ) + continue + + if verbose: + print 'elem: ' + elementName + + while 1: + m = self.reAttribute.match( data, curFilePos ) + if m: + if verbose: + print 'attr: %s, value: %s' % (m.group('attrName'), m.group('attrValue')) + curFilePos = m.end() + attributes.append( m.group('attrName') ) + attributes.append( m.group('attrValue') ) + continue + + m = self.reEndAttributesNoSubElements.match( data, curFilePos ) + if m: + if verbose: + print 'endattr' + curFilePos = m.end() + self.__CallElementHandler( elementName, attributes, 1 ) + break + + m = self.reEndAttributes.match( data, curFilePos ) + if m: + if verbose: + print 'endattr2' + curFilePos = m.end() + elementDepth += 1 + self.__CallElementHandler( elementName, attributes, 0 ) + break + else: + raise VSDotNetXMLParserError + + else: + m = self.reEndElement.match( data, curFilePos ) + if m: + if verbose: + print 'endelem' + curFilePos = m.end() + elementDepth -= 1 + self.EndElementHandler( '<end element name not supported>' ) + else: + # When we're done with the file, the depth should be 0. + if elementDepth != 0: + print 'line %d, depth: %d' % (GetLineNumber( data, curFilePos ), elementDepth) + raise VSDotNetXMLParserError + break + + # Must at least have a header! + if not self.__bReadXMLHeader: + raise VSDotNetXMLParserError + + + def __CallElementHandler( self, elementName, attributes, bEnd ): + if self.__bReadXMLHeader: + self.StartElementHandler( elementName, attributes ) + if bEnd: + self.EndElementHandler( '<end element name not supported>' ) + else: + # First element must be the XML header. + if elementName != '?xml' or not bEnd: + raise VSDotNetXMLParserError + + versionString = encodingString = None + for(i,a) in enumerate( attributes ): + if (i & 1) == 0: + if a == 'version': + versionString = attributes[i+1] + elif a == 'encoding': + encodingString = attributes[i+1] + + if not versionString or not encodingString: + raise VSDotNetXMLParserError + + self.XmlDeclHandler( versionString, encodingString, 1 ) + self.__bReadXMLHeader = 1 + + + +def LoadVCProj( filename ): + f = open( filename, 'rb' ) + return ezxmlfile.EZXMLFile( f.read() ) + + +def FindInList( theList, elem ): + for i,val in enumerate( theList ): + if val == elem: + return i + return -1 + + +def IsExcludedFromProjects( e, validProjects ): + for c in e.Children: + if c.Name == "FileConfiguration": + if FindInList( validProjects, c.GetAttributeValue( 'Name' ) ) != -1: + if c.GetAttributeValue( 'ExcludedFromBuild' ) == 'TRUE': + return 1 + return 0 + + +def StripConfigBlocks_R( e, validProjects ): + newChildren = [] + + # Strip out unwanted configuration blocks. + if e.Name == 'Configuration' or e.Name == 'FileConfiguration': + bValid = 0 + v = e.GetAttributeValue( 'Name' ) + for p in validProjects: + if p == v: + bValid = 1 + break + + if not bValid: + return 0 + + # Strip out files that are excluded from the validProjects. + if e.Name == "File": + if IsExcludedFromProjects( e, validProjects ): + return 0 + + + # Recurse.. + newChildren = [] + for child in e.Children: + if StripConfigBlocks_R( child, validProjects ): + newChildren.append( child ) + e.Children = newChildren + return 1 + + +def RemoveEmptyFilterBlocks_R( e ): + if e.Name == "Filter" and len( e.Children ) == 0: + return 0 + + # Recurse.. + newChildren = [] + for child in e.Children: + if RemoveEmptyFilterBlocks_R( child ): + newChildren.append( child ) + e.Children = newChildren + return 1 + + +def WriteSeparateVCProj( f, validProjects, outFilename ): + outFile = open( outFilename, 'wb' ) + + # Make a copy of f so we're not trashing its data. + #f = copy.deepcopy( f ) + + # Strip out the source control crap. + e = f.GetElement( 'VisualStudioProject' ) + e.RemoveAttribute( 'SccProjectName' ) + e.RemoveAttribute( 'SccAuxPath' ) + e.RemoveAttribute( 'SccLocalPath' ) + e.RemoveAttribute( 'SccProvider' ) + + # Now strip out blocks that are for + StripConfigBlocks_R( f.RootElement, validProjects ) + RemoveEmptyFilterBlocks_R( f.RootElement ) + + f.WriteFile( outFile ) + outFile.close() + print "Wrote %s" % outFilename |