mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-03 05:49:41 +03:00
1
This commit is contained in:
218
devtools/bin/vsdotnetxmlparser.py
Normal file
218
devtools/bin/vsdotnetxmlparser.py
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user