Sync BaseTools Branch (version r2271) to EDKII main trunk.
BaseTool Branch: https://edk2-buildtools.svn.sourceforge.net/svnroot/edk2-buildtools/branches/Releases/BaseTools_r2100 Signed-off-by: lgao4 Reviewed-by: hchen30 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12214 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
503
BaseTools/Source/Python/UPT/Xml/IniToXml.py
Normal file
503
BaseTools/Source/Python/UPT/Xml/IniToXml.py
Normal file
@ -0,0 +1,503 @@
|
||||
## @file
|
||||
# This file is for converting package information data file to xml file.
|
||||
#
|
||||
# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# This program and the accompanying materials are licensed and made available
|
||||
# under the terms and conditions of the BSD License which accompanies this
|
||||
# distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
|
||||
'''
|
||||
IniToXml
|
||||
'''
|
||||
|
||||
import os.path
|
||||
import re
|
||||
from time import strftime
|
||||
from time import localtime
|
||||
|
||||
import Logger.Log as Logger
|
||||
from Logger.ToolError import UPT_INI_PARSE_ERROR
|
||||
from Logger.ToolError import FILE_NOT_FOUND
|
||||
from Library.Xml.XmlRoutines import CreateXmlElement
|
||||
from Library.DataType import TAB_VALUE_SPLIT
|
||||
from Library.DataType import TAB_EQUAL_SPLIT
|
||||
from Library.DataType import TAB_SECTION_START
|
||||
from Library.DataType import TAB_SECTION_END
|
||||
from Logger import StringTable as ST
|
||||
from Library.String import ConvertSpecialChar
|
||||
from Library.ParserValidate import IsValidPath
|
||||
|
||||
## log error:
|
||||
#
|
||||
# @param error: error
|
||||
# @param File: File
|
||||
# @param Line: Line
|
||||
#
|
||||
def IniParseError(Error, File, Line):
|
||||
Logger.Error("UPT", UPT_INI_PARSE_ERROR, File=File,
|
||||
Line=Line, ExtraData=Error)
|
||||
|
||||
## __ValidatePath
|
||||
#
|
||||
# @param Path: Path to be checked
|
||||
#
|
||||
def __ValidatePath(Path, Root):
|
||||
Path = Path.strip()
|
||||
if os.path.isabs(Path) or not IsValidPath(Path, Root):
|
||||
return False, ST.ERR_FILELIST_LOCATION % (Root, Path)
|
||||
return True, ''
|
||||
|
||||
## ValidateMiscFile
|
||||
#
|
||||
# @param Filename: File to be checked
|
||||
#
|
||||
def ValidateMiscFile(Filename):
|
||||
Root = ''
|
||||
if 'WORKSPACE' in os.environ:
|
||||
Root = os.environ['WORKSPACE']
|
||||
return __ValidatePath(Filename, Root)
|
||||
|
||||
## ValidateToolsFile
|
||||
#
|
||||
# @param Filename: File to be checked
|
||||
#
|
||||
def ValidateToolsFile(Filename):
|
||||
Valid, Cause = False, ''
|
||||
if not Valid and 'EDK_TOOLS_PATH' in os.environ:
|
||||
Valid, Cause = __ValidatePath(Filename, os.environ['EDK_TOOLS_PATH'])
|
||||
if not Valid and 'WORKSPACE' in os.environ:
|
||||
Valid, Cause = __ValidatePath(Filename, os.environ['WORKSPACE'])
|
||||
return Valid, Cause
|
||||
|
||||
## ParseFileList
|
||||
#
|
||||
# @param Line: Line
|
||||
# @param Map: Map
|
||||
# @param CurrentKey: CurrentKey
|
||||
# @param PathFunc: Path validate function
|
||||
#
|
||||
def ParseFileList(Line, Map, CurrentKey, PathFunc):
|
||||
FileList = ["", {}]
|
||||
TokenList = Line.split(TAB_VALUE_SPLIT)
|
||||
if len(TokenList) > 0:
|
||||
Path = TokenList[0].strip().replace('\\', '/')
|
||||
if not Path:
|
||||
return False, ST.ERR_WRONG_FILELIST_FORMAT
|
||||
Valid, Cause = PathFunc(Path)
|
||||
if not Valid:
|
||||
return Valid, Cause
|
||||
FileList[0] = TokenList[0].strip()
|
||||
for Token in TokenList[1:]:
|
||||
Attr = Token.split(TAB_EQUAL_SPLIT)
|
||||
if len(Attr) != 2 or not Attr[0].strip() or not Attr[1].strip():
|
||||
return False, ST.ERR_WRONG_FILELIST_FORMAT
|
||||
|
||||
Key = Attr[0].strip()
|
||||
Val = Attr[1].strip()
|
||||
if Key not in ['OS', 'Executable']:
|
||||
return False, ST.ERR_UNKNOWN_FILELIST_ATTR % Key
|
||||
|
||||
if Key == 'OS' and Val not in ["Win32", "Win64", "Linux32",
|
||||
"Linux64", "OS/X32", "OS/X64",
|
||||
"GenericWin", "GenericNix"]:
|
||||
return False, ST.ERR_FILELIST_ATTR % 'OS'
|
||||
elif Key == 'Executable' and Val not in ['true', 'false']:
|
||||
return False, ST.ERR_FILELIST_ATTR % 'Executable'
|
||||
FileList[1][Key] = Val
|
||||
|
||||
Map[CurrentKey].append(FileList)
|
||||
return True, ''
|
||||
|
||||
## Create header XML file
|
||||
#
|
||||
# @param DistMap: DistMap
|
||||
# @param Root: Root
|
||||
#
|
||||
def CreateHeaderXml(DistMap, Root):
|
||||
Element1 = CreateXmlElement('Name', DistMap['Name'],
|
||||
[], [['BaseName', DistMap['BaseName']]])
|
||||
Element2 = CreateXmlElement('GUID', DistMap['GUID'],
|
||||
[], [['Version', DistMap['Version']]])
|
||||
AttributeList = [['ReadOnly', DistMap['ReadOnly']],
|
||||
['RePackage', DistMap['RePackage']]]
|
||||
NodeList = [Element1,
|
||||
Element2,
|
||||
['Vendor', DistMap['Vendor']],
|
||||
['Date', DistMap['Date']],
|
||||
['Copyright', DistMap['Copyright']],
|
||||
['License', DistMap['License']],
|
||||
['Abstract', DistMap['Abstract']],
|
||||
['Description', DistMap['Description']],
|
||||
['Signature', DistMap['Signature']],
|
||||
['XmlSpecification', DistMap['XmlSpecification']],
|
||||
]
|
||||
Root.appendChild(CreateXmlElement('DistributionHeader', '',
|
||||
NodeList, AttributeList))
|
||||
|
||||
## Create tools XML file
|
||||
#
|
||||
# @param Map: Map
|
||||
# @param Root: Root
|
||||
# @param Tag: Tag
|
||||
#
|
||||
def CreateToolsXml(Map, Root, Tag):
|
||||
#
|
||||
# Check if all elements in this section are empty
|
||||
#
|
||||
for Key in Map:
|
||||
if len(Map[Key]) > 0:
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
||||
NodeList = [['Name', Map['Name']],
|
||||
['Copyright', Map['Copyright']],
|
||||
['License', Map['License']],
|
||||
['Abstract', Map['Abstract']],
|
||||
['Description', Map['Description']],
|
||||
]
|
||||
HeaderNode = CreateXmlElement('Header', '', NodeList, [])
|
||||
NodeList = [HeaderNode]
|
||||
|
||||
for File in Map['FileList']:
|
||||
AttrList = []
|
||||
for Key in File[1]:
|
||||
AttrList.append([Key, File[1][Key]])
|
||||
NodeList.append(CreateXmlElement('Filename', File[0], [], AttrList))
|
||||
Root.appendChild(CreateXmlElement(Tag, '', NodeList, []))
|
||||
|
||||
## ValidateValues
|
||||
#
|
||||
# @param Key: Key
|
||||
# @param Value: Value
|
||||
# @param SectionName: SectionName
|
||||
#
|
||||
def ValidateValues(Key, Value, SectionName):
|
||||
if SectionName == 'DistributionHeader':
|
||||
Valid, Cause = ValidateRegValues(Key, Value)
|
||||
if not Valid:
|
||||
return Valid, Cause
|
||||
Valid = __ValidateDistHeader(Key, Value)
|
||||
if not Valid:
|
||||
return Valid, ST.ERR_VALUE_INVALID % (Key, SectionName)
|
||||
else:
|
||||
Valid = __ValidateOtherHeader(Key, Value)
|
||||
if not Valid:
|
||||
return Valid, ST.ERR_VALUE_INVALID % (Key, SectionName)
|
||||
return True, ''
|
||||
|
||||
## ValidateRegValues
|
||||
#
|
||||
# @param Key: Key
|
||||
# @param Value: Value
|
||||
#
|
||||
def ValidateRegValues(Key, Value):
|
||||
ValidateMap = {
|
||||
'ReadOnly' :
|
||||
('true|false', ST.ERR_BOOLEAN_VALUE % (Key, Value)),
|
||||
'RePackage' :
|
||||
('true|false', ST.ERR_BOOLEAN_VALUE % (Key, Value)),
|
||||
'GUID' :
|
||||
('[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}'
|
||||
'-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}',
|
||||
ST.ERR_GUID_VALUE % Value),
|
||||
'Version' : ('[0-9]+(\.[0-9]+)?', ST.ERR_VERSION_VALUE % \
|
||||
(Key, Value)),
|
||||
'XmlSpecification' : ('1\.1', ST.ERR_VERSION_XMLSPEC % Value)
|
||||
}
|
||||
if Key not in ValidateMap:
|
||||
return True, ''
|
||||
Elem = ValidateMap[Key]
|
||||
Match = re.compile(Elem[0]).match(Value)
|
||||
if Match and Match.start() == 0 and Match.end() == len(Value):
|
||||
return True, ''
|
||||
return False, Elem[1]
|
||||
|
||||
## __ValidateDistHeaderName
|
||||
#
|
||||
# @param Name: Name
|
||||
#
|
||||
def __ValidateDistHeaderName(Name):
|
||||
if len(Name) < 1:
|
||||
return False
|
||||
|
||||
for Char in Name:
|
||||
if ord(Char) < 0x20 or ord(Char) >= 0x7f:
|
||||
return False
|
||||
return True
|
||||
|
||||
## __ValidateDistHeaderBaseName
|
||||
#
|
||||
# @param BaseName: BaseName
|
||||
#
|
||||
def __ValidateDistHeaderBaseName(BaseName):
|
||||
if not BaseName:
|
||||
return False
|
||||
# if CheckLen and len(BaseName) < 2:
|
||||
# return False
|
||||
if not BaseName[0].isalnum() and BaseName[0] != '_':
|
||||
return False
|
||||
for Char in BaseName[1:]:
|
||||
if not Char.isalnum() and Char not in '-_':
|
||||
return False
|
||||
return True
|
||||
|
||||
## __ValidateDistHeaderAbstract
|
||||
#
|
||||
# @param Abstract: Abstract
|
||||
#
|
||||
def __ValidateDistHeaderAbstract(Abstract):
|
||||
return '\t' not in Abstract and len(Abstract.splitlines()) == 1
|
||||
|
||||
## __ValidateOtherHeaderAbstract
|
||||
#
|
||||
# @param Abstract: Abstract
|
||||
#
|
||||
def __ValidateOtherHeaderAbstract(Abstract):
|
||||
return __ValidateDistHeaderAbstract(Abstract)
|
||||
|
||||
## __ValidateDistHeader
|
||||
#
|
||||
# @param Key: Key
|
||||
# @param Value: Value
|
||||
#
|
||||
def __ValidateDistHeader(Key, Value):
|
||||
ValidateMap = {
|
||||
'Name' : __ValidateDistHeaderName,
|
||||
'BaseName' : __ValidateDistHeaderBaseName,
|
||||
'Abstract' : __ValidateDistHeaderAbstract,
|
||||
'Vendor' : __ValidateDistHeaderAbstract
|
||||
}
|
||||
return not (Value and Key in ValidateMap and not ValidateMap[Key](Value))
|
||||
|
||||
## __ValidateOtherHeader
|
||||
#
|
||||
# @param Key: Key
|
||||
# @param Value: Value
|
||||
#
|
||||
def __ValidateOtherHeader(Key, Value):
|
||||
ValidateMap = {
|
||||
'Name' : __ValidateDistHeaderName,
|
||||
'Abstract' : __ValidateOtherHeaderAbstract
|
||||
}
|
||||
return not (Value and Key in ValidateMap and not ValidateMap[Key](Value))
|
||||
|
||||
## Convert ini file to xml file
|
||||
#
|
||||
# @param IniFile
|
||||
#
|
||||
def IniToXml(IniFile):
|
||||
if not os.path.exists(IniFile):
|
||||
Logger.Error("UPT", FILE_NOT_FOUND, ST.ERR_TEMPLATE_NOTFOUND % IniFile)
|
||||
|
||||
DistMap = {'ReadOnly' : '', 'RePackage' : '', 'Name' : '',
|
||||
'BaseName' : '', 'GUID' : '', 'Version' : '', 'Vendor' : '',
|
||||
'Date' : '', 'Copyright' : '', 'License' : '', 'Abstract' : '',
|
||||
'Description' : '', 'Signature' : '', 'XmlSpecification' : ''
|
||||
}
|
||||
|
||||
ToolsMap = {'Name' : '', 'Copyright' : '', 'License' : '',
|
||||
'Abstract' : '', 'Description' : '', 'FileList' : []}
|
||||
#
|
||||
# Only FileList is a list: [['file1', {}], ['file2', {}], ...]
|
||||
#
|
||||
MiscMap = {'Name' : '', 'Copyright' : '', 'License' : '',
|
||||
'Abstract' : '', 'Description' : '', 'FileList' : []}
|
||||
|
||||
SectionMap = {
|
||||
'DistributionHeader' : DistMap,
|
||||
'ToolsHeader' : ToolsMap,
|
||||
'MiscellaneousFilesHeader' : MiscMap
|
||||
}
|
||||
|
||||
PathValidator = {
|
||||
'ToolsHeader' : ValidateToolsFile,
|
||||
'MiscellaneousFilesHeader' : ValidateMiscFile
|
||||
}
|
||||
|
||||
ParsedSection = []
|
||||
|
||||
SectionName = ''
|
||||
CurrentKey = ''
|
||||
PreMap = None
|
||||
Map = None
|
||||
FileContent = ConvertSpecialChar(open(IniFile, 'rb').readlines())
|
||||
LastIndex = 0
|
||||
for Index in range(0, len(FileContent)):
|
||||
LastIndex = Index
|
||||
Line = FileContent[Index].strip()
|
||||
if Line == '':
|
||||
continue
|
||||
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
|
||||
CurrentKey = ''
|
||||
SectionName = Line[1:-1].strip()
|
||||
if SectionName not in SectionMap:
|
||||
IniParseError(ST.ERR_SECTION_NAME_INVALID % SectionName,
|
||||
IniFile, Index+1)
|
||||
|
||||
if SectionName in ParsedSection:
|
||||
IniParseError(ST.ERR_SECTION_REDEFINE % SectionName,
|
||||
IniFile, Index+1)
|
||||
else:
|
||||
ParsedSection.append(SectionName)
|
||||
|
||||
Map = SectionMap[SectionName]
|
||||
continue
|
||||
if not Map:
|
||||
IniParseError(ST.ERR_SECTION_NAME_NONE, IniFile, Index+1)
|
||||
TokenList = Line.split(TAB_EQUAL_SPLIT, 1)
|
||||
TempKey = TokenList[0].strip()
|
||||
#
|
||||
# Value spanned multiple or same keyword appears more than one time
|
||||
#
|
||||
if len(TokenList) < 2 or TempKey not in Map:
|
||||
if CurrentKey == '':
|
||||
IniParseError(ST.ERR_KEYWORD_INVALID % TempKey,
|
||||
IniFile, Index+1)
|
||||
elif CurrentKey == 'FileList':
|
||||
#
|
||||
# Special for FileList
|
||||
#
|
||||
Valid, Cause = ParseFileList(Line, Map, CurrentKey,
|
||||
PathValidator[SectionName])
|
||||
if not Valid:
|
||||
IniParseError(Cause, IniFile, Index+1)
|
||||
|
||||
else:
|
||||
#
|
||||
# Multiple lines for one key such as license
|
||||
# Or if string on the left side of '=' is not a keyword
|
||||
#
|
||||
Map[CurrentKey] = ''.join([Map[CurrentKey], '\n', Line])
|
||||
Valid, Cause = ValidateValues(CurrentKey,
|
||||
Map[CurrentKey], SectionName)
|
||||
if not Valid:
|
||||
IniParseError(Cause, IniFile, Index+1)
|
||||
continue
|
||||
|
||||
if (TokenList[1].strip() == ''):
|
||||
IniParseError(ST.ERR_EMPTY_VALUE, IniFile, Index+1)
|
||||
|
||||
#
|
||||
# A keyword found
|
||||
#
|
||||
CurrentKey = TempKey
|
||||
if Map[CurrentKey]:
|
||||
IniParseError(ST.ERR_KEYWORD_REDEFINE % CurrentKey,
|
||||
IniFile, Index+1)
|
||||
|
||||
if id(Map) != id(PreMap) and Map['Copyright']:
|
||||
PreMap = Map
|
||||
Copyright = Map['Copyright'].lower()
|
||||
Pos = Copyright.find('copyright')
|
||||
if Pos == -1:
|
||||
IniParseError(ST.ERR_COPYRIGHT_CONTENT, IniFile, Index)
|
||||
if not Copyright[Pos + len('copyright'):].lstrip(' ').startswith('('):
|
||||
IniParseError(ST.ERR_COPYRIGHT_CONTENT, IniFile, Index)
|
||||
|
||||
if CurrentKey == 'FileList':
|
||||
Valid, Cause = ParseFileList(TokenList[1], Map, CurrentKey,
|
||||
PathValidator[SectionName])
|
||||
if not Valid:
|
||||
IniParseError(Cause, IniFile, Index+1)
|
||||
else:
|
||||
Map[CurrentKey] = TokenList[1].strip()
|
||||
Valid, Cause = ValidateValues(CurrentKey,
|
||||
Map[CurrentKey], SectionName)
|
||||
if not Valid:
|
||||
IniParseError(Cause, IniFile, Index+1)
|
||||
|
||||
if id(Map) != id(PreMap) and Map['Copyright'] and 'copyright' not in Map['Copyright'].lower():
|
||||
IniParseError(ST.ERR_COPYRIGHT_CONTENT, IniFile, LastIndex)
|
||||
|
||||
#
|
||||
# Check mandatory keys
|
||||
#
|
||||
CheckMdtKeys(DistMap, IniFile, LastIndex,
|
||||
(('ToolsHeader', ToolsMap), ('MiscellaneousFilesHeader', MiscMap))
|
||||
)
|
||||
|
||||
return CreateXml(DistMap, ToolsMap, MiscMap, IniFile)
|
||||
|
||||
|
||||
## CheckMdtKeys
|
||||
#
|
||||
# @param MdtDistKeys: All mandatory keys
|
||||
# @param DistMap: Dist content
|
||||
# @param IniFile: Ini file
|
||||
# @param LastIndex: Last index of Ini file
|
||||
# @param Maps: Tools and Misc section name and map. (('section_name', map),*)
|
||||
#
|
||||
def CheckMdtKeys(DistMap, IniFile, LastIndex, Maps):
|
||||
MdtDistKeys = ['Name', 'GUID', 'Version', 'Vendor', 'Copyright', 'License', 'Abstract', 'XmlSpecification']
|
||||
for Key in MdtDistKeys:
|
||||
if Key not in DistMap or DistMap[Key] == '':
|
||||
IniParseError(ST.ERR_KEYWORD_MANDATORY % Key, IniFile, LastIndex+1)
|
||||
|
||||
if '.' not in DistMap['Version']:
|
||||
DistMap['Version'] = DistMap['Version'] + '.0'
|
||||
|
||||
DistMap['Date'] = str(strftime("%Y-%m-%dT%H:%M:%S", localtime()))
|
||||
|
||||
#
|
||||
# Check Tools Surface Area according to UPT Spec
|
||||
# <Tools> {0,}
|
||||
# <Header> ... </Header> {0,1}
|
||||
# <Filename> ... </Filename> {1,}
|
||||
# </Tools>
|
||||
# <Header>
|
||||
# <Name> xs:normalizedString </Name> {1}
|
||||
# <Copyright> xs:string </Copyright> {0,1}
|
||||
# <License> xs:string </License> {0,1}
|
||||
# <Abstract> xs:normalizedString </Abstract> {0,1}
|
||||
# <Description> xs:string </Description> {0,1}
|
||||
# </Header>
|
||||
#
|
||||
for Item in Maps:
|
||||
Map = Item[1]
|
||||
NonEmptyKey = 0
|
||||
for Key in Map:
|
||||
if Map[Key]:
|
||||
NonEmptyKey += 1
|
||||
|
||||
if NonEmptyKey > 0 and not Map['FileList']:
|
||||
IniParseError(ST.ERR_KEYWORD_MANDATORY % (Item[0] + '.FileList'), IniFile, LastIndex+1)
|
||||
|
||||
if NonEmptyKey > 0 and not Map['Name']:
|
||||
IniParseError(ST.ERR_KEYWORD_MANDATORY % (Item[0] + '.Name'), IniFile, LastIndex+1)
|
||||
|
||||
## CreateXml
|
||||
#
|
||||
# @param DistMap: Dist Content
|
||||
# @param ToolsMap: Tools Content
|
||||
# @param MiscMap: Misc Content
|
||||
# @param IniFile: Ini File
|
||||
#
|
||||
def CreateXml(DistMap, ToolsMap, MiscMap, IniFile):
|
||||
Attrs = [['xmlns', 'http://www.uefi.org/2011/1.1'],
|
||||
['xmlns:xsi', 'http:/www.w3.org/2001/XMLSchema-instance'],
|
||||
]
|
||||
Root = CreateXmlElement('DistributionPackage', '', [], Attrs)
|
||||
CreateHeaderXml(DistMap, Root)
|
||||
CreateToolsXml(ToolsMap, Root, 'Tools')
|
||||
CreateToolsXml(MiscMap, Root, 'MiscellaneousFiles')
|
||||
|
||||
FileAndExt = IniFile.rsplit('.', 1)
|
||||
if len(FileAndExt) > 1:
|
||||
FileName = FileAndExt[0] + '.xml'
|
||||
else:
|
||||
FileName = IniFile + '.xml'
|
||||
File = open(FileName, 'w')
|
||||
|
||||
try:
|
||||
File.write(Root.toprettyxml(indent = ' '))
|
||||
finally:
|
||||
File.close()
|
||||
return FileName
|
||||
|
Reference in New Issue
Block a user