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