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