]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
BaseTools: Update --pcd parser to support flexible pcd format
[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
79 for index, line in enumerate(lines):\r
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
88 if m != None:\r
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
YL
112 m = re.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line)\r
113 if m != None:\r
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
22a99b87 118 if m != None:\r
d03c056b
YZ
119 m = re.match(".data.(%s)$" % varname, line)\r
120 if m != None:\r
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
3e7e8571
YZ
126 if m != None:\r
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
133 if efisecs == None or len(efisecs) == 0:\r
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
169 assert m != None, "Fail to parse the section in map file , line is %s" % line\r
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
175 assert m != None, "Fail to parse the symbol in map file, line is %s" % line\r
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
181 if m2 != None:\r
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
191 if efisecs == None or len(efisecs) == 0:\r
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## callback routine for processing variable option\r
291#\r
292# This function can be used to process variable number of option values. The\r
293# typical usage of it is specify architecure list on command line.\r
294# (e.g. <tool> -a IA32 X64 IPF)\r
295#\r
296# @param Option Standard callback function parameter\r
297# @param OptionString Standard callback function parameter\r
298# @param Value Standard callback function parameter\r
299# @param Parser Standard callback function parameter\r
300#\r
301# @retval\r
302#\r
303def ProcessVariableArgument(Option, OptionString, Value, Parser):\r
304 assert Value is None\r
305 Value = []\r
306 RawArgs = Parser.rargs\r
307 while RawArgs:\r
308 Arg = RawArgs[0]\r
309 if (Arg[:2] == "--" and len(Arg) > 2) or \\r
310 (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"):\r
311 break\r
312 Value.append(Arg)\r
313 del RawArgs[0]\r
314 setattr(Parser.values, Option.dest, Value)\r
315\r
316## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style\r
317#\r
318# @param Guid The GUID string\r
319#\r
320# @retval string The GUID string in C structure style\r
321#\r
322def GuidStringToGuidStructureString(Guid):\r
323 GuidList = Guid.split('-')\r
324 Result = '{'\r
47fea6af 325 for Index in range(0, 3, 1):\r
f51461c8
LG
326 Result = Result + '0x' + GuidList[Index] + ', '\r
327 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
47fea6af
YZ
328 for Index in range(0, 12, 2):\r
329 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
f51461c8
LG
330 Result += '}}'\r
331 return Result\r
332\r
333## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
334#\r
335# @param GuidValue The GUID value in byte array\r
336#\r
337# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
338#\r
339def GuidStructureByteArrayToGuidString(GuidValue):\r
340 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
341 guidValueList = guidValueString.split(",")\r
342 if len(guidValueList) != 16:\r
343 return ''\r
344 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
345 try:\r
346 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
347 int(guidValueList[3], 16),\r
348 int(guidValueList[2], 16),\r
349 int(guidValueList[1], 16),\r
350 int(guidValueList[0], 16),\r
351 int(guidValueList[5], 16),\r
352 int(guidValueList[4], 16),\r
353 int(guidValueList[7], 16),\r
354 int(guidValueList[6], 16),\r
355 int(guidValueList[8], 16),\r
356 int(guidValueList[9], 16),\r
357 int(guidValueList[10], 16),\r
358 int(guidValueList[11], 16),\r
359 int(guidValueList[12], 16),\r
360 int(guidValueList[13], 16),\r
361 int(guidValueList[14], 16),\r
362 int(guidValueList[15], 16)\r
363 )\r
364 except:\r
365 return ''\r
366\r
367## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
368#\r
369# @param GuidValue The GUID value in C structure format\r
370#\r
371# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
372#\r
373def GuidStructureStringToGuidString(GuidValue):\r
374 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
375 guidValueList = guidValueString.split(",")\r
376 if len(guidValueList) != 11:\r
377 return ''\r
378 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
379 try:\r
380 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
381 int(guidValueList[0], 16),\r
382 int(guidValueList[1], 16),\r
383 int(guidValueList[2], 16),\r
384 int(guidValueList[3], 16),\r
385 int(guidValueList[4], 16),\r
386 int(guidValueList[5], 16),\r
387 int(guidValueList[6], 16),\r
388 int(guidValueList[7], 16),\r
389 int(guidValueList[8], 16),\r
390 int(guidValueList[9], 16),\r
391 int(guidValueList[10], 16)\r
392 )\r
393 except:\r
394 return ''\r
395\r
396## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx\r
397#\r
398# @param GuidValue The GUID value in C structure format\r
399#\r
400# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format\r
401#\r
402def GuidStructureStringToGuidValueName(GuidValue):\r
403 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
404 guidValueList = guidValueString.split(",")\r
405 if len(guidValueList) != 11:\r
406 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)\r
407 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (\r
408 int(guidValueList[0], 16),\r
409 int(guidValueList[1], 16),\r
410 int(guidValueList[2], 16),\r
411 int(guidValueList[3], 16),\r
412 int(guidValueList[4], 16),\r
413 int(guidValueList[5], 16),\r
414 int(guidValueList[6], 16),\r
415 int(guidValueList[7], 16),\r
416 int(guidValueList[8], 16),\r
417 int(guidValueList[9], 16),\r
418 int(guidValueList[10], 16)\r
419 )\r
420\r
421## Create directories\r
422#\r
423# @param Directory The directory name\r
424#\r
425def CreateDirectory(Directory):\r
426 if Directory == None or Directory.strip() == "":\r
427 return True\r
428 try:\r
429 if not os.access(Directory, os.F_OK):\r
430 os.makedirs(Directory)\r
431 except:\r
432 return False\r
433 return True\r
434\r
435## Remove directories, including files and sub-directories in it\r
436#\r
437# @param Directory The directory name\r
438#\r
439def RemoveDirectory(Directory, Recursively=False):\r
440 if Directory == None or Directory.strip() == "" or not os.path.exists(Directory):\r
441 return\r
442 if Recursively:\r
443 CurrentDirectory = os.getcwd()\r
444 os.chdir(Directory)\r
445 for File in os.listdir("."):\r
446 if os.path.isdir(File):\r
447 RemoveDirectory(File, Recursively)\r
448 else:\r
449 os.remove(File)\r
450 os.chdir(CurrentDirectory)\r
451 os.rmdir(Directory)\r
452\r
453## Check if given file is changed or not\r
454#\r
455# This method is used to check if a file is changed or not between two build\r
456# actions. It makes use a cache to store files timestamp.\r
457#\r
458# @param File The path of file\r
459#\r
460# @retval True If the given file is changed, doesn't exist, or can't be\r
461# found in timestamp cache\r
462# @retval False If the given file is changed\r
463#\r
464def IsChanged(File):\r
465 if not os.path.exists(File):\r
466 return True\r
467\r
468 FileState = os.stat(File)\r
469 TimeStamp = FileState[-2]\r
470\r
471 if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]:\r
472 FileChanged = False\r
473 else:\r
474 FileChanged = True\r
475 gFileTimeStampCache[File] = TimeStamp\r
476\r
477 return FileChanged\r
478\r
479## Store content in file\r
480#\r
481# This method is used to save file only when its content is changed. This is\r
482# quite useful for "make" system to decide what will be re-built and what won't.\r
483#\r
484# @param File The path of file\r
485# @param Content The new content of the file\r
486# @param IsBinaryFile The flag indicating if the file is binary file or not\r
487#\r
488# @retval True If the file content is changed and the file is renewed\r
489# @retval False If the file content is the same\r
490#\r
491def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
492 if not IsBinaryFile:\r
493 Content = Content.replace("\n", os.linesep)\r
494\r
495 if os.path.exists(File):\r
496 try:\r
497 if Content == open(File, "rb").read():\r
498 return False\r
499 except:\r
500 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
501\r
502 DirName = os.path.dirname(File)\r
503 if not CreateDirectory(DirName):\r
504 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
505 else:\r
506 if DirName == '':\r
507 DirName = os.getcwd()\r
508 if not os.access(DirName, os.W_OK):\r
509 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
510\r
511 try:\r
512 if GlobalData.gIsWindows:\r
513 try:\r
514 from PyUtility import SaveFileToDisk\r
515 if not SaveFileToDisk(File, Content):\r
516 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)\r
517 except:\r
518 Fd = open(File, "wb")\r
519 Fd.write(Content)\r
520 Fd.close()\r
521 else:\r
522 Fd = open(File, "wb")\r
523 Fd.write(Content)\r
524 Fd.close()\r
525 except IOError, X:\r
47fea6af 526 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)\r
f51461c8
LG
527\r
528 return True\r
529\r
530## Make a Python object persistent on file system\r
531#\r
532# @param Data The object to be stored in file\r
533# @param File The path of file to store the object\r
534#\r
535def DataDump(Data, File):\r
536 Fd = None\r
537 try:\r
538 Fd = open(File, 'wb')\r
539 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)\r
540 except:\r
541 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
542 finally:\r
543 if Fd != None:\r
544 Fd.close()\r
545\r
546## Restore a Python object from a file\r
547#\r
548# @param File The path of file stored the object\r
549#\r
550# @retval object A python object\r
551# @retval None If failure in file operation\r
552#\r
553def DataRestore(File):\r
554 Data = None\r
555 Fd = None\r
556 try:\r
557 Fd = open(File, 'rb')\r
558 Data = cPickle.load(Fd)\r
559 except Exception, e:\r
560 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))\r
561 Data = None\r
562 finally:\r
563 if Fd != None:\r
564 Fd.close()\r
565 return Data\r
566\r
567## Retrieve and cache the real path name in file system\r
568#\r
569# @param Root The root directory of path relative to\r
570#\r
571# @retval str The path string if the path exists\r
572# @retval None If path doesn't exist\r
573#\r
574class DirCache:\r
575 _CACHE_ = set()\r
576 _UPPER_CACHE_ = {}\r
577\r
578 def __init__(self, Root):\r
579 self._Root = Root\r
580 for F in os.listdir(Root):\r
581 self._CACHE_.add(F)\r
582 self._UPPER_CACHE_[F.upper()] = F\r
583\r
584 # =[] operator\r
585 def __getitem__(self, Path):\r
586 Path = Path[len(os.path.commonprefix([Path, self._Root])):]\r
587 if not Path:\r
588 return self._Root\r
589 if Path and Path[0] == os.path.sep:\r
590 Path = Path[1:]\r
591 if Path in self._CACHE_:\r
592 return os.path.join(self._Root, Path)\r
593 UpperPath = Path.upper()\r
594 if UpperPath in self._UPPER_CACHE_:\r
595 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
596\r
597 IndexList = []\r
598 LastSepIndex = -1\r
599 SepIndex = Path.find(os.path.sep)\r
600 while SepIndex > -1:\r
601 Parent = UpperPath[:SepIndex]\r
602 if Parent not in self._UPPER_CACHE_:\r
603 break\r
604 LastSepIndex = SepIndex\r
605 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)\r
606\r
607 if LastSepIndex == -1:\r
608 return None\r
609\r
610 Cwd = os.getcwd()\r
611 os.chdir(self._Root)\r
612 SepIndex = LastSepIndex\r
613 while SepIndex > -1:\r
614 Parent = Path[:SepIndex]\r
615 ParentKey = UpperPath[:SepIndex]\r
616 if ParentKey not in self._UPPER_CACHE_:\r
617 os.chdir(Cwd)\r
618 return None\r
619\r
620 if Parent in self._CACHE_:\r
621 ParentDir = Parent\r
622 else:\r
623 ParentDir = self._UPPER_CACHE_[ParentKey]\r
624 for F in os.listdir(ParentDir):\r
625 Dir = os.path.join(ParentDir, F)\r
626 self._CACHE_.add(Dir)\r
627 self._UPPER_CACHE_[Dir.upper()] = Dir\r
628\r
629 SepIndex = Path.find(os.path.sep, SepIndex + 1)\r
630\r
631 os.chdir(Cwd)\r
632 if Path in self._CACHE_:\r
633 return os.path.join(self._Root, Path)\r
634 elif UpperPath in self._UPPER_CACHE_:\r
635 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
636 return None\r
637\r
638## Get all files of a directory\r
639#\r
640# @param Root: Root dir\r
641# @param SkipList : The files need be skipped\r
642#\r
643# @retval A list of all files\r
644#\r
47fea6af 645def GetFiles(Root, SkipList=None, FullPath=True):\r
f51461c8
LG
646 OriPath = Root\r
647 FileList = []\r
648 for Root, Dirs, Files in os.walk(Root):\r
649 if SkipList:\r
650 for Item in SkipList:\r
651 if Item in Dirs:\r
652 Dirs.remove(Item)\r
653\r
654 for File in Files:\r
655 File = os.path.normpath(os.path.join(Root, File))\r
656 if not FullPath:\r
657 File = File[len(OriPath) + 1:]\r
658 FileList.append(File)\r
659\r
660 return FileList\r
661\r
662## Check if gvien file exists or not\r
663#\r
664# @param File File name or path to be checked\r
665# @param Dir The directory the file is relative to\r
666#\r
667# @retval True if file exists\r
668# @retval False if file doesn't exists\r
669#\r
670def ValidFile(File, Ext=None):\r
671 if Ext != None:\r
672 Dummy, FileExt = os.path.splitext(File)\r
673 if FileExt.lower() != Ext.lower():\r
674 return False\r
675 if not os.path.exists(File):\r
676 return False\r
677 return True\r
678\r
679def RealPath(File, Dir='', OverrideDir=''):\r
680 NewFile = os.path.normpath(os.path.join(Dir, File))\r
681 NewFile = GlobalData.gAllFiles[NewFile]\r
682 if not NewFile and OverrideDir:\r
683 NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
684 NewFile = GlobalData.gAllFiles[NewFile]\r
685 return NewFile\r
686\r
687def RealPath2(File, Dir='', OverrideDir=''):\r
9b9500a1 688 NewFile = None\r
f51461c8
LG
689 if OverrideDir:\r
690 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
691 if NewFile:\r
692 if OverrideDir[-1] == os.path.sep:\r
693 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
694 else:\r
47fea6af 695 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]\r
f51461c8
LG
696 if GlobalData.gAllFiles:\r
697 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]\r
9b9500a1 698 if not NewFile:\r
f51461c8 699 NewFile = os.path.normpath(os.path.join(Dir, File))\r
9b9500a1
YL
700 if not os.path.exists(NewFile):\r
701 return None, None\r
f51461c8
LG
702 if NewFile:\r
703 if Dir:\r
704 if Dir[-1] == os.path.sep:\r
705 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
706 else:\r
47fea6af 707 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
f51461c8
LG
708 else:\r
709 return NewFile, ''\r
710\r
711 return None, None\r
712\r
713## Check if gvien file exists or not\r
714#\r
715#\r
716def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):\r
717 NewFile = File\r
718 if Ext != None:\r
719 Dummy, FileExt = os.path.splitext(File)\r
720 if FileExt.lower() != Ext.lower():\r
721 return False, File\r
722\r
723 # Replace the Edk macros\r
724 if OverrideDir != '' and OverrideDir != None:\r
725 if OverrideDir.find('$(EFI_SOURCE)') > -1:\r
726 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)\r
727 if OverrideDir.find('$(EDK_SOURCE)') > -1:\r
728 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)\r
729\r
730 # Replace the default dir to current dir\r
731 if Dir == '.':\r
732 Dir = os.getcwd()\r
47fea6af 733 Dir = Dir[len(Workspace) + 1:]\r
f51461c8
LG
734\r
735 # First check if File has Edk definition itself\r
736 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:\r
737 NewFile = File.replace('$(EFI_SOURCE)', EfiSource)\r
738 NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)\r
739 NewFile = AllFiles[os.path.normpath(NewFile)]\r
740 if NewFile != None:\r
741 return True, NewFile\r
742\r
743 # Second check the path with override value\r
744 if OverrideDir != '' and OverrideDir != None:\r
745 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
746 if NewFile != None:\r
747 return True, NewFile\r
748\r
749 # Last check the path with normal definitions\r
750 File = os.path.join(Dir, File)\r
751 NewFile = AllFiles[os.path.normpath(File)]\r
752 if NewFile != None:\r
753 return True, NewFile\r
754\r
755 return False, File\r
756\r
757## Check if gvien file exists or not\r
758#\r
759#\r
760def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):\r
761 # Replace the Edk macros\r
762 if OverrideDir != '' and OverrideDir != None:\r
763 if OverrideDir.find('$(EFI_SOURCE)') > -1:\r
764 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)\r
765 if OverrideDir.find('$(EDK_SOURCE)') > -1:\r
766 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)\r
767\r
768 # Replace the default dir to current dir\r
769 # Dir is current module dir related to workspace\r
770 if Dir == '.':\r
771 Dir = os.getcwd()\r
47fea6af 772 Dir = Dir[len(Workspace) + 1:]\r
f51461c8
LG
773\r
774 NewFile = File\r
775 RelaPath = AllFiles[os.path.normpath(Dir)]\r
776 NewRelaPath = RelaPath\r
777\r
778 while(True):\r
779 # First check if File has Edk definition itself\r
780 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:\r
781 File = File.replace('$(EFI_SOURCE)', EfiSource)\r
782 File = File.replace('$(EDK_SOURCE)', EdkSource)\r
783 NewFile = AllFiles[os.path.normpath(File)]\r
784 if NewFile != None:\r
785 NewRelaPath = os.path.dirname(NewFile)\r
786 File = os.path.basename(NewFile)\r
787 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]\r
788 break\r
789\r
790 # Second check the path with override value\r
791 if OverrideDir != '' and OverrideDir != None:\r
792 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
793 if NewFile != None:\r
794 #NewRelaPath = os.path.dirname(NewFile)\r
795 NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]\r
796 break\r
797\r
798 # Last check the path with normal definitions\r
799 NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))]\r
800 if NewFile != None:\r
801 break\r
802\r
803 # No file found\r
804 break\r
805\r
806 return NewRelaPath, RelaPath, File\r
807\r
808\r
809def GetRelPath(Path1, Path2):\r
810 FileName = os.path.basename(Path2)\r
811 L1 = os.path.normpath(Path1).split(os.path.normpath('/'))\r
812 L2 = os.path.normpath(Path2).split(os.path.normpath('/'))\r
813 for Index in range(0, len(L1)):\r
814 if L1[Index] != L2[Index]:\r
815 FileName = '../' * (len(L1) - Index)\r
816 for Index2 in range(Index, len(L2)):\r
817 FileName = os.path.join(FileName, L2[Index2])\r
818 break\r
819 return os.path.normpath(FileName)\r
820\r
821\r
822## Get GUID value from given packages\r
823#\r
824# @param CName The CName of the GUID\r
825# @param PackageList List of packages looking-up in\r
c28d2e10 826# @param Inffile The driver file\r
f51461c8
LG
827#\r
828# @retval GuidValue if the CName is found in any given package\r
829# @retval None if the CName is not found in all given packages\r
830#\r
c28d2e10 831def GuidValue(CName, PackageList, Inffile = None):\r
f51461c8 832 for P in PackageList:\r
c28d2e10
YZ
833 GuidKeys = P.Guids.keys()\r
834 if Inffile and P._PrivateGuids:\r
835 if not Inffile.startswith(P.MetaFile.Dir):\r
836 GuidKeys = (dict.fromkeys(x for x in P.Guids if x not in P._PrivateGuids)).keys()\r
837 if CName in GuidKeys:\r
f51461c8
LG
838 return P.Guids[CName]\r
839 return None\r
840\r
841## Get Protocol value from given packages\r
842#\r
843# @param CName The CName of the GUID\r
844# @param PackageList List of packages looking-up in\r
c28d2e10 845# @param Inffile The driver file\r
f51461c8
LG
846#\r
847# @retval GuidValue if the CName is found in any given package\r
848# @retval None if the CName is not found in all given packages\r
849#\r
c28d2e10 850def ProtocolValue(CName, PackageList, Inffile = None):\r
f51461c8 851 for P in PackageList:\r
c28d2e10
YZ
852 ProtocolKeys = P.Protocols.keys()\r
853 if Inffile and P._PrivateProtocols:\r
854 if not Inffile.startswith(P.MetaFile.Dir):\r
855 ProtocolKeys = (dict.fromkeys(x for x in P.Protocols if x not in P._PrivateProtocols)).keys()\r
856 if CName in ProtocolKeys:\r
f51461c8
LG
857 return P.Protocols[CName]\r
858 return None\r
859\r
860## Get PPI value from given packages\r
861#\r
862# @param CName The CName of the GUID\r
863# @param PackageList List of packages looking-up in\r
c28d2e10 864# @param Inffile The driver file\r
f51461c8
LG
865#\r
866# @retval GuidValue if the CName is found in any given package\r
867# @retval None if the CName is not found in all given packages\r
868#\r
c28d2e10 869def PpiValue(CName, PackageList, Inffile = None):\r
f51461c8 870 for P in PackageList:\r
c28d2e10
YZ
871 PpiKeys = P.Ppis.keys()\r
872 if Inffile and P._PrivatePpis:\r
873 if not Inffile.startswith(P.MetaFile.Dir):\r
874 PpiKeys = (dict.fromkeys(x for x in P.Ppis if x not in P._PrivatePpis)).keys()\r
875 if CName in PpiKeys:\r
f51461c8
LG
876 return P.Ppis[CName]\r
877 return None\r
878\r
879## A string template class\r
880#\r
881# This class implements a template for string replacement. A string template\r
882# looks like following\r
883#\r
884# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
885#\r
886# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
887# length of "placeholder_name", which is a list passed through a dict. The\r
888# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
889# be not used and, in this case, the "placeholder_name" must not a list and it\r
890# will just be replaced once.\r
891#\r
892class TemplateString(object):\r
893 _REPEAT_START_FLAG = "BEGIN"\r
894 _REPEAT_END_FLAG = "END"\r
895\r
896 class Section(object):\r
897 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
898\r
899 def __init__(self, TemplateSection, PlaceHolderList):\r
900 self._Template = TemplateSection\r
901 self._PlaceHolderList = []\r
902\r
903 # Split the section into sub-sections according to the position of placeholders\r
904 if PlaceHolderList:\r
905 self._SubSectionList = []\r
906 SubSectionStart = 0\r
907 #\r
908 # The placeholders passed in must be in the format of\r
909 #\r
910 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
911 #\r
47fea6af 912 for PlaceHolder, Start, End in PlaceHolderList:\r
f51461c8
LG
913 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
914 self._SubSectionList.append(TemplateSection[Start:End])\r
915 self._PlaceHolderList.append(PlaceHolder)\r
916 SubSectionStart = End\r
917 if SubSectionStart < len(TemplateSection):\r
918 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
919 else:\r
920 self._SubSectionList = [TemplateSection]\r
921\r
922 def __str__(self):\r
923 return self._Template + " : " + str(self._PlaceHolderList)\r
924\r
925 def Instantiate(self, PlaceHolderValues):\r
926 RepeatTime = -1\r
927 RepeatPlaceHolders = {}\r
928 NonRepeatPlaceHolders = {}\r
929\r
930 for PlaceHolder in self._PlaceHolderList:\r
931 if PlaceHolder not in PlaceHolderValues:\r
932 continue\r
933 Value = PlaceHolderValues[PlaceHolder]\r
934 if type(Value) in self._LIST_TYPES:\r
935 if RepeatTime < 0:\r
936 RepeatTime = len(Value)\r
937 elif RepeatTime != len(Value):\r
938 EdkLogger.error(\r
939 "TemplateString",\r
940 PARAMETER_INVALID,\r
941 "${%s} has different repeat time from others!" % PlaceHolder,\r
942 ExtraData=str(self._Template)\r
943 )\r
944 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
945 else:\r
946 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
947\r
948 if NonRepeatPlaceHolders:\r
949 StringList = []\r
950 for S in self._SubSectionList:\r
951 if S not in NonRepeatPlaceHolders:\r
952 StringList.append(S)\r
953 else:\r
954 StringList.append(str(NonRepeatPlaceHolders[S]))\r
955 else:\r
956 StringList = self._SubSectionList\r
957\r
958 if RepeatPlaceHolders:\r
959 TempStringList = []\r
960 for Index in range(RepeatTime):\r
961 for S in StringList:\r
962 if S not in RepeatPlaceHolders:\r
963 TempStringList.append(S)\r
964 else:\r
965 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
966 StringList = TempStringList\r
967\r
968 return "".join(StringList)\r
969\r
970 ## Constructor\r
971 def __init__(self, Template=None):\r
972 self.String = ''\r
973 self.IsBinary = False\r
974 self._Template = Template\r
975 self._TemplateSectionList = self._Parse(Template)\r
976\r
977 ## str() operator\r
978 #\r
979 # @retval string The string replaced\r
980 #\r
981 def __str__(self):\r
982 return self.String\r
983\r
984 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
985 #\r
986 # @retval list A list of TemplateString.Section objects\r
987 #\r
988 def _Parse(self, Template):\r
989 SectionStart = 0\r
990 SearchFrom = 0\r
991 MatchEnd = 0\r
992 PlaceHolderList = []\r
993 TemplateSectionList = []\r
994 while Template:\r
995 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
996 if not MatchObj:\r
997 if MatchEnd <= len(Template):\r
998 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
999 TemplateSectionList.append(TemplateSection)\r
1000 break\r
1001\r
1002 MatchString = MatchObj.group(1)\r
1003 MatchStart = MatchObj.start()\r
1004 MatchEnd = MatchObj.end()\r
1005\r
1006 if MatchString == self._REPEAT_START_FLAG:\r
1007 if MatchStart > SectionStart:\r
1008 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
1009 TemplateSectionList.append(TemplateSection)\r
1010 SectionStart = MatchEnd\r
1011 PlaceHolderList = []\r
1012 elif MatchString == self._REPEAT_END_FLAG:\r
1013 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
1014 TemplateSectionList.append(TemplateSection)\r
1015 SectionStart = MatchEnd\r
1016 PlaceHolderList = []\r
1017 else:\r
1018 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
1019 SearchFrom = MatchEnd\r
1020 return TemplateSectionList\r
1021\r
1022 ## Replace the string template with dictionary of placeholders and append it to previous one\r
1023 #\r
1024 # @param AppendString The string template to append\r
1025 # @param Dictionary The placeholder dictionaries\r
1026 #\r
1027 def Append(self, AppendString, Dictionary=None):\r
1028 if Dictionary:\r
1029 SectionList = self._Parse(AppendString)\r
1030 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])\r
1031 else:\r
1032 self.String += AppendString\r
1033\r
1034 ## Replace the string template with dictionary of placeholders\r
1035 #\r
1036 # @param Dictionary The placeholder dictionaries\r
1037 #\r
1038 # @retval str The string replaced with placeholder values\r
1039 #\r
1040 def Replace(self, Dictionary=None):\r
1041 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])\r
1042\r
1043## Progress indicator class\r
1044#\r
1045# This class makes use of thread to print progress on console.\r
1046#\r
1047class Progressor:\r
1048 # for avoiding deadloop\r
1049 _StopFlag = None\r
1050 _ProgressThread = None\r
1051 _CheckInterval = 0.25\r
1052\r
1053 ## Constructor\r
1054 #\r
1055 # @param OpenMessage The string printed before progress charaters\r
1056 # @param CloseMessage The string printed after progress charaters\r
1057 # @param ProgressChar The charater used to indicate the progress\r
1058 # @param Interval The interval in seconds between two progress charaters\r
1059 #\r
1060 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
1061 self.PromptMessage = OpenMessage\r
1062 self.CodaMessage = CloseMessage\r
1063 self.ProgressChar = ProgressChar\r
1064 self.Interval = Interval\r
1065 if Progressor._StopFlag == None:\r
1066 Progressor._StopFlag = threading.Event()\r
1067\r
1068 ## Start to print progress charater\r
1069 #\r
1070 # @param OpenMessage The string printed before progress charaters\r
1071 #\r
1072 def Start(self, OpenMessage=None):\r
1073 if OpenMessage != None:\r
1074 self.PromptMessage = OpenMessage\r
1075 Progressor._StopFlag.clear()\r
1076 if Progressor._ProgressThread == None:\r
1077 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
1078 Progressor._ProgressThread.setDaemon(False)\r
1079 Progressor._ProgressThread.start()\r
1080\r
1081 ## Stop printing progress charater\r
1082 #\r
1083 # @param CloseMessage The string printed after progress charaters\r
1084 #\r
1085 def Stop(self, CloseMessage=None):\r
1086 OriginalCodaMessage = self.CodaMessage\r
1087 if CloseMessage != None:\r
1088 self.CodaMessage = CloseMessage\r
1089 self.Abort()\r
1090 self.CodaMessage = OriginalCodaMessage\r
1091\r
1092 ## Thread entry method\r
1093 def _ProgressThreadEntry(self):\r
1094 sys.stdout.write(self.PromptMessage + " ")\r
1095 sys.stdout.flush()\r
1096 TimeUp = 0.0\r
1097 while not Progressor._StopFlag.isSet():\r
1098 if TimeUp <= 0.0:\r
1099 sys.stdout.write(self.ProgressChar)\r
1100 sys.stdout.flush()\r
1101 TimeUp = self.Interval\r
1102 time.sleep(self._CheckInterval)\r
1103 TimeUp -= self._CheckInterval\r
1104 sys.stdout.write(" " + self.CodaMessage + "\n")\r
1105 sys.stdout.flush()\r
1106\r
1107 ## Abort the progress display\r
1108 @staticmethod\r
1109 def Abort():\r
1110 if Progressor._StopFlag != None:\r
1111 Progressor._StopFlag.set()\r
1112 if Progressor._ProgressThread != None:\r
1113 Progressor._ProgressThread.join()\r
1114 Progressor._ProgressThread = None\r
1115\r
1116## A dict which can access its keys and/or values orderly\r
1117#\r
1118# The class implements a new kind of dict which its keys or values can be\r
1119# accessed in the order they are added into the dict. It guarantees the order\r
1120# by making use of an internal list to keep a copy of keys.\r
1121#\r
1122class sdict(IterableUserDict):\r
1123 ## Constructor\r
1124 def __init__(self):\r
1125 IterableUserDict.__init__(self)\r
1126 self._key_list = []\r
1127\r
1128 ## [] operator\r
1129 def __setitem__(self, key, value):\r
1130 if key not in self._key_list:\r
1131 self._key_list.append(key)\r
1132 IterableUserDict.__setitem__(self, key, value)\r
1133\r
1134 ## del operator\r
1135 def __delitem__(self, key):\r
1136 self._key_list.remove(key)\r
1137 IterableUserDict.__delitem__(self, key)\r
1138\r
1139 ## used in "for k in dict" loop to ensure the correct order\r
1140 def __iter__(self):\r
1141 return self.iterkeys()\r
1142\r
1143 ## len() support\r
1144 def __len__(self):\r
1145 return len(self._key_list)\r
1146\r
1147 ## "in" test support\r
1148 def __contains__(self, key):\r
1149 return key in self._key_list\r
1150\r
1151 ## indexof support\r
1152 def index(self, key):\r
1153 return self._key_list.index(key)\r
1154\r
1155 ## insert support\r
1156 def insert(self, key, newkey, newvalue, order):\r
1157 index = self._key_list.index(key)\r
1158 if order == 'BEFORE':\r
1159 self._key_list.insert(index, newkey)\r
1160 IterableUserDict.__setitem__(self, newkey, newvalue)\r
1161 elif order == 'AFTER':\r
1162 self._key_list.insert(index + 1, newkey)\r
1163 IterableUserDict.__setitem__(self, newkey, newvalue)\r
1164\r
1165 ## append support\r
1166 def append(self, sdict):\r
1167 for key in sdict:\r
1168 if key not in self._key_list:\r
1169 self._key_list.append(key)\r
1170 IterableUserDict.__setitem__(self, key, sdict[key])\r
1171\r
1172 def has_key(self, key):\r
1173 return key in self._key_list\r
1174\r
1175 ## Empty the dict\r
1176 def clear(self):\r
1177 self._key_list = []\r
1178 IterableUserDict.clear(self)\r
1179\r
1180 ## Return a copy of keys\r
1181 def keys(self):\r
1182 keys = []\r
1183 for key in self._key_list:\r
1184 keys.append(key)\r
1185 return keys\r
1186\r
1187 ## Return a copy of values\r
1188 def values(self):\r
1189 values = []\r
1190 for key in self._key_list:\r
1191 values.append(self[key])\r
1192 return values\r
1193\r
1194 ## Return a copy of (key, value) list\r
1195 def items(self):\r
1196 items = []\r
1197 for key in self._key_list:\r
1198 items.append((key, self[key]))\r
1199 return items\r
1200\r
1201 ## Iteration support\r
1202 def iteritems(self):\r
1203 return iter(self.items())\r
1204\r
1205 ## Keys interation support\r
1206 def iterkeys(self):\r
1207 return iter(self.keys())\r
1208\r
1209 ## Values interation support\r
1210 def itervalues(self):\r
1211 return iter(self.values())\r
1212\r
1213 ## Return value related to a key, and remove the (key, value) from the dict\r
1214 def pop(self, key, *dv):\r
1215 value = None\r
1216 if key in self._key_list:\r
1217 value = self[key]\r
1218 self.__delitem__(key)\r
1219 elif len(dv) != 0 :\r
1220 value = kv[0]\r
1221 return value\r
1222\r
1223 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1224 def popitem(self):\r
1225 key = self._key_list[-1]\r
1226 value = self[key]\r
1227 self.__delitem__(key)\r
1228 return key, value\r
1229\r
1230 def update(self, dict=None, **kwargs):\r
1231 if dict != None:\r
1232 for k, v in dict.items():\r
1233 self[k] = v\r
1234 if len(kwargs):\r
1235 for k, v in kwargs.items():\r
1236 self[k] = v\r
1237\r
1238## Dictionary with restricted keys\r
1239#\r
1240class rdict(dict):\r
1241 ## Constructor\r
1242 def __init__(self, KeyList):\r
1243 for Key in KeyList:\r
1244 dict.__setitem__(self, Key, "")\r
1245\r
1246 ## []= operator\r
1247 def __setitem__(self, key, value):\r
1248 if key not in self:\r
1249 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,\r
1250 ExtraData=", ".join(dict.keys(self)))\r
1251 dict.__setitem__(self, key, value)\r
1252\r
1253 ## =[] operator\r
1254 def __getitem__(self, key):\r
1255 if key not in self:\r
1256 return ""\r
1257 return dict.__getitem__(self, key)\r
1258\r
1259 ## del operator\r
1260 def __delitem__(self, key):\r
1261 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")\r
1262\r
1263 ## Empty the dict\r
1264 def clear(self):\r
1265 for Key in self:\r
1266 self.__setitem__(Key, "")\r
1267\r
1268 ## Return value related to a key, and remove the (key, value) from the dict\r
1269 def pop(self, key, *dv):\r
1270 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")\r
1271\r
1272 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1273 def popitem(self):\r
1274 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")\r
1275\r
1276## Dictionary using prioritized list as key\r
1277#\r
1278class tdict:\r
1279 _ListType = type([])\r
1280 _TupleType = type(())\r
1281 _Wildcard = 'COMMON'\r
1282 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']\r
1283\r
1284 def __init__(self, _Single_=False, _Level_=2):\r
1285 self._Level_ = _Level_\r
1286 self.data = {}\r
1287 self._Single_ = _Single_\r
1288\r
1289 # =[] operator\r
1290 def __getitem__(self, key):\r
1291 KeyType = type(key)\r
1292 RestKeys = None\r
1293 if KeyType == self._ListType or KeyType == self._TupleType:\r
1294 FirstKey = key[0]\r
1295 if len(key) > 1:\r
1296 RestKeys = key[1:]\r
1297 elif self._Level_ > 1:\r
47fea6af 1298 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1299 else:\r
1300 FirstKey = key\r
1301 if self._Level_ > 1:\r
47fea6af 1302 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1303\r
1304 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:\r
1305 FirstKey = self._Wildcard\r
1306\r
1307 if self._Single_:\r
1308 return self._GetSingleValue(FirstKey, RestKeys)\r
1309 else:\r
1310 return self._GetAllValues(FirstKey, RestKeys)\r
1311\r
1312 def _GetSingleValue(self, FirstKey, RestKeys):\r
1313 Value = None\r
1314 #print "%s-%s" % (FirstKey, self._Level_) ,\r
1315 if self._Level_ > 1:\r
1316 if FirstKey == self._Wildcard:\r
1317 if FirstKey in self.data:\r
1318 Value = self.data[FirstKey][RestKeys]\r
1319 if Value == None:\r
1320 for Key in self.data:\r
1321 Value = self.data[Key][RestKeys]\r
1322 if Value != None: break\r
1323 else:\r
1324 if FirstKey in self.data:\r
1325 Value = self.data[FirstKey][RestKeys]\r
1326 if Value == None and self._Wildcard in self.data:\r
1327 #print "Value=None"\r
1328 Value = self.data[self._Wildcard][RestKeys]\r
1329 else:\r
1330 if FirstKey == self._Wildcard:\r
1331 if FirstKey in self.data:\r
1332 Value = self.data[FirstKey]\r
1333 if Value == None:\r
1334 for Key in self.data:\r
1335 Value = self.data[Key]\r
1336 if Value != None: break\r
1337 else:\r
1338 if FirstKey in self.data:\r
1339 Value = self.data[FirstKey]\r
1340 elif self._Wildcard in self.data:\r
1341 Value = self.data[self._Wildcard]\r
1342 return Value\r
1343\r
1344 def _GetAllValues(self, FirstKey, RestKeys):\r
1345 Value = []\r
1346 if self._Level_ > 1:\r
1347 if FirstKey == self._Wildcard:\r
1348 for Key in self.data:\r
1349 Value += self.data[Key][RestKeys]\r
1350 else:\r
1351 if FirstKey in self.data:\r
1352 Value += self.data[FirstKey][RestKeys]\r
1353 if self._Wildcard in self.data:\r
1354 Value += self.data[self._Wildcard][RestKeys]\r
1355 else:\r
1356 if FirstKey == self._Wildcard:\r
1357 for Key in self.data:\r
1358 Value.append(self.data[Key])\r
1359 else:\r
1360 if FirstKey in self.data:\r
1361 Value.append(self.data[FirstKey])\r
1362 if self._Wildcard in self.data:\r
1363 Value.append(self.data[self._Wildcard])\r
1364 return Value\r
1365\r
1366 ## []= operator\r
1367 def __setitem__(self, key, value):\r
1368 KeyType = type(key)\r
1369 RestKeys = None\r
1370 if KeyType == self._ListType or KeyType == self._TupleType:\r
1371 FirstKey = key[0]\r
1372 if len(key) > 1:\r
1373 RestKeys = key[1:]\r
1374 else:\r
47fea6af 1375 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1376 else:\r
1377 FirstKey = key\r
1378 if self._Level_ > 1:\r
47fea6af 1379 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1380\r
1381 if FirstKey in self._ValidWildcardList:\r
1382 FirstKey = self._Wildcard\r
1383\r
1384 if FirstKey not in self.data and self._Level_ > 0:\r
1385 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
1386\r
1387 if self._Level_ > 1:\r
1388 self.data[FirstKey][RestKeys] = value\r
1389 else:\r
1390 self.data[FirstKey] = value\r
1391\r
1392 def SetGreedyMode(self):\r
1393 self._Single_ = False\r
1394 if self._Level_ > 1:\r
1395 for Key in self.data:\r
1396 self.data[Key].SetGreedyMode()\r
1397\r
1398 def SetSingleMode(self):\r
1399 self._Single_ = True\r
1400 if self._Level_ > 1:\r
1401 for Key in self.data:\r
1402 self.data[Key].SetSingleMode()\r
1403\r
1404 def GetKeys(self, KeyIndex=0):\r
1405 assert KeyIndex >= 0\r
1406 if KeyIndex == 0:\r
1407 return set(self.data.keys())\r
1408 else:\r
1409 keys = set()\r
1410 for Key in self.data:\r
1411 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
1412 return keys\r
1413\r
1414## Boolean chain list\r
1415#\r
1416class Blist(UserList):\r
1417 def __init__(self, initlist=None):\r
1418 UserList.__init__(self, initlist)\r
1419 def __setitem__(self, i, item):\r
1420 if item not in [True, False]:\r
1421 if item == 0:\r
1422 item = False\r
1423 else:\r
1424 item = True\r
1425 self.data[i] = item\r
1426 def _GetResult(self):\r
1427 Value = True\r
1428 for item in self.data:\r
1429 Value &= item\r
1430 return Value\r
1431 Result = property(_GetResult)\r
1432\r
1433def ParseConsoleLog(Filename):\r
1434 Opr = open(os.path.normpath(Filename), 'r')\r
1435 Opw = open(os.path.normpath(Filename + '.New'), 'w+')\r
1436 for Line in Opr.readlines():\r
1437 if Line.find('.efi') > -1:\r
1438 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()\r
1439 Opw.write('%s\n' % Line)\r
1440\r
1441 Opr.close()\r
1442 Opw.close()\r
1443\r
8565b582
YZ
1444def IsFieldValueAnArray (Value):\r
1445 Value = Value.strip()\r
1446 if Value.startswith('GUID') and Value.endswith(')'):\r
1447 return True\r
1448 if Value.startswith('L"') and Value.endswith('"') and len(list(Value[2:-1])) > 1:\r
1449 return True\r
1450 if Value[0] == '"' and Value[-1] == '"' and len(list(Value[1:-1])) > 1:\r
1451 return True\r
1452 if Value[0] == '{' and Value[-1] == '}':\r
1453 return True\r
1454 if Value.startswith("L'") and Value.endswith("'") and len(list(Value[2:-1])) > 1:\r
1455 return True\r
1456 if Value[0] == "'" and Value[-1] == "'" and len(list(Value[1:-1])) > 1:\r
1457 return True\r
1458 return False\r
1459\r
67e11e4d 1460def AnalyzePcdExpression(Setting):\r
f51461c8 1461 Setting = Setting.strip()\r
ea927d2f
FY
1462 # There might be escaped quote in a string: \", \\\" , \', \\\'\r
1463 Data = Setting\r
f51461c8
LG
1464 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
1465 NewStr = ''\r
ea927d2f
FY
1466 InSingleQuoteStr = False\r
1467 InDoubleQuoteStr = False\r
f51461c8 1468 Pair = 0\r
ea927d2f
FY
1469 for Index, ch in enumerate(Data):\r
1470 if ch == '"' and not InSingleQuoteStr:\r
1471 if Data[Index - 1] != '\\':\r
1472 InDoubleQuoteStr = not InDoubleQuoteStr\r
1473 elif ch == "'" and not InDoubleQuoteStr:\r
1474 if Data[Index - 1] != '\\':\r
1475 InSingleQuoteStr = not InSingleQuoteStr\r
1476 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1477 Pair += 1\r
ea927d2f 1478 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1479 Pair -= 1\r
47fea6af 1480\r
ea927d2f 1481 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:\r
f51461c8
LG
1482 NewStr += '-'\r
1483 else:\r
1484 NewStr += ch\r
1485 FieldList = []\r
1486 StartPos = 0\r
1487 while True:\r
1488 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
1489 if Pos < 0:\r
1490 FieldList.append(Setting[StartPos:].strip())\r
1491 break\r
1492 FieldList.append(Setting[StartPos:Pos].strip())\r
1493 StartPos = Pos + 1\r
1494\r
67e11e4d
YZ
1495 return FieldList\r
1496\r
726c501c 1497def ParseDevPathValue (Value):\r
7dbc50bd
YZ
1498 DevPathList = [ "Path","HardwarePath","Pci","PcCard","MemoryMapped","VenHw","Ctrl","BMC","AcpiPath","Acpi","PciRoot",\r
1499 "PcieRoot","Floppy","Keyboard","Serial","ParallelPort","AcpiEx","AcpiExp","AcpiAdr","Msg","Ata","Scsi",\r
1500 "Fibre","FibreEx","I1394","USB","I2O","Infiniband","VenMsg","VenPcAnsi","VenVt100","VenVt100Plus",\r
1501 "VenUtf8","UartFlowCtrl","SAS","SasEx","NVMe","UFS","SD","eMMC","DebugPort","MAC","IPv4","IPv6","Uart",\r
1502 "UsbClass","UsbAudio","UsbCDCControl","UsbHID","UsbImage","UsbPrinter","UsbMassStorage","UsbHub",\r
1503 "UsbCDCData","UsbSmartCard","UsbVideo","UsbDiagnostic","UsbWireless","UsbDeviceFirmwareUpdate",\r
1504 "UsbIrdaBridge","UsbTestAndMeasurement","UsbWwid","Unit","iSCSI","Vlan","Uri","Bluetooth","Wi-Fi",\r
1505 "MediaPath","HD","CDROM","VenMedia","Media","Fv","FvFile","Offset","RamDisk","VirtualDisk","VirtualCD",\r
1506 "PersistentVirtualDisk","PersistentVirtualCD","BbsPath","BBS","Sata" ]\r
1507 if '\\' in Value:\r
1508 Value.replace('\\', '/').replace(' ', '')\r
1509 for Item in Value.split('/'):\r
1510 Key = Item.strip().split('(')[0]\r
1511 if Key not in DevPathList:\r
1512 pass\r
1513\r
1514 Cmd = 'DevicePath ' + '"' + Value + '"'\r
1515 try:\r
1516 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
1517 out, err = p.communicate()\r
1518 except Exception, X:\r
1519 raise BadExpression("DevicePath: %s" % (str(X)) )\r
1520 finally:\r
1521 subprocess._cleanup()\r
1522 p.stdout.close()\r
1523 p.stderr.close()\r
1524 if err:\r
1525 raise BadExpression("DevicePath: %s" % str(err))\r
1526 Size = len(out.split())\r
1527 out = ','.join(out.split())\r
1528 return '{' + out + '}', Size\r
726c501c 1529\r
ae7b6df8 1530def ParseFieldValue (Value):\r
726c501c
YZ
1531 if type(Value) == type(0):\r
1532 return Value, (Value.bit_length() + 7) / 8\r
1533 if type(Value) <> type(''):\r
1534 raise BadExpression('Type %s is %s' %(Value, type(Value)))\r
1535 Value = Value.strip()\r
1536 if Value.startswith('UINT8') and Value.endswith(')'):\r
1537 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1538 if Size > 1:\r
1539 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1540 return Value, 1\r
1541 if Value.startswith('UINT16') and Value.endswith(')'):\r
1542 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1543 if Size > 2:\r
1544 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1545 return Value, 2\r
1546 if Value.startswith('UINT32') and Value.endswith(')'):\r
1547 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1548 if Size > 4:\r
1549 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1550 return Value, 4\r
1551 if Value.startswith('UINT64') and Value.endswith(')'):\r
1552 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1553 if Size > 8:\r
1554 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))\r
1555 return Value, 8\r
1556 if Value.startswith('GUID') and Value.endswith(')'):\r
1557 Value = Value.split('(', 1)[1][:-1].strip()\r
1558 if Value[0] == '{' and Value[-1] == '}':\r
4344a788
FY
1559 TmpValue = GuidStructureStringToGuidString(Value)\r
1560 if len(TmpValue) == 0:\r
1561 raise BadExpression("Invalid GUID value string %s" % Value)\r
1562 Value = TmpValue\r
726c501c
YZ
1563 if Value[0] == '"' and Value[-1] == '"':\r
1564 Value = Value[1:-1]\r
1565 try:\r
1566 Value = "'" + uuid.UUID(Value).get_bytes_le() + "'"\r
1567 except ValueError, Message:\r
1568 raise BadExpression('%s' % Message)\r
1569 Value, Size = ParseFieldValue(Value)\r
1570 return Value, 16\r
1571 if Value.startswith('L"') and Value.endswith('"'):\r
1572 # Unicode String\r
4faf1322
FY
1573 # translate escape character\r
1574 Value = Value[1:]\r
1575 try:\r
1576 Value = eval(Value)\r
1577 except:\r
1578 Value = Value[1:-1]\r
1579 List = list(Value)\r
726c501c
YZ
1580 List.reverse()\r
1581 Value = 0\r
1582 for Char in List:\r
1583 Value = (Value << 16) | ord(Char)\r
1584 return Value, (len(List) + 1) * 2\r
1585 if Value.startswith('"') and Value.endswith('"'):\r
1586 # ASCII String\r
4faf1322
FY
1587 # translate escape character\r
1588 try:\r
1589 Value = eval(Value)\r
1590 except:\r
1591 Value = Value[1:-1]\r
1592 List = list(Value)\r
726c501c
YZ
1593 List.reverse()\r
1594 Value = 0\r
1595 for Char in List:\r
1596 Value = (Value << 8) | ord(Char)\r
1597 return Value, len(List) + 1\r
1598 if Value.startswith("L'") and Value.endswith("'"):\r
1599 # Unicode Character Constant\r
4faf1322
FY
1600 # translate escape character\r
1601 Value = Value[1:]\r
1602 try:\r
1603 Value = eval(Value)\r
1604 except:\r
1605 Value = Value[1:-1]\r
1606 List = list(Value)\r
0e6b8673
FY
1607 if len(List) == 0:\r
1608 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1609 List.reverse()\r
1610 Value = 0\r
1611 for Char in List:\r
1612 Value = (Value << 16) | ord(Char)\r
1613 return Value, len(List) * 2\r
1614 if Value.startswith("'") and Value.endswith("'"):\r
1615 # Character constant\r
4faf1322
FY
1616 # translate escape character\r
1617 try:\r
1618 Value = eval(Value)\r
1619 except:\r
1620 Value = Value[1:-1]\r
1621 List = list(Value)\r
0e6b8673
FY
1622 if len(List) == 0:\r
1623 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1624 List.reverse()\r
1625 Value = 0\r
1626 for Char in List:\r
1627 Value = (Value << 8) | ord(Char)\r
1628 return Value, len(List)\r
1629 if Value.startswith('{') and Value.endswith('}'):\r
1630 # Byte array\r
1631 Value = Value[1:-1]\r
1632 List = [Item.strip() for Item in Value.split(',')]\r
1633 List.reverse()\r
1634 Value = 0\r
1635 RetSize = 0\r
1636 for Item in List:\r
1637 ItemValue, Size = ParseFieldValue(Item)\r
1638 RetSize += Size\r
1639 for I in range(Size):\r
1640 Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)\r
1641 return Value, RetSize\r
1642 if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):\r
8ad5f10a
FY
1643 Value = Value.replace("DEVICE_PATH(", '').rstrip(')')\r
1644 Value = Value.strip().strip('"')\r
726c501c
YZ
1645 return ParseDevPathValue(Value)\r
1646 if Value.lower().startswith('0x'):\r
1647 Value = int(Value, 16)\r
1648 if Value == 0:\r
1649 return 0, 1\r
1650 return Value, (Value.bit_length() + 7) / 8\r
1651 if Value[0].isdigit():\r
1652 Value = int(Value, 10)\r
1653 if Value == 0:\r
1654 return 0, 1\r
1655 return Value, (Value.bit_length() + 7) / 8\r
1656 if Value.lower() == 'true':\r
1657 return 1, 1\r
1658 if Value.lower() == 'false':\r
1659 return 0, 1\r
ae7b6df8 1660 return Value, 1\r
ae7b6df8 1661\r
67e11e4d
YZ
1662## AnalyzeDscPcd\r
1663#\r
1664# Analyze DSC PCD value, since there is no data type info in DSC\r
1665# This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database\r
1666# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
1667# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]\r
1668# 3. Dynamic default:\r
1669# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1670# TokenSpace.PcdCName|PcdValue\r
1671# 4. Dynamic VPD:\r
1672# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1673# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1674# 5. Dynamic HII:\r
1675# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]\r
1676# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1677# there might have "|" operator, also in string value.\r
1678#\r
1679# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1680# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1681# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1682# @retval:\r
1683# ValueList: A List contain fields described above\r
1684# IsValid: True if conforming EBNF, otherwise False\r
1685# Index: The index where PcdValue is in ValueList\r
1686#\r
1687def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1688 FieldList = AnalyzePcdExpression(Setting)\r
1689\r
f51461c8
LG
1690 IsValid = True\r
1691 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):\r
1692 Value = FieldList[0]\r
1693 Size = ''\r
1694 if len(FieldList) > 1:\r
ae7b6df8 1695 if FieldList[1].upper().startswith("0X") or FieldList[1].isdigit():\r
f51461c8 1696 Size = FieldList[1]\r
ae7b6df8
LG
1697 else:\r
1698 DataType = FieldList[1]\r
1699\r
f51461c8
LG
1700 if len(FieldList) > 2:\r
1701 Size = FieldList[2]\r
ae7b6df8 1702 if DataType == "":\r
f51461c8 1703 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1704 else:\r
1705 IsValid = (len(FieldList) <= 3)\r
1706# Value, Size = ParseFieldValue(Value)\r
520365de
B
1707 if Size:\r
1708 try:\r
1709 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1710 except:\r
1711 IsValid = False\r
1712 Size = -1\r
ae7b6df8 1713 return [str(Value), '', str(Size)], IsValid, 0\r
f51461c8
LG
1714 elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):\r
1715 Value = FieldList[0]\r
1716 Size = Type = ''\r
1717 if len(FieldList) > 1:\r
1718 Type = FieldList[1]\r
1719 else:\r
1720 Type = DataType\r
1721 if len(FieldList) > 2:\r
1722 Size = FieldList[2]\r
1723 else:\r
1724 if Type == 'VOID*':\r
1725 if Value.startswith("L"):\r
1726 Size = str((len(Value)- 3 + 1) * 2)\r
1727 elif Value.startswith("{"):\r
1728 Size = str(len(Value.split(",")))\r
1729 else:\r
1730 Size = str(len(Value) -2 + 1 )\r
ae7b6df8 1731 if DataType == "":\r
f51461c8 1732 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1733 else:\r
1734 IsValid = (len(FieldList) <= 3)\r
520365de
B
1735\r
1736 if Size:\r
1737 try:\r
1738 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1739 except:\r
1740 IsValid = False\r
1741 Size = -1\r
1742 return [Value, Type, str(Size)], IsValid, 0\r
f51461c8
LG
1743 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1744 VpdOffset = FieldList[0]\r
1745 Value = Size = ''\r
1746 if not DataType == 'VOID*':\r
1747 if len(FieldList) > 1:\r
1748 Value = FieldList[1]\r
1749 else:\r
1750 if len(FieldList) > 1:\r
1751 Size = FieldList[1]\r
1752 if len(FieldList) > 2:\r
1753 Value = FieldList[2]\r
ae7b6df8
LG
1754 if DataType == "":\r
1755 IsValid = (len(FieldList) <= 1)\r
f51461c8 1756 else:\r
ae7b6df8 1757 IsValid = (len(FieldList) <= 3)\r
520365de
B
1758 if Size:\r
1759 try:\r
1760 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1761 except:\r
1762 IsValid = False\r
1763 Size = -1\r
1764 return [VpdOffset, str(Size), Value], IsValid, 2\r
f51461c8
LG
1765 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
1766 HiiString = FieldList[0]\r
82a6a960 1767 Guid = Offset = Value = Attribute = ''\r
f51461c8
LG
1768 if len(FieldList) > 1:\r
1769 Guid = FieldList[1]\r
1770 if len(FieldList) > 2:\r
1771 Offset = FieldList[2]\r
1772 if len(FieldList) > 3:\r
1773 Value = FieldList[3]\r
82a6a960
BF
1774 if len(FieldList) > 4:\r
1775 Attribute = FieldList[4]\r
1776 IsValid = (3 <= len(FieldList) <= 5)\r
1777 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
f51461c8
LG
1778 return [], False, 0\r
1779\r
1780## AnalyzePcdData\r
1781#\r
1782# Analyze the pcd Value, Datum type and TokenNumber.\r
1783# Used to avoid split issue while the value string contain "|" character\r
1784#\r
1785# @param[in] Setting: A String contain value/datum type/token number information;\r
1786# \r
1787# @retval ValueList: A List contain value, datum type and toke number. \r
1788#\r
47fea6af
YZ
1789def AnalyzePcdData(Setting):\r
1790 ValueList = ['', '', '']\r
1791\r
1792 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
f51461c8
LG
1793 PtrValue = ValueRe.findall(Setting)\r
1794 \r
1795 ValueUpdateFlag = False\r
1796 \r
1797 if len(PtrValue) >= 1:\r
1798 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1799 ValueUpdateFlag = True\r
f51461c8
LG
1800\r
1801 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1802 ValueList[0:len(TokenList)] = TokenList\r
1803 \r
1804 if ValueUpdateFlag:\r
1805 ValueList[0] = PtrValue[0]\r
1806 \r
1807 return ValueList \r
1808 \r
1809## AnalyzeHiiPcdData\r
1810#\r
1811# Analyze the pcd Value, variable name, variable Guid and variable offset.\r
1812# Used to avoid split issue while the value string contain "|" character\r
1813#\r
1814# @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;\r
1815# \r
1816# @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue. \r
1817#\r
1818def AnalyzeHiiPcdData(Setting):\r
1819 ValueList = ['', '', '', '']\r
1820\r
1821 TokenList = GetSplitValueList(Setting)\r
1822 ValueList[0:len(TokenList)] = TokenList\r
1823\r
1824 return ValueList\r
1825\r
1826## AnalyzeVpdPcdData\r
1827#\r
1828# Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.\r
1829# Used to avoid split issue while the value string contain "|" character\r
1830#\r
1831# @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;\r
1832# \r
1833# @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue. \r
1834#\r
47fea6af
YZ
1835def AnalyzeVpdPcdData(Setting):\r
1836 ValueList = ['', '', '']\r
1837\r
1838 ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')\r
f51461c8
LG
1839 PtrValue = ValueRe.findall(Setting)\r
1840 \r
1841 ValueUpdateFlag = False\r
1842 \r
1843 if len(PtrValue) >= 1:\r
1844 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1845 ValueUpdateFlag = True\r
f51461c8
LG
1846\r
1847 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1848 ValueList[0:len(TokenList)] = TokenList\r
1849 \r
1850 if ValueUpdateFlag:\r
1851 ValueList[2] = PtrValue[0]\r
1852 \r
1853 return ValueList \r
1854\r
1855## check format of PCD value against its the datum type\r
1856#\r
1857# For PCD value setting\r
1858#\r
1859def CheckPcdDatum(Type, Value):\r
1860 if Type == "VOID*":\r
47fea6af 1861 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
f51461c8 1862 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
d5988a8a 1863 or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))\r
f51461c8
LG
1864 ):\r
1865 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
d5988a8a 1866 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)\r
f51461c8
LG
1867 elif ValueRe.match(Value):\r
1868 # Check the chars in UnicodeString or CString is printable\r
1869 if Value.startswith("L"):\r
1870 Value = Value[2:-1]\r
1871 else:\r
1872 Value = Value[1:-1]\r
1873 Printset = set(string.printable)\r
1874 Printset.remove(TAB_PRINTCHAR_VT)\r
1875 Printset.add(TAB_PRINTCHAR_BS)\r
1876 Printset.add(TAB_PRINTCHAR_NUL)\r
1877 if not set(Value).issubset(Printset):\r
1878 PrintList = list(Printset)\r
1879 PrintList.sort()\r
1880 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1881 elif Type == 'BOOLEAN':\r
1882 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1883 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1884 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1885 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
1886 try:\r
1887 Value = long(Value, 0)\r
1888 except:\r
1889 return False, "Invalid value [%s] of type [%s];"\\r
1890 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
1891 else:\r
ae7b6df8 1892 return True, "StructurePcd"\r
f51461c8
LG
1893\r
1894 return True, ""\r
1895\r
1896## Split command line option string to list\r
1897#\r
1898# subprocess.Popen needs the args to be a sequence. Otherwise there's problem\r
1899# in non-windows platform to launch command\r
1900#\r
1901def SplitOption(OptionString):\r
1902 OptionList = []\r
1903 LastChar = " "\r
1904 OptionStart = 0\r
1905 QuotationMark = ""\r
1906 for Index in range(0, len(OptionString)):\r
1907 CurrentChar = OptionString[Index]\r
1908 if CurrentChar in ['"', "'"]:\r
1909 if QuotationMark == CurrentChar:\r
1910 QuotationMark = ""\r
1911 elif QuotationMark == "":\r
1912 QuotationMark = CurrentChar\r
1913 continue\r
1914 elif QuotationMark:\r
1915 continue\r
1916\r
1917 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:\r
1918 if Index > OptionStart:\r
47fea6af 1919 OptionList.append(OptionString[OptionStart:Index - 1])\r
f51461c8
LG
1920 OptionStart = Index\r
1921 LastChar = CurrentChar\r
1922 OptionList.append(OptionString[OptionStart:])\r
1923 return OptionList\r
1924\r
1925def CommonPath(PathList):\r
1926 P1 = min(PathList).split(os.path.sep)\r
1927 P2 = max(PathList).split(os.path.sep)\r
1928 for Index in xrange(min(len(P1), len(P2))):\r
1929 if P1[Index] != P2[Index]:\r
1930 return os.path.sep.join(P1[:Index])\r
1931 return os.path.sep.join(P1)\r
1932\r
97fa0ee9
YL
1933#\r
1934# Convert string to C format array\r
1935#\r
1936def ConvertStringToByteArray(Value):\r
1937 Value = Value.strip()\r
1938 if not Value:\r
1939 return None\r
1940 if Value[0] == '{':\r
1941 if not Value.endswith('}'):\r
1942 return None\r
1943 Value = Value.replace(' ', '').replace('{', '').replace('}', '')\r
1944 ValFields = Value.split(',')\r
1945 try:\r
1946 for Index in range(len(ValFields)):\r
1947 ValFields[Index] = str(int(ValFields[Index], 0))\r
1948 except ValueError:\r
1949 return None\r
1950 Value = '{' + ','.join(ValFields) + '}'\r
1951 return Value\r
1952\r
1953 Unicode = False\r
1954 if Value.startswith('L"'):\r
1955 if not Value.endswith('"'):\r
1956 return None\r
1957 Value = Value[1:]\r
1958 Unicode = True\r
1959 elif not Value.startswith('"') or not Value.endswith('"'):\r
1960 return None\r
1961\r
1962 Value = eval(Value) # translate escape character\r
1963 NewValue = '{'\r
1964 for Index in range(0,len(Value)):\r
1965 if Unicode:\r
1966 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','\r
1967 else:\r
1968 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','\r
1969 Value = NewValue + '0}'\r
1970 return Value\r
1971\r
f51461c8
LG
1972class PathClass(object):\r
1973 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1974 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1975 self.Arch = Arch\r
1976 self.File = str(File)\r
1977 if os.path.isabs(self.File):\r
1978 self.Root = ''\r
1979 self.AlterRoot = ''\r
1980 else:\r
1981 self.Root = str(Root)\r
1982 self.AlterRoot = str(AlterRoot)\r
1983\r
1984 # Remove any '.' and '..' in path\r
1985 if self.Root:\r
05cc51ad 1986 self.Root = mws.getWs(self.Root, self.File)\r
f51461c8
LG
1987 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1988 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1989 # eliminate the side-effect of 'C:'\r
1990 if self.Root[-1] == ':':\r
1991 self.Root += os.path.sep\r
1992 # file path should not start with path separator\r
1993 if self.Root[-1] == os.path.sep:\r
1994 self.File = self.Path[len(self.Root):]\r
1995 else:\r
47fea6af 1996 self.File = self.Path[len(self.Root) + 1:]\r
f51461c8
LG
1997 else:\r
1998 self.Path = os.path.normpath(self.File)\r
1999\r
2000 self.SubDir, self.Name = os.path.split(self.File)\r
2001 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
2002\r
2003 if self.Root:\r
2004 if self.SubDir:\r
2005 self.Dir = os.path.join(self.Root, self.SubDir)\r
2006 else:\r
2007 self.Dir = self.Root\r
2008 else:\r
2009 self.Dir = self.SubDir\r
2010\r
2011 if IsBinary:\r
2012 self.Type = Type\r
2013 else:\r
2014 self.Type = self.Ext.lower()\r
2015\r
2016 self.IsBinary = IsBinary\r
2017 self.Target = Target\r
2018 self.TagName = TagName\r
2019 self.ToolCode = ToolCode\r
2020 self.ToolChainFamily = ToolChainFamily\r
2021\r
2022 self._Key = None\r
2023\r
2024 ## Convert the object of this class to a string\r
2025 #\r
2026 # Convert member Path of the class to a string\r
2027 #\r
2028 # @retval string Formatted String\r
2029 #\r
2030 def __str__(self):\r
2031 return self.Path\r
2032\r
2033 ## Override __eq__ function\r
2034 #\r
2035 # Check whether PathClass are the same\r
2036 #\r
2037 # @retval False The two PathClass are different\r
2038 # @retval True The two PathClass are the same\r
2039 #\r
2040 def __eq__(self, Other):\r
2041 if type(Other) == type(self):\r
2042 return self.Path == Other.Path\r
2043 else:\r
2044 return self.Path == str(Other)\r
2045\r
2046 ## Override __cmp__ function\r
2047 #\r
2048 # Customize the comparsion operation of two PathClass\r
2049 #\r
2050 # @retval 0 The two PathClass are different\r
2051 # @retval -1 The first PathClass is less than the second PathClass\r
2052 # @retval 1 The first PathClass is Bigger than the second PathClass\r
2053 def __cmp__(self, Other):\r
2054 if type(Other) == type(self):\r
2055 OtherKey = Other.Path\r
2056 else:\r
2057 OtherKey = str(Other)\r
2058 \r
2059 SelfKey = self.Path\r
2060 if SelfKey == OtherKey:\r
2061 return 0\r
2062 elif SelfKey > OtherKey:\r
2063 return 1\r
2064 else:\r
2065 return -1\r
2066\r
2067 ## Override __hash__ function\r
2068 #\r
2069 # Use Path as key in hash table\r
2070 #\r
2071 # @retval string Key for hash table\r
2072 #\r
2073 def __hash__(self):\r
2074 return hash(self.Path)\r
2075\r
2076 def _GetFileKey(self):\r
2077 if self._Key == None:\r
2078 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target\r
2079 return self._Key\r
2080\r
2081 def _GetTimeStamp(self):\r
2082 return os.stat(self.Path)[8]\r
2083\r
2084 def Validate(self, Type='', CaseSensitive=True):\r
2085 if GlobalData.gCaseInsensitive:\r
2086 CaseSensitive = False\r
2087 if Type and Type.lower() != self.Type:\r
2088 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
2089\r
2090 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
2091 if not RealRoot and not RealFile:\r
2092 RealFile = self.File\r
2093 if self.AlterRoot:\r
2094 RealFile = os.path.join(self.AlterRoot, self.File)\r
2095 elif self.Root:\r
2096 RealFile = os.path.join(self.Root, self.File)\r
05cc51ad
LY
2097 if len (mws.getPkgPath()) == 0:\r
2098 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
2099 else:\r
2100 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
f51461c8
LG
2101\r
2102 ErrorCode = 0\r
2103 ErrorInfo = ''\r
2104 if RealRoot != self.Root or RealFile != self.File:\r
2105 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
2106 ErrorCode = FILE_CASE_MISMATCH\r
2107 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
2108\r
2109 self.SubDir, self.Name = os.path.split(RealFile)\r
2110 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
2111 if self.SubDir:\r
2112 self.Dir = os.path.join(RealRoot, self.SubDir)\r
2113 else:\r
2114 self.Dir = RealRoot\r
2115 self.File = RealFile\r
2116 self.Root = RealRoot\r
2117 self.Path = os.path.join(RealRoot, RealFile)\r
2118 return ErrorCode, ErrorInfo\r
2119\r
2120 Key = property(_GetFileKey)\r
2121 TimeStamp = property(_GetTimeStamp)\r
2122\r
2123## Parse PE image to get the required PE informaion.\r
2124#\r
2125class PeImageClass():\r
2126 ## Constructor\r
2127 #\r
2128 # @param File FilePath of PeImage\r
2129 #\r
2130 def __init__(self, PeFile):\r
2131 self.FileName = PeFile\r
2132 self.IsValid = False\r
2133 self.Size = 0\r
2134 self.EntryPoint = 0\r
2135 self.SectionAlignment = 0\r
2136 self.SectionHeaderList = []\r
2137 self.ErrorInfo = ''\r
2138 try:\r
2139 PeObject = open(PeFile, 'rb')\r
2140 except:\r
2141 self.ErrorInfo = self.FileName + ' can not be found\n'\r
2142 return\r
2143 # Read DOS header\r
2144 ByteArray = array.array('B')\r
2145 ByteArray.fromfile(PeObject, 0x3E)\r
2146 ByteList = ByteArray.tolist()\r
2147 # DOS signature should be 'MZ'\r
2148 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
2149 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
2150 return\r
2151\r
2152 # Read 4 byte PE Signature\r
2153 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
2154 PeObject.seek(PeOffset)\r
2155 ByteArray = array.array('B')\r
2156 ByteArray.fromfile(PeObject, 4)\r
2157 # PE signature should be 'PE\0\0'\r
2158 if ByteArray.tostring() != 'PE\0\0':\r
2159 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
2160 return\r
2161\r
2162 # Read PE file header\r
2163 ByteArray = array.array('B')\r
2164 ByteArray.fromfile(PeObject, 0x14)\r
2165 ByteList = ByteArray.tolist()\r
2166 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
2167 if SecNumber == 0:\r
2168 self.ErrorInfo = self.FileName + ' has no section header'\r
2169 return\r
2170\r
2171 # Read PE optional header\r
2172 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
2173 ByteArray = array.array('B')\r
2174 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
2175 ByteList = ByteArray.tolist()\r
2176 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
2177 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
2178 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
2179\r
2180 # Read each Section Header\r
2181 for Index in range(SecNumber):\r
2182 ByteArray = array.array('B')\r
2183 ByteArray.fromfile(PeObject, 0x28)\r
2184 ByteList = ByteArray.tolist()\r
2185 SecName = self._ByteListToStr(ByteList[0:8])\r
2186 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
2187 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
2188 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
2189 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
2190 self.IsValid = True\r
2191 PeObject.close()\r
2192\r
2193 def _ByteListToStr(self, ByteList):\r
2194 String = ''\r
2195 for index in range(len(ByteList)):\r
2196 if ByteList[index] == 0: \r
2197 break\r
2198 String += chr(ByteList[index])\r
2199 return String\r
2200\r
2201 def _ByteListToInt(self, ByteList):\r
2202 Value = 0\r
2203 for index in range(len(ByteList) - 1, -1, -1):\r
2204 Value = (Value << 8) | int(ByteList[index])\r
2205 return Value\r
2206\r
8518bf0b
LG
2207class DefaultStore():\r
2208 def __init__(self,DefaultStores ):\r
2209\r
2210 self.DefaultStores = DefaultStores\r
2211 def DefaultStoreID(self,DefaultStoreName):\r
2212 for key,value in self.DefaultStores.items():\r
2213 if value == DefaultStoreName:\r
2214 return key\r
2215 return None\r
2216 def GetDefaultDefault(self):\r
2217 if not self.DefaultStores or "0" in self.DefaultStores:\r
2218 return "0",TAB_DEFAULT_STORES_DEFAULT\r
2219 else:\r
2220 minvalue = min([int(value_str) for value_str in self.DefaultStores.keys()])\r
2221 return (str(minvalue), self.DefaultStores[str(minvalue)])\r
2222 def GetMin(self,DefaultSIdList):\r
2223 if not DefaultSIdList:\r
2224 return "STANDARD"\r
2b8a6c44
LG
2225 storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}\r
2226 if not storeidset:\r
2227 return ""\r
2228 minid = min(storeidset )\r
8518bf0b
LG
2229 for sid,name in self.DefaultStores.values():\r
2230 if sid == minid:\r
2231 return name\r
f51461c8
LG
2232class SkuClass():\r
2233 \r
2234 DEFAULT = 0\r
2235 SINGLE = 1\r
2236 MULTIPLE =2\r
2237 \r
8518bf0b
LG
2238 def __init__(self,SkuIdentifier='', SkuIds=None):\r
2239 if SkuIds is None:\r
2240 SkuIds = {}\r
c05c2c05
LG
2241\r
2242 for SkuName in SkuIds:\r
2243 SkuId = SkuIds[SkuName][0]\r
2244 skuid_num = int(SkuId,16) if SkuId.upper().startswith("0X") else int(SkuId)\r
e4ff28c3 2245 if skuid_num > 0xFFFFFFFFFFFFFFFF:\r
c05c2c05 2246 EdkLogger.error("build", PARAMETER_INVALID,\r
e4ff28c3
LG
2247 ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"\r
2248 % (SkuName, SkuId))\r
f51461c8
LG
2249 \r
2250 self.AvailableSkuIds = sdict()\r
2251 self.SkuIdSet = []\r
1ae469b9 2252 self.SkuIdNumberSet = []\r
8518bf0b
LG
2253 self.SkuData = SkuIds\r
2254 self.__SkuInherit = {}\r
c05c2c05 2255 self.__SkuIdentifier = SkuIdentifier\r
f51461c8
LG
2256 if SkuIdentifier == '' or SkuIdentifier is None:\r
2257 self.SkuIdSet = ['DEFAULT']\r
1ae469b9 2258 self.SkuIdNumberSet = ['0U']\r
f51461c8
LG
2259 elif SkuIdentifier == 'ALL':\r
2260 self.SkuIdSet = SkuIds.keys()\r
8518bf0b 2261 self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]\r
f51461c8
LG
2262 else:\r
2263 r = SkuIdentifier.split('|') \r
8518bf0b 2264 self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]\r
1ae469b9
BF
2265 k = None\r
2266 try: \r
8518bf0b 2267 self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]\r
1ae469b9
BF
2268 except Exception:\r
2269 EdkLogger.error("build", PARAMETER_INVALID,\r
2270 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 2271 % (k, " | ".join(SkuIds.keys())))\r
f51461c8
LG
2272 for each in self.SkuIdSet:\r
2273 if each in SkuIds:\r
8518bf0b 2274 self.AvailableSkuIds[each] = SkuIds[each][0]\r
f51461c8
LG
2275 else:\r
2276 EdkLogger.error("build", PARAMETER_INVALID,\r
2277 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 2278 % (each, " | ".join(SkuIds.keys())))\r
8518bf0b
LG
2279 if self.SkuUsageType != self.SINGLE:\r
2280 self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})\r
e651d06c
LG
2281 if self.SkuIdSet:\r
2282 GlobalData.gSkuids = (self.SkuIdSet)\r
2283 if 'COMMON' in GlobalData.gSkuids:\r
2284 GlobalData.gSkuids.remove('COMMON')\r
8aaa8f7b
YZ
2285 if self.SkuUsageType == self.SINGLE:\r
2286 if len(GlobalData.gSkuids) != 1:\r
2287 if 'DEFAULT' in GlobalData.gSkuids:\r
2288 GlobalData.gSkuids.remove('DEFAULT')\r
e651d06c
LG
2289 if GlobalData.gSkuids:\r
2290 GlobalData.gSkuids.sort()\r
2291\r
8518bf0b
LG
2292 def GetNextSkuId(self, skuname):\r
2293 if not self.__SkuInherit:\r
2294 self.__SkuInherit = {}\r
2295 for item in self.SkuData.values():\r
2296 self.__SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"\r
2297 return self.__SkuInherit.get(skuname,"DEFAULT")\r
c05c2c05
LG
2298\r
2299 def GetSkuChain(self,sku):\r
09c80b07
B
2300 if sku == "DEFAULT":\r
2301 return ["DEFAULT"]\r
c05c2c05
LG
2302 skulist = [sku]\r
2303 nextsku = sku\r
2304 while 1:\r
2305 nextsku = self.GetNextSkuId(nextsku)\r
2306 skulist.append(nextsku)\r
2307 if nextsku == "DEFAULT":\r
2308 break\r
2309 skulist.reverse()\r
2310 return skulist\r
2311 def SkuOverrideOrder(self):\r
2312 skuorderset = []\r
2313 for skuname in self.SkuIdSet:\r
2314 skuorderset.append(self.GetSkuChain(skuname))\r
f51461c8 2315 \r
c05c2c05
LG
2316 skuorder = []\r
2317 for index in range(max([len(item) for item in skuorderset])):\r
2318 for subset in skuorderset:\r
2319 if index > len(subset)-1:\r
2320 continue\r
2321 if subset[index] in skuorder:\r
2322 continue\r
2323 skuorder.append(subset[index])\r
2324\r
2325 return skuorder\r
2326\r
f51461c8
LG
2327 def __SkuUsageType(self): \r
2328 \r
c05c2c05
LG
2329 if self.__SkuIdentifier.upper() == "ALL":\r
2330 return SkuClass.MULTIPLE\r
2331\r
f51461c8
LG
2332 if len(self.SkuIdSet) == 1:\r
2333 if self.SkuIdSet[0] == 'DEFAULT':\r
2334 return SkuClass.DEFAULT\r
2335 else:\r
2336 return SkuClass.SINGLE\r
c05c2c05
LG
2337 elif len(self.SkuIdSet) == 2:\r
2338 if 'DEFAULT' in self.SkuIdSet:\r
2339 return SkuClass.SINGLE\r
2340 else:\r
2341 return SkuClass.MULTIPLE\r
f51461c8
LG
2342 else:\r
2343 return SkuClass.MULTIPLE\r
8518bf0b 2344 def DumpSkuIdArrary(self):\r
f51461c8 2345\r
8518bf0b
LG
2346 ArrayStrList = []\r
2347 if self.SkuUsageType == SkuClass.SINGLE:\r
2348 ArrayStr = "{0x0}"\r
2349 else:\r
2350 for skuname in self.AvailableSkuIds:\r
2351 if skuname == "COMMON":\r
2352 continue\r
2353 while skuname != "DEFAULT":\r
2354 ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))\r
2355 skuname = self.GetNextSkuId(skuname)\r
2356 ArrayStrList.append("0x0")\r
2357 ArrayStr = "{" + ",".join(ArrayStrList) + "}"\r
2358 return ArrayStr\r
f51461c8
LG
2359 def __GetAvailableSkuIds(self):\r
2360 return self.AvailableSkuIds\r
2361 \r
2362 def __GetSystemSkuID(self):\r
2363 if self.__SkuUsageType() == SkuClass.SINGLE:\r
c05c2c05
LG
2364 if len(self.SkuIdSet) == 1:\r
2365 return self.SkuIdSet[0]\r
2366 else:\r
2367 return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]\r
f51461c8
LG
2368 else:\r
2369 return 'DEFAULT'\r
1ae469b9
BF
2370 def __GetAvailableSkuIdNumber(self):\r
2371 return self.SkuIdNumberSet\r
f51461c8
LG
2372 SystemSkuId = property(__GetSystemSkuID)\r
2373 AvailableSkuIdSet = property(__GetAvailableSkuIds)\r
2374 SkuUsageType = property(__SkuUsageType)\r
1ae469b9 2375 AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)\r
a3251d84
YL
2376\r
2377#\r
2378# Pack a registry format GUID\r
2379#\r
2380def PackRegistryFormatGuid(Guid):\r
2381 Guid = Guid.split('-')\r
2382 return pack('=LHHBBBBBBBB',\r
2383 int(Guid[0], 16),\r
2384 int(Guid[1], 16),\r
2385 int(Guid[2], 16),\r
2386 int(Guid[3][-4:-2], 16),\r
2387 int(Guid[3][-2:], 16),\r
2388 int(Guid[4][-12:-10], 16),\r
2389 int(Guid[4][-10:-8], 16),\r
2390 int(Guid[4][-8:-6], 16),\r
2391 int(Guid[4][-6:-4], 16),\r
2392 int(Guid[4][-4:-2], 16),\r
2393 int(Guid[4][-2:], 16)\r
2394 )\r
2395\r
34952f49
LG
2396## Get the integer value from string like "14U" or integer like 2\r
2397#\r
2398# @param Input The object that may be either a integer value or a string\r
2399#\r
2400# @retval Value The integer value that the input represents\r
2401#\r
2402def GetIntegerValue(Input):\r
2403 if type(Input) in (int, long):\r
2404 return Input\r
2405 String = Input\r
2406 if String.endswith("U"):\r
2407 String = String[:-1]\r
2408 if String.endswith("ULL"):\r
2409 String = String[:-3]\r
2410 if String.endswith("LL"):\r
2411 String = String[:-2]\r
2412\r
2413 if String.startswith("0x") or String.startswith("0X"):\r
2414 return int(String, 16)\r
2415 elif String == '':\r
2416 return 0\r
2417 else:\r
2418 return int(String)\r
db55dac7 2419\r
f51461c8
LG
2420##\r
2421#\r
2422# This acts like the main() function for the script, unless it is 'import'ed into another\r
2423# script.\r
2424#\r
2425if __name__ == '__main__':\r
2426 pass\r
2427\r