]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
BaseTools: GenPatchPcdTable - refactor RegEx to minimize multiple compiling
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
CommitLineData
f51461c8
LG
1## @file\r
2# Common routines used by all tools\r
3#\r
d5988a8a 4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
f51461c8
LG
5# This program and the accompanying materials\r
6# are licensed and made available under the terms and conditions of the BSD License\r
7# which accompanies this distribution. The full text of the license may be found at\r
8# http://opensource.org/licenses/bsd-license.php\r
9#\r
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12#\r
13\r
14##\r
15# Import Modules\r
16#\r
1be2ed90 17import Common.LongFilePathOs as os\r
f51461c8
LG
18import sys\r
19import string\r
20import thread\r
21import threading\r
22import time\r
23import re\r
24import cPickle\r
25import array\r
97fa0ee9 26import shutil\r
a3251d84 27from struct import pack\r
f51461c8
LG
28from UserDict import IterableUserDict\r
29from UserList import UserList\r
30\r
31from Common import EdkLogger as EdkLogger\r
32from Common import GlobalData as GlobalData\r
33from DataType import *\r
34from BuildToolError import *\r
35from CommonDataClass.DataClass import *\r
36from Parsing import GetSplitValueList\r
1be2ed90 37from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 38from Common.MultipleWorkspace import MultipleWorkspace as mws\r
ae7b6df8 39import uuid\r
726c501c 40from CommonDataClass.Exceptions import BadExpression\r
7dbc50bd 41import subprocess\r
f51461c8 42## Regular expression used to find out place holders in string template\r
47fea6af 43gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)\r
f51461c8
LG
44\r
45## Dictionary used to store file time stamp for quick re-access\r
46gFileTimeStampCache = {} # {file path : file time stamp}\r
47\r
48## Dictionary used to store dependencies of files\r
49gDependencyDatabase = {} # arch : {file path : [dependent files list]}\r
50\r
22a99b87
YL
51def GetVariableOffset(mapfilepath, efifilepath, varnames):\r
52 """ Parse map file to get variable offset in current EFI file \r
53 @param mapfilepath Map file absolution path\r
54 @param efifilepath: EFI binary file full path\r
55 @param varnames iteratable container whose elements are variable names to be searched\r
56 \r
57 @return List whos elements are tuple with variable name and raw offset\r
58 """\r
59 lines = []\r
60 try:\r
61 f = open(mapfilepath, 'r')\r
62 lines = f.readlines()\r
63 f.close()\r
64 except:\r
65 return None\r
66 \r
67 if len(lines) == 0: return None\r
68 firstline = lines[0].strip()\r
69 if (firstline.startswith("Archive member included ") and\r
70 firstline.endswith(" file (symbol)")):\r
71 return _parseForGCC(lines, efifilepath, varnames)\r
14239ee0
YZ
72 if firstline.startswith("# Path:"):\r
73 return _parseForXcode(lines, efifilepath, varnames)\r
22a99b87
YL
74 return _parseGeneral(lines, efifilepath, varnames)\r
75\r
14239ee0
YZ
76def _parseForXcode(lines, efifilepath, varnames):\r
77 status = 0\r
78 ret = []\r
e52aed0d 79 for line in lines:\r
14239ee0
YZ
80 line = line.strip()\r
81 if status == 0 and line == "# Symbols:":\r
82 status = 1\r
83 continue\r
84 if status == 1 and len(line) != 0:\r
85 for varname in varnames:\r
86 if varname in line:\r
6686d9a1 87 # cannot pregenerate this RegEx since it uses varname from varnames.\r
14239ee0 88 m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)\r
4231a819 89 if m is not None:\r
14239ee0
YZ
90 ret.append((varname, m.group(1)))\r
91 return ret\r
92\r
22a99b87
YL
93def _parseForGCC(lines, efifilepath, varnames):\r
94 """ Parse map file generated by GCC linker """\r
6686d9a1
CJ
95 valuePattern = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')\r
96 pcdPattern = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')\r
22a99b87
YL
97 status = 0\r
98 sections = []\r
99 varoffset = []\r
3e7e8571 100 for index, line in enumerate(lines):\r
22a99b87
YL
101 line = line.strip()\r
102 # status machine transection\r
103 if status == 0 and line == "Memory Configuration":\r
104 status = 1\r
105 continue\r
106 elif status == 1 and line == 'Linker script and memory map':\r
107 status = 2\r
108 continue\r
109 elif status ==2 and line == 'START GROUP':\r
110 status = 3\r
111 continue\r
112\r
113 # status handler\r
3e7e8571 114 if status == 3:\r
6686d9a1 115 m = valuePattern.match(line)\r
4231a819 116 if m is not None:\r
22a99b87
YL
117 sections.append(m.groups(0))\r
118 for varname in varnames:\r
d03c056b
YZ
119 Str = ''\r
120 m = re.match("^.data.(%s)" % varname, line)\r
4231a819 121 if m is not None:\r
d03c056b 122 m = re.match(".data.(%s)$" % varname, line)\r
4231a819 123 if m is not None:\r
d03c056b
YZ
124 Str = lines[index + 1]\r
125 else:\r
126 Str = line[len(".data.%s" % varname):]\r
127 if Str:\r
6686d9a1 128 m = pcdPattern.match(Str.strip())\r
4231a819 129 if m is not None:\r
3e7e8571 130 varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0]))\r
22a99b87
YL
131\r
132 if not varoffset:\r
133 return []\r
134 # get section information from efi file\r
135 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
4231a819 136 if efisecs is None or len(efisecs) == 0:\r
22a99b87
YL
137 return []\r
138 #redirection\r
139 redirection = 0\r
140 for efisec in efisecs:\r
141 for section in sections:\r
142 if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':\r
143 redirection = int(section[1], 16) - efisec[1]\r
144\r
145 ret = []\r
146 for var in varoffset:\r
147 for efisec in efisecs:\r
148 if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:\r
149 ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))\r
150 return ret\r
151\r
152def _parseGeneral(lines, efifilepath, varnames):\r
153 status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table\r
154 secs = [] # key = section name\r
155 varoffset = []\r
156 secRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)\r
157 symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re.UNICODE)\r
6686d9a1
CJ
158 startRe = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class")\r
159 addressRe = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")\r
22a99b87
YL
160\r
161 for line in lines:\r
162 line = line.strip()\r
6686d9a1 163 if startRe.match(line):\r
22a99b87
YL
164 status = 1\r
165 continue\r
6686d9a1 166 if addressRe.match(line):\r
22a99b87
YL
167 status = 2\r
168 continue\r
6686d9a1 169 if line.startswith("entry point at"):\r
22a99b87
YL
170 status = 3\r
171 continue \r
172 if status == 1 and len(line) != 0:\r
173 m = secRe.match(line)\r
4231a819 174 assert m is not None, "Fail to parse the section in map file , line is %s" % line\r
22a99b87
YL
175 sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)\r
176 secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])\r
177 if status == 2 and len(line) != 0:\r
178 for varname in varnames:\r
179 m = symRe.match(line)\r
4231a819 180 assert m is not None, "Fail to parse the symbol in map file, line is %s" % line\r
22a99b87
YL
181 sec_no, sym_offset, sym_name, vir_addr = m.groups(0)\r
182 sec_no = int(sec_no, 16)\r
183 sym_offset = int(sym_offset, 16)\r
184 vir_addr = int(vir_addr, 16)\r
6686d9a1 185 # cannot pregenerate this RegEx since it uses varname from varnames.\r
22a99b87 186 m2 = re.match('^[_]*(%s)' % varname, sym_name)\r
4231a819 187 if m2 is not None:\r
22a99b87
YL
188 # fond a binary pcd entry in map file\r
189 for sec in secs:\r
190 if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):\r
191 varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])\r
192\r
193 if not varoffset: return []\r
194\r
195 # get section information from efi file\r
196 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
4231a819 197 if efisecs is None or len(efisecs) == 0:\r
22a99b87
YL
198 return []\r
199\r
200 ret = []\r
201 for var in varoffset:\r
202 index = 0\r
203 for efisec in efisecs:\r
204 index = index + 1\r
205 if var[1].strip() == efisec[0].strip():\r
206 ret.append((var[0], hex(efisec[2] + var[2])))\r
207 elif var[4] == index:\r
208 ret.append((var[0], hex(efisec[2] + var[2])))\r
209\r
210 return ret\r
211\r
97fa0ee9
YL
212## Routine to process duplicated INF\r
213#\r
214# This function is called by following two cases:\r
215# Case 1 in DSC:\r
216# [components.arch]\r
217# Pkg/module/module.inf\r
218# Pkg/module/module.inf {\r
219# <Defines>\r
220# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836\r
221# }\r
222# Case 2 in FDF:\r
223# INF Pkg/module/module.inf\r
224# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf\r
225#\r
226# This function copies Pkg/module/module.inf to\r
227# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf\r
228#\r
229# @param Path Original PathClass object\r
230# @param BaseName New file base name\r
231#\r
232# @retval return the new PathClass object\r
233#\r
234def ProcessDuplicatedInf(Path, BaseName, Workspace):\r
235 Filename = os.path.split(Path.File)[1]\r
236 if '.' in Filename:\r
237 Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]\r
238 else:\r
239 Filename = BaseName + Path.BaseName\r
240\r
241 #\r
242 # If -N is specified on command line, cache is disabled\r
243 # The directory has to be created\r
244 #\r
245 DbDir = os.path.split(GlobalData.gDatabasePath)[0]\r
246 if not os.path.exists(DbDir):\r
247 os.makedirs(DbDir)\r
248 #\r
249 # A temporary INF is copied to database path which must have write permission\r
250 # The temporary will be removed at the end of build\r
251 # In case of name conflict, the file name is \r
252 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)\r
253 #\r
254 TempFullPath = os.path.join(DbDir,\r
255 Filename)\r
256 RtPath = PathClass(Path.File, Workspace)\r
257 #\r
258 # Modify the full path to temporary path, keep other unchanged\r
259 #\r
260 # To build same module more than once, the module path with FILE_GUID overridden has\r
261 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path\r
262 # in DSC which is used as relative path by C files and other files in INF. \r
263 # A trick was used: all module paths are PathClass instances, after the initialization\r
264 # of PathClass, the PathClass.Path is overridden by the temporary INF path.\r
265 #\r
266 # The reason for creating a temporary INF is:\r
267 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,\r
268 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.\r
269 # A different key for the same module is needed to create different output directory,\r
270 # retrieve overridden PCDs, library instances.\r
271 #\r
272 # The BaseName is the FILE_GUID which is also the output directory name.\r
273 #\r
274 #\r
275 RtPath.Path = TempFullPath\r
276 RtPath.BaseName = BaseName\r
277 #\r
278 # If file exists, compare contents\r
279 #\r
280 if os.path.exists(TempFullPath):\r
281 with open(str(Path), 'rb') as f1: Src = f1.read()\r
282 with open(TempFullPath, 'rb') as f2: Dst = f2.read()\r
283 if Src == Dst:\r
284 return RtPath\r
285 GlobalData.gTempInfs.append(TempFullPath)\r
286 shutil.copy2(str(Path), TempFullPath)\r
287 return RtPath\r
288\r
289## Remove temporary created INFs whose paths were saved in gTempInfs\r
290#\r
291def ClearDuplicatedInf():\r
292 for File in GlobalData.gTempInfs:\r
293 if os.path.exists(File):\r
294 os.remove(File)\r
295\r
f51461c8
LG
296## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style\r
297#\r
298# @param Guid The GUID string\r
299#\r
300# @retval string The GUID string in C structure style\r
301#\r
302def GuidStringToGuidStructureString(Guid):\r
303 GuidList = Guid.split('-')\r
304 Result = '{'\r
47fea6af 305 for Index in range(0, 3, 1):\r
f51461c8
LG
306 Result = Result + '0x' + GuidList[Index] + ', '\r
307 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
47fea6af
YZ
308 for Index in range(0, 12, 2):\r
309 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
f51461c8
LG
310 Result += '}}'\r
311 return Result\r
312\r
313## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
314#\r
315# @param GuidValue The GUID value in byte array\r
316#\r
317# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
318#\r
319def GuidStructureByteArrayToGuidString(GuidValue):\r
320 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
321 guidValueList = guidValueString.split(",")\r
322 if len(guidValueList) != 16:\r
323 return ''\r
324 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
325 try:\r
326 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
327 int(guidValueList[3], 16),\r
328 int(guidValueList[2], 16),\r
329 int(guidValueList[1], 16),\r
330 int(guidValueList[0], 16),\r
331 int(guidValueList[5], 16),\r
332 int(guidValueList[4], 16),\r
333 int(guidValueList[7], 16),\r
334 int(guidValueList[6], 16),\r
335 int(guidValueList[8], 16),\r
336 int(guidValueList[9], 16),\r
337 int(guidValueList[10], 16),\r
338 int(guidValueList[11], 16),\r
339 int(guidValueList[12], 16),\r
340 int(guidValueList[13], 16),\r
341 int(guidValueList[14], 16),\r
342 int(guidValueList[15], 16)\r
343 )\r
344 except:\r
345 return ''\r
346\r
347## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
348#\r
349# @param GuidValue The GUID value in C structure format\r
350#\r
351# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
352#\r
353def GuidStructureStringToGuidString(GuidValue):\r
354 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
355 guidValueList = guidValueString.split(",")\r
356 if len(guidValueList) != 11:\r
357 return ''\r
358 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
359 try:\r
360 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
361 int(guidValueList[0], 16),\r
362 int(guidValueList[1], 16),\r
363 int(guidValueList[2], 16),\r
364 int(guidValueList[3], 16),\r
365 int(guidValueList[4], 16),\r
366 int(guidValueList[5], 16),\r
367 int(guidValueList[6], 16),\r
368 int(guidValueList[7], 16),\r
369 int(guidValueList[8], 16),\r
370 int(guidValueList[9], 16),\r
371 int(guidValueList[10], 16)\r
372 )\r
373 except:\r
374 return ''\r
375\r
376## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx\r
377#\r
378# @param GuidValue The GUID value in C structure format\r
379#\r
380# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format\r
381#\r
382def GuidStructureStringToGuidValueName(GuidValue):\r
383 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
384 guidValueList = guidValueString.split(",")\r
385 if len(guidValueList) != 11:\r
386 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)\r
387 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (\r
388 int(guidValueList[0], 16),\r
389 int(guidValueList[1], 16),\r
390 int(guidValueList[2], 16),\r
391 int(guidValueList[3], 16),\r
392 int(guidValueList[4], 16),\r
393 int(guidValueList[5], 16),\r
394 int(guidValueList[6], 16),\r
395 int(guidValueList[7], 16),\r
396 int(guidValueList[8], 16),\r
397 int(guidValueList[9], 16),\r
398 int(guidValueList[10], 16)\r
399 )\r
400\r
401## Create directories\r
402#\r
403# @param Directory The directory name\r
404#\r
405def CreateDirectory(Directory):\r
4231a819 406 if Directory is None or Directory.strip() == "":\r
f51461c8
LG
407 return True\r
408 try:\r
409 if not os.access(Directory, os.F_OK):\r
410 os.makedirs(Directory)\r
411 except:\r
412 return False\r
413 return True\r
414\r
415## Remove directories, including files and sub-directories in it\r
416#\r
417# @param Directory The directory name\r
418#\r
419def RemoveDirectory(Directory, Recursively=False):\r
4231a819 420 if Directory is None or Directory.strip() == "" or not os.path.exists(Directory):\r
f51461c8
LG
421 return\r
422 if Recursively:\r
423 CurrentDirectory = os.getcwd()\r
424 os.chdir(Directory)\r
425 for File in os.listdir("."):\r
426 if os.path.isdir(File):\r
427 RemoveDirectory(File, Recursively)\r
428 else:\r
429 os.remove(File)\r
430 os.chdir(CurrentDirectory)\r
431 os.rmdir(Directory)\r
432\r
f51461c8
LG
433## Store content in file\r
434#\r
435# This method is used to save file only when its content is changed. This is\r
436# quite useful for "make" system to decide what will be re-built and what won't.\r
437#\r
438# @param File The path of file\r
439# @param Content The new content of the file\r
440# @param IsBinaryFile The flag indicating if the file is binary file or not\r
441#\r
442# @retval True If the file content is changed and the file is renewed\r
443# @retval False If the file content is the same\r
444#\r
445def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
446 if not IsBinaryFile:\r
447 Content = Content.replace("\n", os.linesep)\r
448\r
449 if os.path.exists(File):\r
450 try:\r
451 if Content == open(File, "rb").read():\r
452 return False\r
453 except:\r
454 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
455\r
456 DirName = os.path.dirname(File)\r
457 if not CreateDirectory(DirName):\r
458 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
459 else:\r
460 if DirName == '':\r
461 DirName = os.getcwd()\r
462 if not os.access(DirName, os.W_OK):\r
463 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
464\r
465 try:\r
466 if GlobalData.gIsWindows:\r
467 try:\r
468 from PyUtility import SaveFileToDisk\r
469 if not SaveFileToDisk(File, Content):\r
470 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)\r
471 except:\r
472 Fd = open(File, "wb")\r
473 Fd.write(Content)\r
474 Fd.close()\r
475 else:\r
476 Fd = open(File, "wb")\r
477 Fd.write(Content)\r
478 Fd.close()\r
479 except IOError, X:\r
47fea6af 480 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)\r
f51461c8
LG
481\r
482 return True\r
483\r
484## Make a Python object persistent on file system\r
485#\r
486# @param Data The object to be stored in file\r
487# @param File The path of file to store the object\r
488#\r
489def DataDump(Data, File):\r
490 Fd = None\r
491 try:\r
492 Fd = open(File, 'wb')\r
493 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)\r
494 except:\r
495 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
496 finally:\r
4231a819 497 if Fd is not None:\r
f51461c8
LG
498 Fd.close()\r
499\r
500## Restore a Python object from a file\r
501#\r
502# @param File The path of file stored the object\r
503#\r
504# @retval object A python object\r
505# @retval None If failure in file operation\r
506#\r
507def DataRestore(File):\r
508 Data = None\r
509 Fd = None\r
510 try:\r
511 Fd = open(File, 'rb')\r
512 Data = cPickle.load(Fd)\r
513 except Exception, e:\r
514 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))\r
515 Data = None\r
516 finally:\r
4231a819 517 if Fd is not None:\r
f51461c8
LG
518 Fd.close()\r
519 return Data\r
520\r
521## Retrieve and cache the real path name in file system\r
522#\r
523# @param Root The root directory of path relative to\r
524#\r
525# @retval str The path string if the path exists\r
526# @retval None If path doesn't exist\r
527#\r
528class DirCache:\r
529 _CACHE_ = set()\r
530 _UPPER_CACHE_ = {}\r
531\r
532 def __init__(self, Root):\r
533 self._Root = Root\r
534 for F in os.listdir(Root):\r
535 self._CACHE_.add(F)\r
536 self._UPPER_CACHE_[F.upper()] = F\r
537\r
538 # =[] operator\r
539 def __getitem__(self, Path):\r
540 Path = Path[len(os.path.commonprefix([Path, self._Root])):]\r
541 if not Path:\r
542 return self._Root\r
543 if Path and Path[0] == os.path.sep:\r
544 Path = Path[1:]\r
545 if Path in self._CACHE_:\r
546 return os.path.join(self._Root, Path)\r
547 UpperPath = Path.upper()\r
548 if UpperPath in self._UPPER_CACHE_:\r
549 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
550\r
551 IndexList = []\r
552 LastSepIndex = -1\r
553 SepIndex = Path.find(os.path.sep)\r
554 while SepIndex > -1:\r
555 Parent = UpperPath[:SepIndex]\r
556 if Parent not in self._UPPER_CACHE_:\r
557 break\r
558 LastSepIndex = SepIndex\r
559 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)\r
560\r
561 if LastSepIndex == -1:\r
562 return None\r
563\r
564 Cwd = os.getcwd()\r
565 os.chdir(self._Root)\r
566 SepIndex = LastSepIndex\r
567 while SepIndex > -1:\r
568 Parent = Path[:SepIndex]\r
569 ParentKey = UpperPath[:SepIndex]\r
570 if ParentKey not in self._UPPER_CACHE_:\r
571 os.chdir(Cwd)\r
572 return None\r
573\r
574 if Parent in self._CACHE_:\r
575 ParentDir = Parent\r
576 else:\r
577 ParentDir = self._UPPER_CACHE_[ParentKey]\r
578 for F in os.listdir(ParentDir):\r
579 Dir = os.path.join(ParentDir, F)\r
580 self._CACHE_.add(Dir)\r
581 self._UPPER_CACHE_[Dir.upper()] = Dir\r
582\r
583 SepIndex = Path.find(os.path.sep, SepIndex + 1)\r
584\r
585 os.chdir(Cwd)\r
586 if Path in self._CACHE_:\r
587 return os.path.join(self._Root, Path)\r
588 elif UpperPath in self._UPPER_CACHE_:\r
589 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
590 return None\r
591\r
f51461c8
LG
592def RealPath(File, Dir='', OverrideDir=''):\r
593 NewFile = os.path.normpath(os.path.join(Dir, File))\r
594 NewFile = GlobalData.gAllFiles[NewFile]\r
595 if not NewFile and OverrideDir:\r
596 NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
597 NewFile = GlobalData.gAllFiles[NewFile]\r
598 return NewFile\r
599\r
600def RealPath2(File, Dir='', OverrideDir=''):\r
9b9500a1 601 NewFile = None\r
f51461c8
LG
602 if OverrideDir:\r
603 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
604 if NewFile:\r
605 if OverrideDir[-1] == os.path.sep:\r
606 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
607 else:\r
47fea6af 608 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]\r
f51461c8
LG
609 if GlobalData.gAllFiles:\r
610 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]\r
9b9500a1 611 if not NewFile:\r
f51461c8 612 NewFile = os.path.normpath(os.path.join(Dir, File))\r
9b9500a1
YL
613 if not os.path.exists(NewFile):\r
614 return None, None\r
f51461c8
LG
615 if NewFile:\r
616 if Dir:\r
617 if Dir[-1] == os.path.sep:\r
618 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
619 else:\r
47fea6af 620 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
f51461c8
LG
621 else:\r
622 return NewFile, ''\r
623\r
624 return None, None\r
625\r
f51461c8
LG
626## Get GUID value from given packages\r
627#\r
628# @param CName The CName of the GUID\r
629# @param PackageList List of packages looking-up in\r
c28d2e10 630# @param Inffile The driver file\r
f51461c8
LG
631#\r
632# @retval GuidValue if the CName is found in any given package\r
633# @retval None if the CName is not found in all given packages\r
634#\r
c28d2e10 635def GuidValue(CName, PackageList, Inffile = None):\r
f51461c8 636 for P in PackageList:\r
c28d2e10
YZ
637 GuidKeys = P.Guids.keys()\r
638 if Inffile and P._PrivateGuids:\r
639 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 640 GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids]\r
c28d2e10 641 if CName in GuidKeys:\r
f51461c8
LG
642 return P.Guids[CName]\r
643 return None\r
644\r
645## Get Protocol value from given packages\r
646#\r
647# @param CName The CName of the GUID\r
648# @param PackageList List of packages looking-up in\r
c28d2e10 649# @param Inffile The driver file\r
f51461c8
LG
650#\r
651# @retval GuidValue if the CName is found in any given package\r
652# @retval None if the CName is not found in all given packages\r
653#\r
c28d2e10 654def ProtocolValue(CName, PackageList, Inffile = None):\r
f51461c8 655 for P in PackageList:\r
c28d2e10
YZ
656 ProtocolKeys = P.Protocols.keys()\r
657 if Inffile and P._PrivateProtocols:\r
658 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 659 ProtocolKeys = [x for x in P.Protocols if x not in P._PrivateProtocols]\r
c28d2e10 660 if CName in ProtocolKeys:\r
f51461c8
LG
661 return P.Protocols[CName]\r
662 return None\r
663\r
664## Get PPI value from given packages\r
665#\r
666# @param CName The CName of the GUID\r
667# @param PackageList List of packages looking-up in\r
c28d2e10 668# @param Inffile The driver file\r
f51461c8
LG
669#\r
670# @retval GuidValue if the CName is found in any given package\r
671# @retval None if the CName is not found in all given packages\r
672#\r
c28d2e10 673def PpiValue(CName, PackageList, Inffile = None):\r
f51461c8 674 for P in PackageList:\r
c28d2e10
YZ
675 PpiKeys = P.Ppis.keys()\r
676 if Inffile and P._PrivatePpis:\r
677 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 678 PpiKeys = [x for x in P.Ppis if x not in P._PrivatePpis]\r
c28d2e10 679 if CName in PpiKeys:\r
f51461c8
LG
680 return P.Ppis[CName]\r
681 return None\r
682\r
683## A string template class\r
684#\r
685# This class implements a template for string replacement. A string template\r
686# looks like following\r
687#\r
688# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
689#\r
690# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
691# length of "placeholder_name", which is a list passed through a dict. The\r
692# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
693# be not used and, in this case, the "placeholder_name" must not a list and it\r
694# will just be replaced once.\r
695#\r
696class TemplateString(object):\r
697 _REPEAT_START_FLAG = "BEGIN"\r
698 _REPEAT_END_FLAG = "END"\r
699\r
700 class Section(object):\r
701 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
702\r
703 def __init__(self, TemplateSection, PlaceHolderList):\r
704 self._Template = TemplateSection\r
705 self._PlaceHolderList = []\r
706\r
707 # Split the section into sub-sections according to the position of placeholders\r
708 if PlaceHolderList:\r
709 self._SubSectionList = []\r
710 SubSectionStart = 0\r
711 #\r
712 # The placeholders passed in must be in the format of\r
713 #\r
714 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
715 #\r
47fea6af 716 for PlaceHolder, Start, End in PlaceHolderList:\r
f51461c8
LG
717 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
718 self._SubSectionList.append(TemplateSection[Start:End])\r
719 self._PlaceHolderList.append(PlaceHolder)\r
720 SubSectionStart = End\r
721 if SubSectionStart < len(TemplateSection):\r
722 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
723 else:\r
724 self._SubSectionList = [TemplateSection]\r
725\r
726 def __str__(self):\r
727 return self._Template + " : " + str(self._PlaceHolderList)\r
728\r
729 def Instantiate(self, PlaceHolderValues):\r
730 RepeatTime = -1\r
731 RepeatPlaceHolders = {}\r
732 NonRepeatPlaceHolders = {}\r
733\r
734 for PlaceHolder in self._PlaceHolderList:\r
735 if PlaceHolder not in PlaceHolderValues:\r
736 continue\r
737 Value = PlaceHolderValues[PlaceHolder]\r
738 if type(Value) in self._LIST_TYPES:\r
739 if RepeatTime < 0:\r
740 RepeatTime = len(Value)\r
741 elif RepeatTime != len(Value):\r
742 EdkLogger.error(\r
743 "TemplateString",\r
744 PARAMETER_INVALID,\r
745 "${%s} has different repeat time from others!" % PlaceHolder,\r
746 ExtraData=str(self._Template)\r
747 )\r
748 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
749 else:\r
750 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
751\r
752 if NonRepeatPlaceHolders:\r
753 StringList = []\r
754 for S in self._SubSectionList:\r
755 if S not in NonRepeatPlaceHolders:\r
756 StringList.append(S)\r
757 else:\r
758 StringList.append(str(NonRepeatPlaceHolders[S]))\r
759 else:\r
760 StringList = self._SubSectionList\r
761\r
762 if RepeatPlaceHolders:\r
763 TempStringList = []\r
764 for Index in range(RepeatTime):\r
765 for S in StringList:\r
766 if S not in RepeatPlaceHolders:\r
767 TempStringList.append(S)\r
768 else:\r
769 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
770 StringList = TempStringList\r
771\r
772 return "".join(StringList)\r
773\r
774 ## Constructor\r
775 def __init__(self, Template=None):\r
776 self.String = ''\r
777 self.IsBinary = False\r
778 self._Template = Template\r
779 self._TemplateSectionList = self._Parse(Template)\r
780\r
781 ## str() operator\r
782 #\r
783 # @retval string The string replaced\r
784 #\r
785 def __str__(self):\r
786 return self.String\r
787\r
788 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
789 #\r
790 # @retval list A list of TemplateString.Section objects\r
791 #\r
792 def _Parse(self, Template):\r
793 SectionStart = 0\r
794 SearchFrom = 0\r
795 MatchEnd = 0\r
796 PlaceHolderList = []\r
797 TemplateSectionList = []\r
798 while Template:\r
799 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
800 if not MatchObj:\r
801 if MatchEnd <= len(Template):\r
802 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
803 TemplateSectionList.append(TemplateSection)\r
804 break\r
805\r
806 MatchString = MatchObj.group(1)\r
807 MatchStart = MatchObj.start()\r
808 MatchEnd = MatchObj.end()\r
809\r
810 if MatchString == self._REPEAT_START_FLAG:\r
811 if MatchStart > SectionStart:\r
812 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
813 TemplateSectionList.append(TemplateSection)\r
814 SectionStart = MatchEnd\r
815 PlaceHolderList = []\r
816 elif MatchString == self._REPEAT_END_FLAG:\r
817 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
818 TemplateSectionList.append(TemplateSection)\r
819 SectionStart = MatchEnd\r
820 PlaceHolderList = []\r
821 else:\r
822 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
823 SearchFrom = MatchEnd\r
824 return TemplateSectionList\r
825\r
826 ## Replace the string template with dictionary of placeholders and append it to previous one\r
827 #\r
828 # @param AppendString The string template to append\r
829 # @param Dictionary The placeholder dictionaries\r
830 #\r
831 def Append(self, AppendString, Dictionary=None):\r
832 if Dictionary:\r
833 SectionList = self._Parse(AppendString)\r
834 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])\r
835 else:\r
836 self.String += AppendString\r
837\r
838 ## Replace the string template with dictionary of placeholders\r
839 #\r
840 # @param Dictionary The placeholder dictionaries\r
841 #\r
842 # @retval str The string replaced with placeholder values\r
843 #\r
844 def Replace(self, Dictionary=None):\r
845 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])\r
846\r
847## Progress indicator class\r
848#\r
849# This class makes use of thread to print progress on console.\r
850#\r
851class Progressor:\r
852 # for avoiding deadloop\r
853 _StopFlag = None\r
854 _ProgressThread = None\r
855 _CheckInterval = 0.25\r
856\r
857 ## Constructor\r
858 #\r
859 # @param OpenMessage The string printed before progress charaters\r
860 # @param CloseMessage The string printed after progress charaters\r
861 # @param ProgressChar The charater used to indicate the progress\r
862 # @param Interval The interval in seconds between two progress charaters\r
863 #\r
864 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
865 self.PromptMessage = OpenMessage\r
866 self.CodaMessage = CloseMessage\r
867 self.ProgressChar = ProgressChar\r
868 self.Interval = Interval\r
4231a819 869 if Progressor._StopFlag is None:\r
f51461c8
LG
870 Progressor._StopFlag = threading.Event()\r
871\r
872 ## Start to print progress charater\r
873 #\r
874 # @param OpenMessage The string printed before progress charaters\r
875 #\r
876 def Start(self, OpenMessage=None):\r
4231a819 877 if OpenMessage is not None:\r
f51461c8
LG
878 self.PromptMessage = OpenMessage\r
879 Progressor._StopFlag.clear()\r
4231a819 880 if Progressor._ProgressThread is None:\r
f51461c8
LG
881 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
882 Progressor._ProgressThread.setDaemon(False)\r
883 Progressor._ProgressThread.start()\r
884\r
885 ## Stop printing progress charater\r
886 #\r
887 # @param CloseMessage The string printed after progress charaters\r
888 #\r
889 def Stop(self, CloseMessage=None):\r
890 OriginalCodaMessage = self.CodaMessage\r
4231a819 891 if CloseMessage is not None:\r
f51461c8
LG
892 self.CodaMessage = CloseMessage\r
893 self.Abort()\r
894 self.CodaMessage = OriginalCodaMessage\r
895\r
896 ## Thread entry method\r
897 def _ProgressThreadEntry(self):\r
898 sys.stdout.write(self.PromptMessage + " ")\r
899 sys.stdout.flush()\r
900 TimeUp = 0.0\r
901 while not Progressor._StopFlag.isSet():\r
902 if TimeUp <= 0.0:\r
903 sys.stdout.write(self.ProgressChar)\r
904 sys.stdout.flush()\r
905 TimeUp = self.Interval\r
906 time.sleep(self._CheckInterval)\r
907 TimeUp -= self._CheckInterval\r
908 sys.stdout.write(" " + self.CodaMessage + "\n")\r
909 sys.stdout.flush()\r
910\r
911 ## Abort the progress display\r
912 @staticmethod\r
913 def Abort():\r
4231a819 914 if Progressor._StopFlag is not None:\r
f51461c8 915 Progressor._StopFlag.set()\r
4231a819 916 if Progressor._ProgressThread is not None:\r
f51461c8
LG
917 Progressor._ProgressThread.join()\r
918 Progressor._ProgressThread = None\r
919\r
920## A dict which can access its keys and/or values orderly\r
921#\r
922# The class implements a new kind of dict which its keys or values can be\r
923# accessed in the order they are added into the dict. It guarantees the order\r
924# by making use of an internal list to keep a copy of keys.\r
925#\r
926class sdict(IterableUserDict):\r
927 ## Constructor\r
928 def __init__(self):\r
929 IterableUserDict.__init__(self)\r
930 self._key_list = []\r
931\r
932 ## [] operator\r
933 def __setitem__(self, key, value):\r
934 if key not in self._key_list:\r
935 self._key_list.append(key)\r
936 IterableUserDict.__setitem__(self, key, value)\r
937\r
938 ## del operator\r
939 def __delitem__(self, key):\r
940 self._key_list.remove(key)\r
941 IterableUserDict.__delitem__(self, key)\r
942\r
943 ## used in "for k in dict" loop to ensure the correct order\r
944 def __iter__(self):\r
945 return self.iterkeys()\r
946\r
947 ## len() support\r
948 def __len__(self):\r
949 return len(self._key_list)\r
950\r
951 ## "in" test support\r
952 def __contains__(self, key):\r
953 return key in self._key_list\r
954\r
955 ## indexof support\r
956 def index(self, key):\r
957 return self._key_list.index(key)\r
958\r
959 ## insert support\r
960 def insert(self, key, newkey, newvalue, order):\r
961 index = self._key_list.index(key)\r
962 if order == 'BEFORE':\r
963 self._key_list.insert(index, newkey)\r
964 IterableUserDict.__setitem__(self, newkey, newvalue)\r
965 elif order == 'AFTER':\r
966 self._key_list.insert(index + 1, newkey)\r
967 IterableUserDict.__setitem__(self, newkey, newvalue)\r
968\r
969 ## append support\r
970 def append(self, sdict):\r
971 for key in sdict:\r
972 if key not in self._key_list:\r
973 self._key_list.append(key)\r
974 IterableUserDict.__setitem__(self, key, sdict[key])\r
975\r
976 def has_key(self, key):\r
977 return key in self._key_list\r
978\r
979 ## Empty the dict\r
980 def clear(self):\r
981 self._key_list = []\r
982 IterableUserDict.clear(self)\r
983\r
984 ## Return a copy of keys\r
985 def keys(self):\r
986 keys = []\r
987 for key in self._key_list:\r
988 keys.append(key)\r
989 return keys\r
990\r
991 ## Return a copy of values\r
992 def values(self):\r
993 values = []\r
994 for key in self._key_list:\r
995 values.append(self[key])\r
996 return values\r
997\r
998 ## Return a copy of (key, value) list\r
999 def items(self):\r
1000 items = []\r
1001 for key in self._key_list:\r
1002 items.append((key, self[key]))\r
1003 return items\r
1004\r
1005 ## Iteration support\r
1006 def iteritems(self):\r
1007 return iter(self.items())\r
1008\r
1009 ## Keys interation support\r
1010 def iterkeys(self):\r
1011 return iter(self.keys())\r
1012\r
1013 ## Values interation support\r
1014 def itervalues(self):\r
1015 return iter(self.values())\r
1016\r
1017 ## Return value related to a key, and remove the (key, value) from the dict\r
1018 def pop(self, key, *dv):\r
1019 value = None\r
1020 if key in self._key_list:\r
1021 value = self[key]\r
1022 self.__delitem__(key)\r
1023 elif len(dv) != 0 :\r
1024 value = kv[0]\r
1025 return value\r
1026\r
1027 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1028 def popitem(self):\r
1029 key = self._key_list[-1]\r
1030 value = self[key]\r
1031 self.__delitem__(key)\r
1032 return key, value\r
1033\r
1034 def update(self, dict=None, **kwargs):\r
4231a819 1035 if dict is not None:\r
f51461c8
LG
1036 for k, v in dict.items():\r
1037 self[k] = v\r
1038 if len(kwargs):\r
1039 for k, v in kwargs.items():\r
1040 self[k] = v\r
1041\r
1042## Dictionary with restricted keys\r
1043#\r
1044class rdict(dict):\r
1045 ## Constructor\r
1046 def __init__(self, KeyList):\r
1047 for Key in KeyList:\r
1048 dict.__setitem__(self, Key, "")\r
1049\r
1050 ## []= operator\r
1051 def __setitem__(self, key, value):\r
1052 if key not in self:\r
1053 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,\r
1054 ExtraData=", ".join(dict.keys(self)))\r
1055 dict.__setitem__(self, key, value)\r
1056\r
1057 ## =[] operator\r
1058 def __getitem__(self, key):\r
1059 if key not in self:\r
1060 return ""\r
1061 return dict.__getitem__(self, key)\r
1062\r
1063 ## del operator\r
1064 def __delitem__(self, key):\r
1065 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")\r
1066\r
1067 ## Empty the dict\r
1068 def clear(self):\r
1069 for Key in self:\r
1070 self.__setitem__(Key, "")\r
1071\r
1072 ## Return value related to a key, and remove the (key, value) from the dict\r
1073 def pop(self, key, *dv):\r
1074 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")\r
1075\r
1076 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1077 def popitem(self):\r
1078 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")\r
1079\r
1080## Dictionary using prioritized list as key\r
1081#\r
1082class tdict:\r
1083 _ListType = type([])\r
1084 _TupleType = type(())\r
1085 _Wildcard = 'COMMON'\r
1086 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']\r
1087\r
1088 def __init__(self, _Single_=False, _Level_=2):\r
1089 self._Level_ = _Level_\r
1090 self.data = {}\r
1091 self._Single_ = _Single_\r
1092\r
1093 # =[] operator\r
1094 def __getitem__(self, key):\r
1095 KeyType = type(key)\r
1096 RestKeys = None\r
1097 if KeyType == self._ListType or KeyType == self._TupleType:\r
1098 FirstKey = key[0]\r
1099 if len(key) > 1:\r
1100 RestKeys = key[1:]\r
1101 elif self._Level_ > 1:\r
47fea6af 1102 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1103 else:\r
1104 FirstKey = key\r
1105 if self._Level_ > 1:\r
47fea6af 1106 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8 1107\r
4231a819 1108 if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:\r
f51461c8
LG
1109 FirstKey = self._Wildcard\r
1110\r
1111 if self._Single_:\r
1112 return self._GetSingleValue(FirstKey, RestKeys)\r
1113 else:\r
1114 return self._GetAllValues(FirstKey, RestKeys)\r
1115\r
1116 def _GetSingleValue(self, FirstKey, RestKeys):\r
1117 Value = None\r
1118 #print "%s-%s" % (FirstKey, self._Level_) ,\r
1119 if self._Level_ > 1:\r
1120 if FirstKey == self._Wildcard:\r
1121 if FirstKey in self.data:\r
1122 Value = self.data[FirstKey][RestKeys]\r
4231a819 1123 if Value is None:\r
f51461c8
LG
1124 for Key in self.data:\r
1125 Value = self.data[Key][RestKeys]\r
4231a819 1126 if Value is not None: break\r
f51461c8
LG
1127 else:\r
1128 if FirstKey in self.data:\r
1129 Value = self.data[FirstKey][RestKeys]\r
4231a819 1130 if Value is None and self._Wildcard in self.data:\r
f51461c8
LG
1131 #print "Value=None"\r
1132 Value = self.data[self._Wildcard][RestKeys]\r
1133 else:\r
1134 if FirstKey == self._Wildcard:\r
1135 if FirstKey in self.data:\r
1136 Value = self.data[FirstKey]\r
4231a819 1137 if Value is None:\r
f51461c8
LG
1138 for Key in self.data:\r
1139 Value = self.data[Key]\r
4231a819 1140 if Value is not None: break\r
f51461c8
LG
1141 else:\r
1142 if FirstKey in self.data:\r
1143 Value = self.data[FirstKey]\r
1144 elif self._Wildcard in self.data:\r
1145 Value = self.data[self._Wildcard]\r
1146 return Value\r
1147\r
1148 def _GetAllValues(self, FirstKey, RestKeys):\r
1149 Value = []\r
1150 if self._Level_ > 1:\r
1151 if FirstKey == self._Wildcard:\r
1152 for Key in self.data:\r
1153 Value += self.data[Key][RestKeys]\r
1154 else:\r
1155 if FirstKey in self.data:\r
1156 Value += self.data[FirstKey][RestKeys]\r
1157 if self._Wildcard in self.data:\r
1158 Value += self.data[self._Wildcard][RestKeys]\r
1159 else:\r
1160 if FirstKey == self._Wildcard:\r
1161 for Key in self.data:\r
1162 Value.append(self.data[Key])\r
1163 else:\r
1164 if FirstKey in self.data:\r
1165 Value.append(self.data[FirstKey])\r
1166 if self._Wildcard in self.data:\r
1167 Value.append(self.data[self._Wildcard])\r
1168 return Value\r
1169\r
1170 ## []= operator\r
1171 def __setitem__(self, key, value):\r
1172 KeyType = type(key)\r
1173 RestKeys = None\r
1174 if KeyType == self._ListType or KeyType == self._TupleType:\r
1175 FirstKey = key[0]\r
1176 if len(key) > 1:\r
1177 RestKeys = key[1:]\r
1178 else:\r
47fea6af 1179 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1180 else:\r
1181 FirstKey = key\r
1182 if self._Level_ > 1:\r
47fea6af 1183 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1184\r
1185 if FirstKey in self._ValidWildcardList:\r
1186 FirstKey = self._Wildcard\r
1187\r
1188 if FirstKey not in self.data and self._Level_ > 0:\r
1189 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
1190\r
1191 if self._Level_ > 1:\r
1192 self.data[FirstKey][RestKeys] = value\r
1193 else:\r
1194 self.data[FirstKey] = value\r
1195\r
1196 def SetGreedyMode(self):\r
1197 self._Single_ = False\r
1198 if self._Level_ > 1:\r
1199 for Key in self.data:\r
1200 self.data[Key].SetGreedyMode()\r
1201\r
1202 def SetSingleMode(self):\r
1203 self._Single_ = True\r
1204 if self._Level_ > 1:\r
1205 for Key in self.data:\r
1206 self.data[Key].SetSingleMode()\r
1207\r
1208 def GetKeys(self, KeyIndex=0):\r
1209 assert KeyIndex >= 0\r
1210 if KeyIndex == 0:\r
1211 return set(self.data.keys())\r
1212 else:\r
1213 keys = set()\r
1214 for Key in self.data:\r
1215 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
1216 return keys\r
1217\r
8565b582
YZ
1218def IsFieldValueAnArray (Value):\r
1219 Value = Value.strip()\r
1220 if Value.startswith('GUID') and Value.endswith(')'):\r
1221 return True\r
1222 if Value.startswith('L"') and Value.endswith('"') and len(list(Value[2:-1])) > 1:\r
1223 return True\r
1224 if Value[0] == '"' and Value[-1] == '"' and len(list(Value[1:-1])) > 1:\r
1225 return True\r
1226 if Value[0] == '{' and Value[-1] == '}':\r
1227 return True\r
1228 if Value.startswith("L'") and Value.endswith("'") and len(list(Value[2:-1])) > 1:\r
1229 return True\r
1230 if Value[0] == "'" and Value[-1] == "'" and len(list(Value[1:-1])) > 1:\r
1231 return True\r
1232 return False\r
1233\r
67e11e4d 1234def AnalyzePcdExpression(Setting):\r
f51461c8 1235 Setting = Setting.strip()\r
ea927d2f
FY
1236 # There might be escaped quote in a string: \", \\\" , \', \\\'\r
1237 Data = Setting\r
f51461c8
LG
1238 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
1239 NewStr = ''\r
ea927d2f
FY
1240 InSingleQuoteStr = False\r
1241 InDoubleQuoteStr = False\r
f51461c8 1242 Pair = 0\r
ea927d2f
FY
1243 for Index, ch in enumerate(Data):\r
1244 if ch == '"' and not InSingleQuoteStr:\r
1245 if Data[Index - 1] != '\\':\r
1246 InDoubleQuoteStr = not InDoubleQuoteStr\r
1247 elif ch == "'" and not InDoubleQuoteStr:\r
1248 if Data[Index - 1] != '\\':\r
1249 InSingleQuoteStr = not InSingleQuoteStr\r
1250 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1251 Pair += 1\r
ea927d2f 1252 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1253 Pair -= 1\r
47fea6af 1254\r
ea927d2f 1255 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:\r
f51461c8
LG
1256 NewStr += '-'\r
1257 else:\r
1258 NewStr += ch\r
1259 FieldList = []\r
1260 StartPos = 0\r
1261 while True:\r
1262 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
1263 if Pos < 0:\r
1264 FieldList.append(Setting[StartPos:].strip())\r
1265 break\r
1266 FieldList.append(Setting[StartPos:Pos].strip())\r
1267 StartPos = Pos + 1\r
1268\r
67e11e4d
YZ
1269 return FieldList\r
1270\r
726c501c 1271def ParseDevPathValue (Value):\r
7dbc50bd
YZ
1272 if '\\' in Value:\r
1273 Value.replace('\\', '/').replace(' ', '')\r
7dbc50bd
YZ
1274\r
1275 Cmd = 'DevicePath ' + '"' + Value + '"'\r
1276 try:\r
1277 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
1278 out, err = p.communicate()\r
1279 except Exception, X:\r
1280 raise BadExpression("DevicePath: %s" % (str(X)) )\r
1281 finally:\r
1282 subprocess._cleanup()\r
1283 p.stdout.close()\r
1284 p.stderr.close()\r
1285 if err:\r
1286 raise BadExpression("DevicePath: %s" % str(err))\r
1287 Size = len(out.split())\r
1288 out = ','.join(out.split())\r
1289 return '{' + out + '}', Size\r
726c501c 1290\r
ae7b6df8 1291def ParseFieldValue (Value):\r
726c501c
YZ
1292 if type(Value) == type(0):\r
1293 return Value, (Value.bit_length() + 7) / 8\r
1294 if type(Value) <> type(''):\r
1295 raise BadExpression('Type %s is %s' %(Value, type(Value)))\r
1296 Value = Value.strip()\r
656d2539 1297 if Value.startswith(TAB_UINT8) and Value.endswith(')'):\r
726c501c
YZ
1298 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1299 if Size > 1:\r
1300 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1301 return Value, 1\r
656d2539 1302 if Value.startswith(TAB_UINT16) and Value.endswith(')'):\r
726c501c
YZ
1303 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1304 if Size > 2:\r
1305 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1306 return Value, 2\r
656d2539 1307 if Value.startswith(TAB_UINT32) and Value.endswith(')'):\r
726c501c
YZ
1308 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1309 if Size > 4:\r
1310 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1311 return Value, 4\r
656d2539 1312 if Value.startswith(TAB_UINT64) and Value.endswith(')'):\r
726c501c
YZ
1313 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1314 if Size > 8:\r
1315 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))\r
1316 return Value, 8\r
1317 if Value.startswith('GUID') and Value.endswith(')'):\r
1318 Value = Value.split('(', 1)[1][:-1].strip()\r
1319 if Value[0] == '{' and Value[-1] == '}':\r
4344a788
FY
1320 TmpValue = GuidStructureStringToGuidString(Value)\r
1321 if len(TmpValue) == 0:\r
1322 raise BadExpression("Invalid GUID value string %s" % Value)\r
1323 Value = TmpValue\r
726c501c
YZ
1324 if Value[0] == '"' and Value[-1] == '"':\r
1325 Value = Value[1:-1]\r
1326 try:\r
1327 Value = "'" + uuid.UUID(Value).get_bytes_le() + "'"\r
1328 except ValueError, Message:\r
1329 raise BadExpression('%s' % Message)\r
1330 Value, Size = ParseFieldValue(Value)\r
1331 return Value, 16\r
1332 if Value.startswith('L"') and Value.endswith('"'):\r
1333 # Unicode String\r
4faf1322
FY
1334 # translate escape character\r
1335 Value = Value[1:]\r
1336 try:\r
1337 Value = eval(Value)\r
1338 except:\r
1339 Value = Value[1:-1]\r
1340 List = list(Value)\r
726c501c
YZ
1341 List.reverse()\r
1342 Value = 0\r
1343 for Char in List:\r
1344 Value = (Value << 16) | ord(Char)\r
1345 return Value, (len(List) + 1) * 2\r
1346 if Value.startswith('"') and Value.endswith('"'):\r
1347 # ASCII String\r
4faf1322
FY
1348 # translate escape character\r
1349 try:\r
1350 Value = eval(Value)\r
1351 except:\r
1352 Value = Value[1:-1]\r
1353 List = list(Value)\r
726c501c
YZ
1354 List.reverse()\r
1355 Value = 0\r
1356 for Char in List:\r
1357 Value = (Value << 8) | ord(Char)\r
1358 return Value, len(List) + 1\r
1359 if Value.startswith("L'") and Value.endswith("'"):\r
1360 # Unicode Character Constant\r
4faf1322
FY
1361 # translate escape character\r
1362 Value = Value[1:]\r
1363 try:\r
1364 Value = eval(Value)\r
1365 except:\r
1366 Value = Value[1:-1]\r
1367 List = list(Value)\r
0e6b8673
FY
1368 if len(List) == 0:\r
1369 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1370 List.reverse()\r
1371 Value = 0\r
1372 for Char in List:\r
1373 Value = (Value << 16) | ord(Char)\r
1374 return Value, len(List) * 2\r
1375 if Value.startswith("'") and Value.endswith("'"):\r
1376 # Character constant\r
4faf1322
FY
1377 # translate escape character\r
1378 try:\r
1379 Value = eval(Value)\r
1380 except:\r
1381 Value = Value[1:-1]\r
1382 List = list(Value)\r
0e6b8673
FY
1383 if len(List) == 0:\r
1384 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1385 List.reverse()\r
1386 Value = 0\r
1387 for Char in List:\r
1388 Value = (Value << 8) | ord(Char)\r
1389 return Value, len(List)\r
1390 if Value.startswith('{') and Value.endswith('}'):\r
1391 # Byte array\r
1392 Value = Value[1:-1]\r
1393 List = [Item.strip() for Item in Value.split(',')]\r
1394 List.reverse()\r
1395 Value = 0\r
1396 RetSize = 0\r
1397 for Item in List:\r
1398 ItemValue, Size = ParseFieldValue(Item)\r
1399 RetSize += Size\r
1400 for I in range(Size):\r
1401 Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)\r
1402 return Value, RetSize\r
1403 if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):\r
8ad5f10a
FY
1404 Value = Value.replace("DEVICE_PATH(", '').rstrip(')')\r
1405 Value = Value.strip().strip('"')\r
726c501c
YZ
1406 return ParseDevPathValue(Value)\r
1407 if Value.lower().startswith('0x'):\r
1408 Value = int(Value, 16)\r
1409 if Value == 0:\r
1410 return 0, 1\r
1411 return Value, (Value.bit_length() + 7) / 8\r
1412 if Value[0].isdigit():\r
1413 Value = int(Value, 10)\r
1414 if Value == 0:\r
1415 return 0, 1\r
1416 return Value, (Value.bit_length() + 7) / 8\r
1417 if Value.lower() == 'true':\r
1418 return 1, 1\r
1419 if Value.lower() == 'false':\r
1420 return 0, 1\r
ae7b6df8 1421 return Value, 1\r
ae7b6df8 1422\r
67e11e4d
YZ
1423## AnalyzeDscPcd\r
1424#\r
1425# Analyze DSC PCD value, since there is no data type info in DSC\r
ab0ff0b0 1426# This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database\r
67e11e4d
YZ
1427# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
1428# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]\r
1429# 3. Dynamic default:\r
1430# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1431# TokenSpace.PcdCName|PcdValue\r
1432# 4. Dynamic VPD:\r
1433# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1434# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1435# 5. Dynamic HII:\r
1436# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]\r
1437# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1438# there might have "|" operator, also in string value.\r
1439#\r
1440# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1441# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1442# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1443# @retval:\r
1444# ValueList: A List contain fields described above\r
1445# IsValid: True if conforming EBNF, otherwise False\r
1446# Index: The index where PcdValue is in ValueList\r
1447#\r
1448def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1449 FieldList = AnalyzePcdExpression(Setting)\r
1450\r
f51461c8
LG
1451 IsValid = True\r
1452 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):\r
1453 Value = FieldList[0]\r
1454 Size = ''\r
1455 if len(FieldList) > 1:\r
ae7b6df8 1456 if FieldList[1].upper().startswith("0X") or FieldList[1].isdigit():\r
f51461c8 1457 Size = FieldList[1]\r
ae7b6df8
LG
1458 else:\r
1459 DataType = FieldList[1]\r
1460\r
f51461c8
LG
1461 if len(FieldList) > 2:\r
1462 Size = FieldList[2]\r
ae7b6df8 1463 if DataType == "":\r
f51461c8 1464 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1465 else:\r
1466 IsValid = (len(FieldList) <= 3)\r
1467# Value, Size = ParseFieldValue(Value)\r
520365de
B
1468 if Size:\r
1469 try:\r
1470 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1471 except:\r
1472 IsValid = False\r
1473 Size = -1\r
ae7b6df8 1474 return [str(Value), '', str(Size)], IsValid, 0\r
f51461c8
LG
1475 elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):\r
1476 Value = FieldList[0]\r
1477 Size = Type = ''\r
1478 if len(FieldList) > 1:\r
1479 Type = FieldList[1]\r
1480 else:\r
1481 Type = DataType\r
1482 if len(FieldList) > 2:\r
1483 Size = FieldList[2]\r
ae7b6df8 1484 if DataType == "":\r
f51461c8 1485 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1486 else:\r
1487 IsValid = (len(FieldList) <= 3)\r
520365de
B
1488\r
1489 if Size:\r
1490 try:\r
1491 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1492 except:\r
1493 IsValid = False\r
1494 Size = -1\r
1495 return [Value, Type, str(Size)], IsValid, 0\r
f51461c8
LG
1496 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1497 VpdOffset = FieldList[0]\r
1498 Value = Size = ''\r
656d2539 1499 if not DataType == TAB_VOID:\r
f51461c8
LG
1500 if len(FieldList) > 1:\r
1501 Value = FieldList[1]\r
1502 else:\r
1503 if len(FieldList) > 1:\r
1504 Size = FieldList[1]\r
1505 if len(FieldList) > 2:\r
1506 Value = FieldList[2]\r
ae7b6df8
LG
1507 if DataType == "":\r
1508 IsValid = (len(FieldList) <= 1)\r
f51461c8 1509 else:\r
ae7b6df8 1510 IsValid = (len(FieldList) <= 3)\r
520365de
B
1511 if Size:\r
1512 try:\r
1513 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1514 except:\r
1515 IsValid = False\r
1516 Size = -1\r
1517 return [VpdOffset, str(Size), Value], IsValid, 2\r
f51461c8
LG
1518 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
1519 HiiString = FieldList[0]\r
82a6a960 1520 Guid = Offset = Value = Attribute = ''\r
f51461c8
LG
1521 if len(FieldList) > 1:\r
1522 Guid = FieldList[1]\r
1523 if len(FieldList) > 2:\r
1524 Offset = FieldList[2]\r
1525 if len(FieldList) > 3:\r
1526 Value = FieldList[3]\r
82a6a960
BF
1527 if len(FieldList) > 4:\r
1528 Attribute = FieldList[4]\r
1529 IsValid = (3 <= len(FieldList) <= 5)\r
1530 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
f51461c8
LG
1531 return [], False, 0\r
1532\r
1533## AnalyzePcdData\r
1534#\r
1535# Analyze the pcd Value, Datum type and TokenNumber.\r
1536# Used to avoid split issue while the value string contain "|" character\r
1537#\r
1538# @param[in] Setting: A String contain value/datum type/token number information;\r
1539# \r
1540# @retval ValueList: A List contain value, datum type and toke number. \r
1541#\r
47fea6af
YZ
1542def AnalyzePcdData(Setting):\r
1543 ValueList = ['', '', '']\r
1544\r
1545 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
f51461c8
LG
1546 PtrValue = ValueRe.findall(Setting)\r
1547 \r
1548 ValueUpdateFlag = False\r
1549 \r
1550 if len(PtrValue) >= 1:\r
1551 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1552 ValueUpdateFlag = True\r
f51461c8
LG
1553\r
1554 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1555 ValueList[0:len(TokenList)] = TokenList\r
1556 \r
1557 if ValueUpdateFlag:\r
1558 ValueList[0] = PtrValue[0]\r
1559 \r
1560 return ValueList \r
1561 \r
f51461c8
LG
1562## check format of PCD value against its the datum type\r
1563#\r
1564# For PCD value setting\r
1565#\r
1566def CheckPcdDatum(Type, Value):\r
656d2539 1567 if Type == TAB_VOID:\r
47fea6af 1568 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
f51461c8 1569 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
d5988a8a 1570 or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))\r
f51461c8
LG
1571 ):\r
1572 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
d5988a8a 1573 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)\r
f51461c8
LG
1574 elif ValueRe.match(Value):\r
1575 # Check the chars in UnicodeString or CString is printable\r
1576 if Value.startswith("L"):\r
1577 Value = Value[2:-1]\r
1578 else:\r
1579 Value = Value[1:-1]\r
1580 Printset = set(string.printable)\r
1581 Printset.remove(TAB_PRINTCHAR_VT)\r
1582 Printset.add(TAB_PRINTCHAR_BS)\r
1583 Printset.add(TAB_PRINTCHAR_NUL)\r
1584 if not set(Value).issubset(Printset):\r
1585 PrintList = list(Printset)\r
1586 PrintList.sort()\r
1587 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1588 elif Type == 'BOOLEAN':\r
1589 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1590 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1591 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1592 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
1593 try:\r
1594 Value = long(Value, 0)\r
1595 except:\r
1596 return False, "Invalid value [%s] of type [%s];"\\r
1597 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
1598 else:\r
ae7b6df8 1599 return True, "StructurePcd"\r
f51461c8
LG
1600\r
1601 return True, ""\r
1602\r
1603## Split command line option string to list\r
1604#\r
1605# subprocess.Popen needs the args to be a sequence. Otherwise there's problem\r
1606# in non-windows platform to launch command\r
1607#\r
1608def SplitOption(OptionString):\r
1609 OptionList = []\r
1610 LastChar = " "\r
1611 OptionStart = 0\r
1612 QuotationMark = ""\r
1613 for Index in range(0, len(OptionString)):\r
1614 CurrentChar = OptionString[Index]\r
1615 if CurrentChar in ['"', "'"]:\r
1616 if QuotationMark == CurrentChar:\r
1617 QuotationMark = ""\r
1618 elif QuotationMark == "":\r
1619 QuotationMark = CurrentChar\r
1620 continue\r
1621 elif QuotationMark:\r
1622 continue\r
1623\r
1624 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:\r
1625 if Index > OptionStart:\r
47fea6af 1626 OptionList.append(OptionString[OptionStart:Index - 1])\r
f51461c8
LG
1627 OptionStart = Index\r
1628 LastChar = CurrentChar\r
1629 OptionList.append(OptionString[OptionStart:])\r
1630 return OptionList\r
1631\r
1632def CommonPath(PathList):\r
1633 P1 = min(PathList).split(os.path.sep)\r
1634 P2 = max(PathList).split(os.path.sep)\r
1635 for Index in xrange(min(len(P1), len(P2))):\r
1636 if P1[Index] != P2[Index]:\r
1637 return os.path.sep.join(P1[:Index])\r
1638 return os.path.sep.join(P1)\r
1639\r
97fa0ee9
YL
1640#\r
1641# Convert string to C format array\r
1642#\r
1643def ConvertStringToByteArray(Value):\r
1644 Value = Value.strip()\r
1645 if not Value:\r
1646 return None\r
1647 if Value[0] == '{':\r
1648 if not Value.endswith('}'):\r
1649 return None\r
1650 Value = Value.replace(' ', '').replace('{', '').replace('}', '')\r
1651 ValFields = Value.split(',')\r
1652 try:\r
1653 for Index in range(len(ValFields)):\r
1654 ValFields[Index] = str(int(ValFields[Index], 0))\r
1655 except ValueError:\r
1656 return None\r
1657 Value = '{' + ','.join(ValFields) + '}'\r
1658 return Value\r
1659\r
1660 Unicode = False\r
1661 if Value.startswith('L"'):\r
1662 if not Value.endswith('"'):\r
1663 return None\r
1664 Value = Value[1:]\r
1665 Unicode = True\r
1666 elif not Value.startswith('"') or not Value.endswith('"'):\r
1667 return None\r
1668\r
1669 Value = eval(Value) # translate escape character\r
1670 NewValue = '{'\r
1671 for Index in range(0,len(Value)):\r
1672 if Unicode:\r
1673 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','\r
1674 else:\r
1675 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','\r
1676 Value = NewValue + '0}'\r
1677 return Value\r
1678\r
f51461c8
LG
1679class PathClass(object):\r
1680 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1681 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1682 self.Arch = Arch\r
1683 self.File = str(File)\r
1684 if os.path.isabs(self.File):\r
1685 self.Root = ''\r
1686 self.AlterRoot = ''\r
1687 else:\r
1688 self.Root = str(Root)\r
1689 self.AlterRoot = str(AlterRoot)\r
1690\r
1691 # Remove any '.' and '..' in path\r
1692 if self.Root:\r
05cc51ad 1693 self.Root = mws.getWs(self.Root, self.File)\r
f51461c8
LG
1694 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1695 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1696 # eliminate the side-effect of 'C:'\r
1697 if self.Root[-1] == ':':\r
1698 self.Root += os.path.sep\r
1699 # file path should not start with path separator\r
1700 if self.Root[-1] == os.path.sep:\r
1701 self.File = self.Path[len(self.Root):]\r
1702 else:\r
47fea6af 1703 self.File = self.Path[len(self.Root) + 1:]\r
f51461c8
LG
1704 else:\r
1705 self.Path = os.path.normpath(self.File)\r
1706\r
1707 self.SubDir, self.Name = os.path.split(self.File)\r
1708 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1709\r
1710 if self.Root:\r
1711 if self.SubDir:\r
1712 self.Dir = os.path.join(self.Root, self.SubDir)\r
1713 else:\r
1714 self.Dir = self.Root\r
1715 else:\r
1716 self.Dir = self.SubDir\r
1717\r
1718 if IsBinary:\r
1719 self.Type = Type\r
1720 else:\r
1721 self.Type = self.Ext.lower()\r
1722\r
1723 self.IsBinary = IsBinary\r
1724 self.Target = Target\r
1725 self.TagName = TagName\r
1726 self.ToolCode = ToolCode\r
1727 self.ToolChainFamily = ToolChainFamily\r
1728\r
1729 self._Key = None\r
1730\r
1731 ## Convert the object of this class to a string\r
1732 #\r
1733 # Convert member Path of the class to a string\r
1734 #\r
1735 # @retval string Formatted String\r
1736 #\r
1737 def __str__(self):\r
1738 return self.Path\r
1739\r
1740 ## Override __eq__ function\r
1741 #\r
1742 # Check whether PathClass are the same\r
1743 #\r
1744 # @retval False The two PathClass are different\r
1745 # @retval True The two PathClass are the same\r
1746 #\r
1747 def __eq__(self, Other):\r
1748 if type(Other) == type(self):\r
1749 return self.Path == Other.Path\r
1750 else:\r
1751 return self.Path == str(Other)\r
1752\r
1753 ## Override __cmp__ function\r
1754 #\r
1755 # Customize the comparsion operation of two PathClass\r
1756 #\r
1757 # @retval 0 The two PathClass are different\r
1758 # @retval -1 The first PathClass is less than the second PathClass\r
1759 # @retval 1 The first PathClass is Bigger than the second PathClass\r
1760 def __cmp__(self, Other):\r
1761 if type(Other) == type(self):\r
1762 OtherKey = Other.Path\r
1763 else:\r
1764 OtherKey = str(Other)\r
1765 \r
1766 SelfKey = self.Path\r
1767 if SelfKey == OtherKey:\r
1768 return 0\r
1769 elif SelfKey > OtherKey:\r
1770 return 1\r
1771 else:\r
1772 return -1\r
1773\r
1774 ## Override __hash__ function\r
1775 #\r
1776 # Use Path as key in hash table\r
1777 #\r
1778 # @retval string Key for hash table\r
1779 #\r
1780 def __hash__(self):\r
1781 return hash(self.Path)\r
1782\r
1783 def _GetFileKey(self):\r
4231a819 1784 if self._Key is None:\r
f51461c8
LG
1785 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target\r
1786 return self._Key\r
1787\r
1788 def _GetTimeStamp(self):\r
1789 return os.stat(self.Path)[8]\r
1790\r
1791 def Validate(self, Type='', CaseSensitive=True):\r
1792 if GlobalData.gCaseInsensitive:\r
1793 CaseSensitive = False\r
1794 if Type and Type.lower() != self.Type:\r
1795 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
1796\r
1797 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
1798 if not RealRoot and not RealFile:\r
1799 RealFile = self.File\r
1800 if self.AlterRoot:\r
1801 RealFile = os.path.join(self.AlterRoot, self.File)\r
1802 elif self.Root:\r
1803 RealFile = os.path.join(self.Root, self.File)\r
05cc51ad
LY
1804 if len (mws.getPkgPath()) == 0:\r
1805 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
1806 else:\r
1807 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
f51461c8
LG
1808\r
1809 ErrorCode = 0\r
1810 ErrorInfo = ''\r
1811 if RealRoot != self.Root or RealFile != self.File:\r
1812 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
1813 ErrorCode = FILE_CASE_MISMATCH\r
1814 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
1815\r
1816 self.SubDir, self.Name = os.path.split(RealFile)\r
1817 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1818 if self.SubDir:\r
1819 self.Dir = os.path.join(RealRoot, self.SubDir)\r
1820 else:\r
1821 self.Dir = RealRoot\r
1822 self.File = RealFile\r
1823 self.Root = RealRoot\r
1824 self.Path = os.path.join(RealRoot, RealFile)\r
1825 return ErrorCode, ErrorInfo\r
1826\r
1827 Key = property(_GetFileKey)\r
1828 TimeStamp = property(_GetTimeStamp)\r
1829\r
1830## Parse PE image to get the required PE informaion.\r
1831#\r
1832class PeImageClass():\r
1833 ## Constructor\r
1834 #\r
1835 # @param File FilePath of PeImage\r
1836 #\r
1837 def __init__(self, PeFile):\r
1838 self.FileName = PeFile\r
1839 self.IsValid = False\r
1840 self.Size = 0\r
1841 self.EntryPoint = 0\r
1842 self.SectionAlignment = 0\r
1843 self.SectionHeaderList = []\r
1844 self.ErrorInfo = ''\r
1845 try:\r
1846 PeObject = open(PeFile, 'rb')\r
1847 except:\r
1848 self.ErrorInfo = self.FileName + ' can not be found\n'\r
1849 return\r
1850 # Read DOS header\r
1851 ByteArray = array.array('B')\r
1852 ByteArray.fromfile(PeObject, 0x3E)\r
1853 ByteList = ByteArray.tolist()\r
1854 # DOS signature should be 'MZ'\r
1855 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
1856 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
1857 return\r
1858\r
1859 # Read 4 byte PE Signature\r
1860 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
1861 PeObject.seek(PeOffset)\r
1862 ByteArray = array.array('B')\r
1863 ByteArray.fromfile(PeObject, 4)\r
1864 # PE signature should be 'PE\0\0'\r
1865 if ByteArray.tostring() != 'PE\0\0':\r
1866 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
1867 return\r
1868\r
1869 # Read PE file header\r
1870 ByteArray = array.array('B')\r
1871 ByteArray.fromfile(PeObject, 0x14)\r
1872 ByteList = ByteArray.tolist()\r
1873 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
1874 if SecNumber == 0:\r
1875 self.ErrorInfo = self.FileName + ' has no section header'\r
1876 return\r
1877\r
1878 # Read PE optional header\r
1879 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
1880 ByteArray = array.array('B')\r
1881 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
1882 ByteList = ByteArray.tolist()\r
1883 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
1884 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
1885 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
1886\r
1887 # Read each Section Header\r
1888 for Index in range(SecNumber):\r
1889 ByteArray = array.array('B')\r
1890 ByteArray.fromfile(PeObject, 0x28)\r
1891 ByteList = ByteArray.tolist()\r
1892 SecName = self._ByteListToStr(ByteList[0:8])\r
1893 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
1894 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
1895 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
1896 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
1897 self.IsValid = True\r
1898 PeObject.close()\r
1899\r
1900 def _ByteListToStr(self, ByteList):\r
1901 String = ''\r
1902 for index in range(len(ByteList)):\r
1903 if ByteList[index] == 0: \r
1904 break\r
1905 String += chr(ByteList[index])\r
1906 return String\r
1907\r
1908 def _ByteListToInt(self, ByteList):\r
1909 Value = 0\r
1910 for index in range(len(ByteList) - 1, -1, -1):\r
1911 Value = (Value << 8) | int(ByteList[index])\r
1912 return Value\r
1913\r
8518bf0b
LG
1914class DefaultStore():\r
1915 def __init__(self,DefaultStores ):\r
1916\r
1917 self.DefaultStores = DefaultStores\r
1918 def DefaultStoreID(self,DefaultStoreName):\r
1919 for key,value in self.DefaultStores.items():\r
1920 if value == DefaultStoreName:\r
1921 return key\r
1922 return None\r
1923 def GetDefaultDefault(self):\r
1924 if not self.DefaultStores or "0" in self.DefaultStores:\r
1925 return "0",TAB_DEFAULT_STORES_DEFAULT\r
1926 else:\r
9eb87141 1927 minvalue = min([int(value_str) for value_str in self.DefaultStores])\r
8518bf0b
LG
1928 return (str(minvalue), self.DefaultStores[str(minvalue)])\r
1929 def GetMin(self,DefaultSIdList):\r
1930 if not DefaultSIdList:\r
4d3b9389 1931 return TAB_DEFAULT_STORES_DEFAULT\r
2b8a6c44
LG
1932 storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}\r
1933 if not storeidset:\r
1934 return ""\r
1935 minid = min(storeidset )\r
8518bf0b
LG
1936 for sid,name in self.DefaultStores.values():\r
1937 if sid == minid:\r
1938 return name\r
f51461c8
LG
1939class SkuClass():\r
1940 \r
1941 DEFAULT = 0\r
1942 SINGLE = 1\r
1943 MULTIPLE =2\r
1944 \r
8518bf0b
LG
1945 def __init__(self,SkuIdentifier='', SkuIds=None):\r
1946 if SkuIds is None:\r
1947 SkuIds = {}\r
c05c2c05
LG
1948\r
1949 for SkuName in SkuIds:\r
1950 SkuId = SkuIds[SkuName][0]\r
1951 skuid_num = int(SkuId,16) if SkuId.upper().startswith("0X") else int(SkuId)\r
e4ff28c3 1952 if skuid_num > 0xFFFFFFFFFFFFFFFF:\r
c05c2c05 1953 EdkLogger.error("build", PARAMETER_INVALID,\r
e4ff28c3
LG
1954 ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"\r
1955 % (SkuName, SkuId))\r
f51461c8
LG
1956 \r
1957 self.AvailableSkuIds = sdict()\r
1958 self.SkuIdSet = []\r
1ae469b9 1959 self.SkuIdNumberSet = []\r
8518bf0b
LG
1960 self.SkuData = SkuIds\r
1961 self.__SkuInherit = {}\r
c05c2c05 1962 self.__SkuIdentifier = SkuIdentifier\r
f51461c8
LG
1963 if SkuIdentifier == '' or SkuIdentifier is None:\r
1964 self.SkuIdSet = ['DEFAULT']\r
1ae469b9 1965 self.SkuIdNumberSet = ['0U']\r
f51461c8
LG
1966 elif SkuIdentifier == 'ALL':\r
1967 self.SkuIdSet = SkuIds.keys()\r
8518bf0b 1968 self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]\r
f51461c8
LG
1969 else:\r
1970 r = SkuIdentifier.split('|') \r
8518bf0b 1971 self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]\r
1ae469b9
BF
1972 k = None\r
1973 try: \r
8518bf0b 1974 self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]\r
1ae469b9
BF
1975 except Exception:\r
1976 EdkLogger.error("build", PARAMETER_INVALID,\r
1977 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1978 % (k, " | ".join(SkuIds.keys())))\r
f51461c8
LG
1979 for each in self.SkuIdSet:\r
1980 if each in SkuIds:\r
8518bf0b 1981 self.AvailableSkuIds[each] = SkuIds[each][0]\r
f51461c8
LG
1982 else:\r
1983 EdkLogger.error("build", PARAMETER_INVALID,\r
1984 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1985 % (each, " | ".join(SkuIds.keys())))\r
8518bf0b
LG
1986 if self.SkuUsageType != self.SINGLE:\r
1987 self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})\r
e651d06c
LG
1988 if self.SkuIdSet:\r
1989 GlobalData.gSkuids = (self.SkuIdSet)\r
1990 if 'COMMON' in GlobalData.gSkuids:\r
1991 GlobalData.gSkuids.remove('COMMON')\r
8aaa8f7b
YZ
1992 if self.SkuUsageType == self.SINGLE:\r
1993 if len(GlobalData.gSkuids) != 1:\r
1994 if 'DEFAULT' in GlobalData.gSkuids:\r
1995 GlobalData.gSkuids.remove('DEFAULT')\r
e651d06c
LG
1996 if GlobalData.gSkuids:\r
1997 GlobalData.gSkuids.sort()\r
1998\r
8518bf0b
LG
1999 def GetNextSkuId(self, skuname):\r
2000 if not self.__SkuInherit:\r
2001 self.__SkuInherit = {}\r
2002 for item in self.SkuData.values():\r
2003 self.__SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"\r
2004 return self.__SkuInherit.get(skuname,"DEFAULT")\r
c05c2c05
LG
2005\r
2006 def GetSkuChain(self,sku):\r
09c80b07
B
2007 if sku == "DEFAULT":\r
2008 return ["DEFAULT"]\r
c05c2c05
LG
2009 skulist = [sku]\r
2010 nextsku = sku\r
2011 while 1:\r
2012 nextsku = self.GetNextSkuId(nextsku)\r
2013 skulist.append(nextsku)\r
2014 if nextsku == "DEFAULT":\r
2015 break\r
2016 skulist.reverse()\r
2017 return skulist\r
2018 def SkuOverrideOrder(self):\r
2019 skuorderset = []\r
2020 for skuname in self.SkuIdSet:\r
2021 skuorderset.append(self.GetSkuChain(skuname))\r
f51461c8 2022 \r
c05c2c05
LG
2023 skuorder = []\r
2024 for index in range(max([len(item) for item in skuorderset])):\r
2025 for subset in skuorderset:\r
2026 if index > len(subset)-1:\r
2027 continue\r
2028 if subset[index] in skuorder:\r
2029 continue\r
2030 skuorder.append(subset[index])\r
2031\r
2032 return skuorder\r
2033\r
f51461c8
LG
2034 def __SkuUsageType(self): \r
2035 \r
c05c2c05
LG
2036 if self.__SkuIdentifier.upper() == "ALL":\r
2037 return SkuClass.MULTIPLE\r
2038\r
f51461c8
LG
2039 if len(self.SkuIdSet) == 1:\r
2040 if self.SkuIdSet[0] == 'DEFAULT':\r
2041 return SkuClass.DEFAULT\r
2042 else:\r
2043 return SkuClass.SINGLE\r
c05c2c05
LG
2044 elif len(self.SkuIdSet) == 2:\r
2045 if 'DEFAULT' in self.SkuIdSet:\r
2046 return SkuClass.SINGLE\r
2047 else:\r
2048 return SkuClass.MULTIPLE\r
f51461c8
LG
2049 else:\r
2050 return SkuClass.MULTIPLE\r
8518bf0b 2051 def DumpSkuIdArrary(self):\r
f51461c8 2052\r
8518bf0b
LG
2053 ArrayStrList = []\r
2054 if self.SkuUsageType == SkuClass.SINGLE:\r
2055 ArrayStr = "{0x0}"\r
2056 else:\r
2057 for skuname in self.AvailableSkuIds:\r
2058 if skuname == "COMMON":\r
2059 continue\r
2060 while skuname != "DEFAULT":\r
2061 ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))\r
2062 skuname = self.GetNextSkuId(skuname)\r
2063 ArrayStrList.append("0x0")\r
2064 ArrayStr = "{" + ",".join(ArrayStrList) + "}"\r
2065 return ArrayStr\r
f51461c8
LG
2066 def __GetAvailableSkuIds(self):\r
2067 return self.AvailableSkuIds\r
2068 \r
2069 def __GetSystemSkuID(self):\r
2070 if self.__SkuUsageType() == SkuClass.SINGLE:\r
c05c2c05
LG
2071 if len(self.SkuIdSet) == 1:\r
2072 return self.SkuIdSet[0]\r
2073 else:\r
2074 return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]\r
f51461c8
LG
2075 else:\r
2076 return 'DEFAULT'\r
1ae469b9
BF
2077 def __GetAvailableSkuIdNumber(self):\r
2078 return self.SkuIdNumberSet\r
f51461c8
LG
2079 SystemSkuId = property(__GetSystemSkuID)\r
2080 AvailableSkuIdSet = property(__GetAvailableSkuIds)\r
2081 SkuUsageType = property(__SkuUsageType)\r
1ae469b9 2082 AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)\r
a3251d84
YL
2083\r
2084#\r
2085# Pack a registry format GUID\r
2086#\r
2087def PackRegistryFormatGuid(Guid):\r
2088 Guid = Guid.split('-')\r
2089 return pack('=LHHBBBBBBBB',\r
2090 int(Guid[0], 16),\r
2091 int(Guid[1], 16),\r
2092 int(Guid[2], 16),\r
2093 int(Guid[3][-4:-2], 16),\r
2094 int(Guid[3][-2:], 16),\r
2095 int(Guid[4][-12:-10], 16),\r
2096 int(Guid[4][-10:-8], 16),\r
2097 int(Guid[4][-8:-6], 16),\r
2098 int(Guid[4][-6:-4], 16),\r
2099 int(Guid[4][-4:-2], 16),\r
2100 int(Guid[4][-2:], 16)\r
2101 )\r
2102\r
34952f49
LG
2103## Get the integer value from string like "14U" or integer like 2\r
2104#\r
2105# @param Input The object that may be either a integer value or a string\r
2106#\r
2107# @retval Value The integer value that the input represents\r
2108#\r
2109def GetIntegerValue(Input):\r
2110 if type(Input) in (int, long):\r
2111 return Input\r
2112 String = Input\r
2113 if String.endswith("U"):\r
2114 String = String[:-1]\r
2115 if String.endswith("ULL"):\r
2116 String = String[:-3]\r
2117 if String.endswith("LL"):\r
2118 String = String[:-2]\r
2119\r
2120 if String.startswith("0x") or String.startswith("0X"):\r
2121 return int(String, 16)\r
2122 elif String == '':\r
2123 return 0\r
2124 else:\r
2125 return int(String)\r
db55dac7 2126\r
f51461c8
LG
2127##\r
2128#\r
2129# This acts like the main() function for the script, unless it is 'import'ed into another\r
2130# script.\r
2131#\r
2132if __name__ == '__main__':\r
2133 pass\r
2134\r