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