Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.5 KiB

  1. import re
  2. import os, ezxmlfile
  3. # Until I find a better XML parser, this one acts like xml.parsers.expat but it preserves the \r's and \n's inside
  4. # attribute strings in .vcproj files.
  5. class VSDotNetXMLParserError:
  6. pass
  7. def GetLineNumber( data, filePos ):
  8. lines = data.split( '\n' )
  9. testOffset = 0
  10. for i,x in enumerate( lines ):
  11. testOffset += len(x) + 1
  12. if testOffset >= filePos:
  13. return i+1
  14. return -1
  15. verbose = 0
  16. class VSDotNetXMLParser:
  17. def __init__( self ):
  18. self.XmlDeclHandler = None
  19. self.StartElementHandler = None
  20. self.EndElementHandler = None
  21. self.reStartElement = re.compile( r'\s*<(?P<blockName>[^ /\t\n\r\f\v>]+)(?P<noAttrs>>)?' )
  22. self.reEndElement = re.compile( r'\s*</(?P<blockName>\S+)>' )
  23. self.reAttribute = re.compile( r'\s*(?P<attrName>\S+)="(?P<attrValue>.*?)"', re.DOTALL )
  24. self.reEndAttributes = re.compile( r'\s*>' )
  25. self.reEndAttributesNoSubElements = re.compile( r'\s*(\/|\?)>' )
  26. def Parse( self, data, final ):
  27. curFilePos = 0
  28. elementDepth = 0
  29. self.__bReadXMLHeader = 0
  30. # First read the XML header.
  31. while 1:
  32. m = self.reStartElement.match( data, curFilePos )
  33. if m:
  34. curFilePos = m.end()
  35. # Read the element name and get all its attributes.
  36. elementName = m.group('blockName')
  37. attributes = []
  38. # No attributes?
  39. if m.group('noAttrs') == '>':
  40. elementDepth += 1
  41. self.__CallElementHandler( elementName, [], 0 )
  42. continue
  43. if verbose:
  44. print 'elem: ' + elementName
  45. while 1:
  46. m = self.reAttribute.match( data, curFilePos )
  47. if m:
  48. if verbose:
  49. print 'attr: %s, value: %s' % (m.group('attrName'), m.group('attrValue'))
  50. curFilePos = m.end()
  51. attributes.append( m.group('attrName') )
  52. attributes.append( m.group('attrValue') )
  53. continue
  54. m = self.reEndAttributesNoSubElements.match( data, curFilePos )
  55. if m:
  56. if verbose:
  57. print 'endattr'
  58. curFilePos = m.end()
  59. self.__CallElementHandler( elementName, attributes, 1 )
  60. break
  61. m = self.reEndAttributes.match( data, curFilePos )
  62. if m:
  63. if verbose:
  64. print 'endattr2'
  65. curFilePos = m.end()
  66. elementDepth += 1
  67. self.__CallElementHandler( elementName, attributes, 0 )
  68. break
  69. else:
  70. raise VSDotNetXMLParserError
  71. else:
  72. m = self.reEndElement.match( data, curFilePos )
  73. if m:
  74. if verbose:
  75. print 'endelem'
  76. curFilePos = m.end()
  77. elementDepth -= 1
  78. self.EndElementHandler( '<end element name not supported>' )
  79. else:
  80. # When we're done with the file, the depth should be 0.
  81. if elementDepth != 0:
  82. print 'line %d, depth: %d' % (GetLineNumber( data, curFilePos ), elementDepth)
  83. raise VSDotNetXMLParserError
  84. break
  85. # Must at least have a header!
  86. if not self.__bReadXMLHeader:
  87. raise VSDotNetXMLParserError
  88. def __CallElementHandler( self, elementName, attributes, bEnd ):
  89. if self.__bReadXMLHeader:
  90. self.StartElementHandler( elementName, attributes )
  91. if bEnd:
  92. self.EndElementHandler( '<end element name not supported>' )
  93. else:
  94. # First element must be the XML header.
  95. if elementName != '?xml' or not bEnd:
  96. raise VSDotNetXMLParserError
  97. versionString = encodingString = None
  98. for(i,a) in enumerate( attributes ):
  99. if (i & 1) == 0:
  100. if a == 'version':
  101. versionString = attributes[i+1]
  102. elif a == 'encoding':
  103. encodingString = attributes[i+1]
  104. if not versionString or not encodingString:
  105. raise VSDotNetXMLParserError
  106. self.XmlDeclHandler( versionString, encodingString, 1 )
  107. self.__bReadXMLHeader = 1
  108. def LoadVCProj( filename ):
  109. f = open( filename, 'rb' )
  110. return ezxmlfile.EZXMLFile( f.read() )
  111. def FindInList( theList, elem ):
  112. for i,val in enumerate( theList ):
  113. if val == elem:
  114. return i
  115. return -1
  116. def IsExcludedFromProjects( e, validProjects ):
  117. for c in e.Children:
  118. if c.Name == "FileConfiguration":
  119. if FindInList( validProjects, c.GetAttributeValue( 'Name' ) ) != -1:
  120. if c.GetAttributeValue( 'ExcludedFromBuild' ) == 'TRUE':
  121. return 1
  122. return 0
  123. def StripConfigBlocks_R( e, validProjects ):
  124. newChildren = []
  125. # Strip out unwanted configuration blocks.
  126. if e.Name == 'Configuration' or e.Name == 'FileConfiguration':
  127. bValid = 0
  128. v = e.GetAttributeValue( 'Name' )
  129. for p in validProjects:
  130. if p == v:
  131. bValid = 1
  132. break
  133. if not bValid:
  134. return 0
  135. # Strip out files that are excluded from the validProjects.
  136. if e.Name == "File":
  137. if IsExcludedFromProjects( e, validProjects ):
  138. return 0
  139. # Recurse..
  140. newChildren = []
  141. for child in e.Children:
  142. if StripConfigBlocks_R( child, validProjects ):
  143. newChildren.append( child )
  144. e.Children = newChildren
  145. return 1
  146. def RemoveEmptyFilterBlocks_R( e ):
  147. if e.Name == "Filter" and len( e.Children ) == 0:
  148. return 0
  149. # Recurse..
  150. newChildren = []
  151. for child in e.Children:
  152. if RemoveEmptyFilterBlocks_R( child ):
  153. newChildren.append( child )
  154. e.Children = newChildren
  155. return 1
  156. def WriteSeparateVCProj( f, validProjects, outFilename ):
  157. outFile = open( outFilename, 'wb' )
  158. # Make a copy of f so we're not trashing its data.
  159. #f = copy.deepcopy( f )
  160. # Strip out the source control crap.
  161. e = f.GetElement( 'VisualStudioProject' )
  162. e.RemoveAttribute( 'SccProjectName' )
  163. e.RemoveAttribute( 'SccAuxPath' )
  164. e.RemoveAttribute( 'SccLocalPath' )
  165. e.RemoveAttribute( 'SccProvider' )
  166. # Now strip out blocks that are for
  167. StripConfigBlocks_R( f.RootElement, validProjects )
  168. RemoveEmptyFilterBlocks_R( f.RootElement )
  169. f.WriteFile( outFile )
  170. outFile.close()
  171. print "Wrote %s" % outFilename