]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
BaseTools: Enhance tool to generate EFI_HII_IIBT_DUPLICATE image block
[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
c28d2e10 4# Copyright (c) 2007 - 2016, 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
c28d2e10 797# @param Inffile The driver file\r
f51461c8
LG
798#\r
799# @retval GuidValue if the CName is found in any given package\r
800# @retval None if the CName is not found in all given packages\r
801#\r
c28d2e10 802def GuidValue(CName, PackageList, Inffile = None):\r
f51461c8 803 for P in PackageList:\r
c28d2e10
YZ
804 GuidKeys = P.Guids.keys()\r
805 if Inffile and P._PrivateGuids:\r
806 if not Inffile.startswith(P.MetaFile.Dir):\r
807 GuidKeys = (dict.fromkeys(x for x in P.Guids if x not in P._PrivateGuids)).keys()\r
808 if CName in GuidKeys:\r
f51461c8
LG
809 return P.Guids[CName]\r
810 return None\r
811\r
812## Get Protocol value from given packages\r
813#\r
814# @param CName The CName of the GUID\r
815# @param PackageList List of packages looking-up in\r
c28d2e10 816# @param Inffile The driver file\r
f51461c8
LG
817#\r
818# @retval GuidValue if the CName is found in any given package\r
819# @retval None if the CName is not found in all given packages\r
820#\r
c28d2e10 821def ProtocolValue(CName, PackageList, Inffile = None):\r
f51461c8 822 for P in PackageList:\r
c28d2e10
YZ
823 ProtocolKeys = P.Protocols.keys()\r
824 if Inffile and P._PrivateProtocols:\r
825 if not Inffile.startswith(P.MetaFile.Dir):\r
826 ProtocolKeys = (dict.fromkeys(x for x in P.Protocols if x not in P._PrivateProtocols)).keys()\r
827 if CName in ProtocolKeys:\r
f51461c8
LG
828 return P.Protocols[CName]\r
829 return None\r
830\r
831## Get PPI value from given packages\r
832#\r
833# @param CName The CName of the GUID\r
834# @param PackageList List of packages looking-up in\r
c28d2e10 835# @param Inffile The driver file\r
f51461c8
LG
836#\r
837# @retval GuidValue if the CName is found in any given package\r
838# @retval None if the CName is not found in all given packages\r
839#\r
c28d2e10 840def PpiValue(CName, PackageList, Inffile = None):\r
f51461c8 841 for P in PackageList:\r
c28d2e10
YZ
842 PpiKeys = P.Ppis.keys()\r
843 if Inffile and P._PrivatePpis:\r
844 if not Inffile.startswith(P.MetaFile.Dir):\r
845 PpiKeys = (dict.fromkeys(x for x in P.Ppis if x not in P._PrivatePpis)).keys()\r
846 if CName in PpiKeys:\r
f51461c8
LG
847 return P.Ppis[CName]\r
848 return None\r
849\r
850## A string template class\r
851#\r
852# This class implements a template for string replacement. A string template\r
853# looks like following\r
854#\r
855# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
856#\r
857# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
858# length of "placeholder_name", which is a list passed through a dict. The\r
859# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
860# be not used and, in this case, the "placeholder_name" must not a list and it\r
861# will just be replaced once.\r
862#\r
863class TemplateString(object):\r
864 _REPEAT_START_FLAG = "BEGIN"\r
865 _REPEAT_END_FLAG = "END"\r
866\r
867 class Section(object):\r
868 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
869\r
870 def __init__(self, TemplateSection, PlaceHolderList):\r
871 self._Template = TemplateSection\r
872 self._PlaceHolderList = []\r
873\r
874 # Split the section into sub-sections according to the position of placeholders\r
875 if PlaceHolderList:\r
876 self._SubSectionList = []\r
877 SubSectionStart = 0\r
878 #\r
879 # The placeholders passed in must be in the format of\r
880 #\r
881 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
882 #\r
47fea6af 883 for PlaceHolder, Start, End in PlaceHolderList:\r
f51461c8
LG
884 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
885 self._SubSectionList.append(TemplateSection[Start:End])\r
886 self._PlaceHolderList.append(PlaceHolder)\r
887 SubSectionStart = End\r
888 if SubSectionStart < len(TemplateSection):\r
889 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
890 else:\r
891 self._SubSectionList = [TemplateSection]\r
892\r
893 def __str__(self):\r
894 return self._Template + " : " + str(self._PlaceHolderList)\r
895\r
896 def Instantiate(self, PlaceHolderValues):\r
897 RepeatTime = -1\r
898 RepeatPlaceHolders = {}\r
899 NonRepeatPlaceHolders = {}\r
900\r
901 for PlaceHolder in self._PlaceHolderList:\r
902 if PlaceHolder not in PlaceHolderValues:\r
903 continue\r
904 Value = PlaceHolderValues[PlaceHolder]\r
905 if type(Value) in self._LIST_TYPES:\r
906 if RepeatTime < 0:\r
907 RepeatTime = len(Value)\r
908 elif RepeatTime != len(Value):\r
909 EdkLogger.error(\r
910 "TemplateString",\r
911 PARAMETER_INVALID,\r
912 "${%s} has different repeat time from others!" % PlaceHolder,\r
913 ExtraData=str(self._Template)\r
914 )\r
915 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
916 else:\r
917 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
918\r
919 if NonRepeatPlaceHolders:\r
920 StringList = []\r
921 for S in self._SubSectionList:\r
922 if S not in NonRepeatPlaceHolders:\r
923 StringList.append(S)\r
924 else:\r
925 StringList.append(str(NonRepeatPlaceHolders[S]))\r
926 else:\r
927 StringList = self._SubSectionList\r
928\r
929 if RepeatPlaceHolders:\r
930 TempStringList = []\r
931 for Index in range(RepeatTime):\r
932 for S in StringList:\r
933 if S not in RepeatPlaceHolders:\r
934 TempStringList.append(S)\r
935 else:\r
936 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
937 StringList = TempStringList\r
938\r
939 return "".join(StringList)\r
940\r
941 ## Constructor\r
942 def __init__(self, Template=None):\r
943 self.String = ''\r
944 self.IsBinary = False\r
945 self._Template = Template\r
946 self._TemplateSectionList = self._Parse(Template)\r
947\r
948 ## str() operator\r
949 #\r
950 # @retval string The string replaced\r
951 #\r
952 def __str__(self):\r
953 return self.String\r
954\r
955 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
956 #\r
957 # @retval list A list of TemplateString.Section objects\r
958 #\r
959 def _Parse(self, Template):\r
960 SectionStart = 0\r
961 SearchFrom = 0\r
962 MatchEnd = 0\r
963 PlaceHolderList = []\r
964 TemplateSectionList = []\r
965 while Template:\r
966 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
967 if not MatchObj:\r
968 if MatchEnd <= len(Template):\r
969 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
970 TemplateSectionList.append(TemplateSection)\r
971 break\r
972\r
973 MatchString = MatchObj.group(1)\r
974 MatchStart = MatchObj.start()\r
975 MatchEnd = MatchObj.end()\r
976\r
977 if MatchString == self._REPEAT_START_FLAG:\r
978 if MatchStart > SectionStart:\r
979 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
980 TemplateSectionList.append(TemplateSection)\r
981 SectionStart = MatchEnd\r
982 PlaceHolderList = []\r
983 elif MatchString == self._REPEAT_END_FLAG:\r
984 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
985 TemplateSectionList.append(TemplateSection)\r
986 SectionStart = MatchEnd\r
987 PlaceHolderList = []\r
988 else:\r
989 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
990 SearchFrom = MatchEnd\r
991 return TemplateSectionList\r
992\r
993 ## Replace the string template with dictionary of placeholders and append it to previous one\r
994 #\r
995 # @param AppendString The string template to append\r
996 # @param Dictionary The placeholder dictionaries\r
997 #\r
998 def Append(self, AppendString, Dictionary=None):\r
999 if Dictionary:\r
1000 SectionList = self._Parse(AppendString)\r
1001 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])\r
1002 else:\r
1003 self.String += AppendString\r
1004\r
1005 ## Replace the string template with dictionary of placeholders\r
1006 #\r
1007 # @param Dictionary The placeholder dictionaries\r
1008 #\r
1009 # @retval str The string replaced with placeholder values\r
1010 #\r
1011 def Replace(self, Dictionary=None):\r
1012 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])\r
1013\r
1014## Progress indicator class\r
1015#\r
1016# This class makes use of thread to print progress on console.\r
1017#\r
1018class Progressor:\r
1019 # for avoiding deadloop\r
1020 _StopFlag = None\r
1021 _ProgressThread = None\r
1022 _CheckInterval = 0.25\r
1023\r
1024 ## Constructor\r
1025 #\r
1026 # @param OpenMessage The string printed before progress charaters\r
1027 # @param CloseMessage The string printed after progress charaters\r
1028 # @param ProgressChar The charater used to indicate the progress\r
1029 # @param Interval The interval in seconds between two progress charaters\r
1030 #\r
1031 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
1032 self.PromptMessage = OpenMessage\r
1033 self.CodaMessage = CloseMessage\r
1034 self.ProgressChar = ProgressChar\r
1035 self.Interval = Interval\r
1036 if Progressor._StopFlag == None:\r
1037 Progressor._StopFlag = threading.Event()\r
1038\r
1039 ## Start to print progress charater\r
1040 #\r
1041 # @param OpenMessage The string printed before progress charaters\r
1042 #\r
1043 def Start(self, OpenMessage=None):\r
1044 if OpenMessage != None:\r
1045 self.PromptMessage = OpenMessage\r
1046 Progressor._StopFlag.clear()\r
1047 if Progressor._ProgressThread == None:\r
1048 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
1049 Progressor._ProgressThread.setDaemon(False)\r
1050 Progressor._ProgressThread.start()\r
1051\r
1052 ## Stop printing progress charater\r
1053 #\r
1054 # @param CloseMessage The string printed after progress charaters\r
1055 #\r
1056 def Stop(self, CloseMessage=None):\r
1057 OriginalCodaMessage = self.CodaMessage\r
1058 if CloseMessage != None:\r
1059 self.CodaMessage = CloseMessage\r
1060 self.Abort()\r
1061 self.CodaMessage = OriginalCodaMessage\r
1062\r
1063 ## Thread entry method\r
1064 def _ProgressThreadEntry(self):\r
1065 sys.stdout.write(self.PromptMessage + " ")\r
1066 sys.stdout.flush()\r
1067 TimeUp = 0.0\r
1068 while not Progressor._StopFlag.isSet():\r
1069 if TimeUp <= 0.0:\r
1070 sys.stdout.write(self.ProgressChar)\r
1071 sys.stdout.flush()\r
1072 TimeUp = self.Interval\r
1073 time.sleep(self._CheckInterval)\r
1074 TimeUp -= self._CheckInterval\r
1075 sys.stdout.write(" " + self.CodaMessage + "\n")\r
1076 sys.stdout.flush()\r
1077\r
1078 ## Abort the progress display\r
1079 @staticmethod\r
1080 def Abort():\r
1081 if Progressor._StopFlag != None:\r
1082 Progressor._StopFlag.set()\r
1083 if Progressor._ProgressThread != None:\r
1084 Progressor._ProgressThread.join()\r
1085 Progressor._ProgressThread = None\r
1086\r
1087## A dict which can access its keys and/or values orderly\r
1088#\r
1089# The class implements a new kind of dict which its keys or values can be\r
1090# accessed in the order they are added into the dict. It guarantees the order\r
1091# by making use of an internal list to keep a copy of keys.\r
1092#\r
1093class sdict(IterableUserDict):\r
1094 ## Constructor\r
1095 def __init__(self):\r
1096 IterableUserDict.__init__(self)\r
1097 self._key_list = []\r
1098\r
1099 ## [] operator\r
1100 def __setitem__(self, key, value):\r
1101 if key not in self._key_list:\r
1102 self._key_list.append(key)\r
1103 IterableUserDict.__setitem__(self, key, value)\r
1104\r
1105 ## del operator\r
1106 def __delitem__(self, key):\r
1107 self._key_list.remove(key)\r
1108 IterableUserDict.__delitem__(self, key)\r
1109\r
1110 ## used in "for k in dict" loop to ensure the correct order\r
1111 def __iter__(self):\r
1112 return self.iterkeys()\r
1113\r
1114 ## len() support\r
1115 def __len__(self):\r
1116 return len(self._key_list)\r
1117\r
1118 ## "in" test support\r
1119 def __contains__(self, key):\r
1120 return key in self._key_list\r
1121\r
1122 ## indexof support\r
1123 def index(self, key):\r
1124 return self._key_list.index(key)\r
1125\r
1126 ## insert support\r
1127 def insert(self, key, newkey, newvalue, order):\r
1128 index = self._key_list.index(key)\r
1129 if order == 'BEFORE':\r
1130 self._key_list.insert(index, newkey)\r
1131 IterableUserDict.__setitem__(self, newkey, newvalue)\r
1132 elif order == 'AFTER':\r
1133 self._key_list.insert(index + 1, newkey)\r
1134 IterableUserDict.__setitem__(self, newkey, newvalue)\r
1135\r
1136 ## append support\r
1137 def append(self, sdict):\r
1138 for key in sdict:\r
1139 if key not in self._key_list:\r
1140 self._key_list.append(key)\r
1141 IterableUserDict.__setitem__(self, key, sdict[key])\r
1142\r
1143 def has_key(self, key):\r
1144 return key in self._key_list\r
1145\r
1146 ## Empty the dict\r
1147 def clear(self):\r
1148 self._key_list = []\r
1149 IterableUserDict.clear(self)\r
1150\r
1151 ## Return a copy of keys\r
1152 def keys(self):\r
1153 keys = []\r
1154 for key in self._key_list:\r
1155 keys.append(key)\r
1156 return keys\r
1157\r
1158 ## Return a copy of values\r
1159 def values(self):\r
1160 values = []\r
1161 for key in self._key_list:\r
1162 values.append(self[key])\r
1163 return values\r
1164\r
1165 ## Return a copy of (key, value) list\r
1166 def items(self):\r
1167 items = []\r
1168 for key in self._key_list:\r
1169 items.append((key, self[key]))\r
1170 return items\r
1171\r
1172 ## Iteration support\r
1173 def iteritems(self):\r
1174 return iter(self.items())\r
1175\r
1176 ## Keys interation support\r
1177 def iterkeys(self):\r
1178 return iter(self.keys())\r
1179\r
1180 ## Values interation support\r
1181 def itervalues(self):\r
1182 return iter(self.values())\r
1183\r
1184 ## Return value related to a key, and remove the (key, value) from the dict\r
1185 def pop(self, key, *dv):\r
1186 value = None\r
1187 if key in self._key_list:\r
1188 value = self[key]\r
1189 self.__delitem__(key)\r
1190 elif len(dv) != 0 :\r
1191 value = kv[0]\r
1192 return value\r
1193\r
1194 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1195 def popitem(self):\r
1196 key = self._key_list[-1]\r
1197 value = self[key]\r
1198 self.__delitem__(key)\r
1199 return key, value\r
1200\r
1201 def update(self, dict=None, **kwargs):\r
1202 if dict != None:\r
1203 for k, v in dict.items():\r
1204 self[k] = v\r
1205 if len(kwargs):\r
1206 for k, v in kwargs.items():\r
1207 self[k] = v\r
1208\r
1209## Dictionary with restricted keys\r
1210#\r
1211class rdict(dict):\r
1212 ## Constructor\r
1213 def __init__(self, KeyList):\r
1214 for Key in KeyList:\r
1215 dict.__setitem__(self, Key, "")\r
1216\r
1217 ## []= operator\r
1218 def __setitem__(self, key, value):\r
1219 if key not in self:\r
1220 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,\r
1221 ExtraData=", ".join(dict.keys(self)))\r
1222 dict.__setitem__(self, key, value)\r
1223\r
1224 ## =[] operator\r
1225 def __getitem__(self, key):\r
1226 if key not in self:\r
1227 return ""\r
1228 return dict.__getitem__(self, key)\r
1229\r
1230 ## del operator\r
1231 def __delitem__(self, key):\r
1232 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")\r
1233\r
1234 ## Empty the dict\r
1235 def clear(self):\r
1236 for Key in self:\r
1237 self.__setitem__(Key, "")\r
1238\r
1239 ## Return value related to a key, and remove the (key, value) from the dict\r
1240 def pop(self, key, *dv):\r
1241 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")\r
1242\r
1243 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1244 def popitem(self):\r
1245 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")\r
1246\r
1247## Dictionary using prioritized list as key\r
1248#\r
1249class tdict:\r
1250 _ListType = type([])\r
1251 _TupleType = type(())\r
1252 _Wildcard = 'COMMON'\r
1253 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']\r
1254\r
1255 def __init__(self, _Single_=False, _Level_=2):\r
1256 self._Level_ = _Level_\r
1257 self.data = {}\r
1258 self._Single_ = _Single_\r
1259\r
1260 # =[] operator\r
1261 def __getitem__(self, key):\r
1262 KeyType = type(key)\r
1263 RestKeys = None\r
1264 if KeyType == self._ListType or KeyType == self._TupleType:\r
1265 FirstKey = key[0]\r
1266 if len(key) > 1:\r
1267 RestKeys = key[1:]\r
1268 elif self._Level_ > 1:\r
47fea6af 1269 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1270 else:\r
1271 FirstKey = key\r
1272 if self._Level_ > 1:\r
47fea6af 1273 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1274\r
1275 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:\r
1276 FirstKey = self._Wildcard\r
1277\r
1278 if self._Single_:\r
1279 return self._GetSingleValue(FirstKey, RestKeys)\r
1280 else:\r
1281 return self._GetAllValues(FirstKey, RestKeys)\r
1282\r
1283 def _GetSingleValue(self, FirstKey, RestKeys):\r
1284 Value = None\r
1285 #print "%s-%s" % (FirstKey, self._Level_) ,\r
1286 if self._Level_ > 1:\r
1287 if FirstKey == self._Wildcard:\r
1288 if FirstKey in self.data:\r
1289 Value = self.data[FirstKey][RestKeys]\r
1290 if Value == None:\r
1291 for Key in self.data:\r
1292 Value = self.data[Key][RestKeys]\r
1293 if Value != None: break\r
1294 else:\r
1295 if FirstKey in self.data:\r
1296 Value = self.data[FirstKey][RestKeys]\r
1297 if Value == None and self._Wildcard in self.data:\r
1298 #print "Value=None"\r
1299 Value = self.data[self._Wildcard][RestKeys]\r
1300 else:\r
1301 if FirstKey == self._Wildcard:\r
1302 if FirstKey in self.data:\r
1303 Value = self.data[FirstKey]\r
1304 if Value == None:\r
1305 for Key in self.data:\r
1306 Value = self.data[Key]\r
1307 if Value != None: break\r
1308 else:\r
1309 if FirstKey in self.data:\r
1310 Value = self.data[FirstKey]\r
1311 elif self._Wildcard in self.data:\r
1312 Value = self.data[self._Wildcard]\r
1313 return Value\r
1314\r
1315 def _GetAllValues(self, FirstKey, RestKeys):\r
1316 Value = []\r
1317 if self._Level_ > 1:\r
1318 if FirstKey == self._Wildcard:\r
1319 for Key in self.data:\r
1320 Value += self.data[Key][RestKeys]\r
1321 else:\r
1322 if FirstKey in self.data:\r
1323 Value += self.data[FirstKey][RestKeys]\r
1324 if self._Wildcard in self.data:\r
1325 Value += self.data[self._Wildcard][RestKeys]\r
1326 else:\r
1327 if FirstKey == self._Wildcard:\r
1328 for Key in self.data:\r
1329 Value.append(self.data[Key])\r
1330 else:\r
1331 if FirstKey in self.data:\r
1332 Value.append(self.data[FirstKey])\r
1333 if self._Wildcard in self.data:\r
1334 Value.append(self.data[self._Wildcard])\r
1335 return Value\r
1336\r
1337 ## []= operator\r
1338 def __setitem__(self, key, value):\r
1339 KeyType = type(key)\r
1340 RestKeys = None\r
1341 if KeyType == self._ListType or KeyType == self._TupleType:\r
1342 FirstKey = key[0]\r
1343 if len(key) > 1:\r
1344 RestKeys = key[1:]\r
1345 else:\r
47fea6af 1346 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1347 else:\r
1348 FirstKey = key\r
1349 if self._Level_ > 1:\r
47fea6af 1350 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1351\r
1352 if FirstKey in self._ValidWildcardList:\r
1353 FirstKey = self._Wildcard\r
1354\r
1355 if FirstKey not in self.data and self._Level_ > 0:\r
1356 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
1357\r
1358 if self._Level_ > 1:\r
1359 self.data[FirstKey][RestKeys] = value\r
1360 else:\r
1361 self.data[FirstKey] = value\r
1362\r
1363 def SetGreedyMode(self):\r
1364 self._Single_ = False\r
1365 if self._Level_ > 1:\r
1366 for Key in self.data:\r
1367 self.data[Key].SetGreedyMode()\r
1368\r
1369 def SetSingleMode(self):\r
1370 self._Single_ = True\r
1371 if self._Level_ > 1:\r
1372 for Key in self.data:\r
1373 self.data[Key].SetSingleMode()\r
1374\r
1375 def GetKeys(self, KeyIndex=0):\r
1376 assert KeyIndex >= 0\r
1377 if KeyIndex == 0:\r
1378 return set(self.data.keys())\r
1379 else:\r
1380 keys = set()\r
1381 for Key in self.data:\r
1382 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
1383 return keys\r
1384\r
1385## Boolean chain list\r
1386#\r
1387class Blist(UserList):\r
1388 def __init__(self, initlist=None):\r
1389 UserList.__init__(self, initlist)\r
1390 def __setitem__(self, i, item):\r
1391 if item not in [True, False]:\r
1392 if item == 0:\r
1393 item = False\r
1394 else:\r
1395 item = True\r
1396 self.data[i] = item\r
1397 def _GetResult(self):\r
1398 Value = True\r
1399 for item in self.data:\r
1400 Value &= item\r
1401 return Value\r
1402 Result = property(_GetResult)\r
1403\r
1404def ParseConsoleLog(Filename):\r
1405 Opr = open(os.path.normpath(Filename), 'r')\r
1406 Opw = open(os.path.normpath(Filename + '.New'), 'w+')\r
1407 for Line in Opr.readlines():\r
1408 if Line.find('.efi') > -1:\r
1409 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()\r
1410 Opw.write('%s\n' % Line)\r
1411\r
1412 Opr.close()\r
1413 Opw.close()\r
1414\r
1415## AnalyzeDscPcd\r
1416#\r
1417# Analyze DSC PCD value, since there is no data type info in DSC\r
1418# This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database\r
1419# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
1420# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]\r
1421# 3. Dynamic default:\r
1422# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1423# TokenSpace.PcdCName|PcdValue\r
1424# 4. Dynamic VPD:\r
1425# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1426# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1427# 5. Dynamic HII:\r
1428# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]\r
1429# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1430# there might have "|" operator, also in string value.\r
1431#\r
1432# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1433# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1434# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1435# @retval:\r
1436# ValueList: A List contain fields described above\r
1437# IsValid: True if conforming EBNF, otherwise False\r
1438# Index: The index where PcdValue is in ValueList\r
1439#\r
1440def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1441 Setting = Setting.strip()\r
1442 # There might be escaped quote in a string: \", \\\"\r
1443 Data = Setting.replace('\\\\', '//').replace('\\\"', '\\\'')\r
1444 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
1445 NewStr = ''\r
1446 InStr = False\r
1447 Pair = 0\r
1448 for ch in Data:\r
1449 if ch == '"':\r
1450 InStr = not InStr\r
1451 elif ch == '(' and not InStr:\r
1452 Pair += 1\r
1453 elif ch == ')' and not InStr:\r
1454 Pair -= 1\r
47fea6af 1455\r
f51461c8
LG
1456 if (Pair > 0 or InStr) and ch == TAB_VALUE_SPLIT:\r
1457 NewStr += '-'\r
1458 else:\r
1459 NewStr += ch\r
1460 FieldList = []\r
1461 StartPos = 0\r
1462 while True:\r
1463 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
1464 if Pos < 0:\r
1465 FieldList.append(Setting[StartPos:].strip())\r
1466 break\r
1467 FieldList.append(Setting[StartPos:Pos].strip())\r
1468 StartPos = Pos + 1\r
1469\r
1470 IsValid = True\r
1471 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):\r
1472 Value = FieldList[0]\r
1473 Size = ''\r
1474 if len(FieldList) > 1:\r
1475 Type = FieldList[1]\r
1476 # Fix the PCD type when no DataType input\r
1477 if Type == 'VOID*':\r
1478 DataType = 'VOID*'\r
1479 else:\r
1480 Size = FieldList[1]\r
1481 if len(FieldList) > 2:\r
1482 Size = FieldList[2]\r
1483 if DataType == 'VOID*':\r
1484 IsValid = (len(FieldList) <= 3)\r
1485 else:\r
1486 IsValid = (len(FieldList) <= 1)\r
1487 return [Value, '', Size], IsValid, 0\r
1488 elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):\r
1489 Value = FieldList[0]\r
1490 Size = Type = ''\r
1491 if len(FieldList) > 1:\r
1492 Type = FieldList[1]\r
1493 else:\r
1494 Type = DataType\r
1495 if len(FieldList) > 2:\r
1496 Size = FieldList[2]\r
1497 else:\r
1498 if Type == 'VOID*':\r
1499 if Value.startswith("L"):\r
1500 Size = str((len(Value)- 3 + 1) * 2)\r
1501 elif Value.startswith("{"):\r
1502 Size = str(len(Value.split(",")))\r
1503 else:\r
1504 Size = str(len(Value) -2 + 1 )\r
1505 if DataType == 'VOID*':\r
1506 IsValid = (len(FieldList) <= 3)\r
1507 else:\r
1508 IsValid = (len(FieldList) <= 1)\r
47fea6af 1509 return [Value, Type, Size], IsValid, 0\r
f51461c8
LG
1510 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1511 VpdOffset = FieldList[0]\r
1512 Value = Size = ''\r
1513 if not DataType == 'VOID*':\r
1514 if len(FieldList) > 1:\r
1515 Value = FieldList[1]\r
1516 else:\r
1517 if len(FieldList) > 1:\r
1518 Size = FieldList[1]\r
1519 if len(FieldList) > 2:\r
1520 Value = FieldList[2]\r
1521 if DataType == 'VOID*':\r
1522 IsValid = (len(FieldList) <= 3)\r
1523 else:\r
1524 IsValid = (len(FieldList) <= 2)\r
1525 return [VpdOffset, Size, Value], IsValid, 2\r
1526 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
1527 HiiString = FieldList[0]\r
82a6a960 1528 Guid = Offset = Value = Attribute = ''\r
f51461c8
LG
1529 if len(FieldList) > 1:\r
1530 Guid = FieldList[1]\r
1531 if len(FieldList) > 2:\r
1532 Offset = FieldList[2]\r
1533 if len(FieldList) > 3:\r
1534 Value = FieldList[3]\r
82a6a960
BF
1535 if len(FieldList) > 4:\r
1536 Attribute = FieldList[4]\r
1537 IsValid = (3 <= len(FieldList) <= 5)\r
1538 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
f51461c8
LG
1539 return [], False, 0\r
1540\r
1541## AnalyzePcdData\r
1542#\r
1543# Analyze the pcd Value, Datum type and TokenNumber.\r
1544# Used to avoid split issue while the value string contain "|" character\r
1545#\r
1546# @param[in] Setting: A String contain value/datum type/token number information;\r
1547# \r
1548# @retval ValueList: A List contain value, datum type and toke number. \r
1549#\r
47fea6af
YZ
1550def AnalyzePcdData(Setting):\r
1551 ValueList = ['', '', '']\r
1552\r
1553 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
f51461c8
LG
1554 PtrValue = ValueRe.findall(Setting)\r
1555 \r
1556 ValueUpdateFlag = False\r
1557 \r
1558 if len(PtrValue) >= 1:\r
1559 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1560 ValueUpdateFlag = True\r
f51461c8
LG
1561\r
1562 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1563 ValueList[0:len(TokenList)] = TokenList\r
1564 \r
1565 if ValueUpdateFlag:\r
1566 ValueList[0] = PtrValue[0]\r
1567 \r
1568 return ValueList \r
1569 \r
1570## AnalyzeHiiPcdData\r
1571#\r
1572# Analyze the pcd Value, variable name, variable Guid and variable offset.\r
1573# Used to avoid split issue while the value string contain "|" character\r
1574#\r
1575# @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;\r
1576# \r
1577# @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue. \r
1578#\r
1579def AnalyzeHiiPcdData(Setting):\r
1580 ValueList = ['', '', '', '']\r
1581\r
1582 TokenList = GetSplitValueList(Setting)\r
1583 ValueList[0:len(TokenList)] = TokenList\r
1584\r
1585 return ValueList\r
1586\r
1587## AnalyzeVpdPcdData\r
1588#\r
1589# Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.\r
1590# Used to avoid split issue while the value string contain "|" character\r
1591#\r
1592# @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;\r
1593# \r
1594# @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue. \r
1595#\r
47fea6af
YZ
1596def AnalyzeVpdPcdData(Setting):\r
1597 ValueList = ['', '', '']\r
1598\r
1599 ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')\r
f51461c8
LG
1600 PtrValue = ValueRe.findall(Setting)\r
1601 \r
1602 ValueUpdateFlag = False\r
1603 \r
1604 if len(PtrValue) >= 1:\r
1605 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1606 ValueUpdateFlag = True\r
f51461c8
LG
1607\r
1608 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1609 ValueList[0:len(TokenList)] = TokenList\r
1610 \r
1611 if ValueUpdateFlag:\r
1612 ValueList[2] = PtrValue[0]\r
1613 \r
1614 return ValueList \r
1615\r
1616## check format of PCD value against its the datum type\r
1617#\r
1618# For PCD value setting\r
1619#\r
1620def CheckPcdDatum(Type, Value):\r
1621 if Type == "VOID*":\r
47fea6af 1622 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
f51461c8
LG
1623 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
1624 or (Value.startswith('{') and Value.endswith('}'))\r
1625 ):\r
1626 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
47fea6af 1627 ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)\r
f51461c8
LG
1628 elif ValueRe.match(Value):\r
1629 # Check the chars in UnicodeString or CString is printable\r
1630 if Value.startswith("L"):\r
1631 Value = Value[2:-1]\r
1632 else:\r
1633 Value = Value[1:-1]\r
1634 Printset = set(string.printable)\r
1635 Printset.remove(TAB_PRINTCHAR_VT)\r
1636 Printset.add(TAB_PRINTCHAR_BS)\r
1637 Printset.add(TAB_PRINTCHAR_NUL)\r
1638 if not set(Value).issubset(Printset):\r
1639 PrintList = list(Printset)\r
1640 PrintList.sort()\r
1641 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1642 elif Type == 'BOOLEAN':\r
1643 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1644 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1645 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1646 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
1647 try:\r
1648 Value = long(Value, 0)\r
1649 except:\r
1650 return False, "Invalid value [%s] of type [%s];"\\r
1651 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
1652 else:\r
1653 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type)\r
1654\r
1655 return True, ""\r
1656\r
1657## Split command line option string to list\r
1658#\r
1659# subprocess.Popen needs the args to be a sequence. Otherwise there's problem\r
1660# in non-windows platform to launch command\r
1661#\r
1662def SplitOption(OptionString):\r
1663 OptionList = []\r
1664 LastChar = " "\r
1665 OptionStart = 0\r
1666 QuotationMark = ""\r
1667 for Index in range(0, len(OptionString)):\r
1668 CurrentChar = OptionString[Index]\r
1669 if CurrentChar in ['"', "'"]:\r
1670 if QuotationMark == CurrentChar:\r
1671 QuotationMark = ""\r
1672 elif QuotationMark == "":\r
1673 QuotationMark = CurrentChar\r
1674 continue\r
1675 elif QuotationMark:\r
1676 continue\r
1677\r
1678 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:\r
1679 if Index > OptionStart:\r
47fea6af 1680 OptionList.append(OptionString[OptionStart:Index - 1])\r
f51461c8
LG
1681 OptionStart = Index\r
1682 LastChar = CurrentChar\r
1683 OptionList.append(OptionString[OptionStart:])\r
1684 return OptionList\r
1685\r
1686def CommonPath(PathList):\r
1687 P1 = min(PathList).split(os.path.sep)\r
1688 P2 = max(PathList).split(os.path.sep)\r
1689 for Index in xrange(min(len(P1), len(P2))):\r
1690 if P1[Index] != P2[Index]:\r
1691 return os.path.sep.join(P1[:Index])\r
1692 return os.path.sep.join(P1)\r
1693\r
97fa0ee9
YL
1694#\r
1695# Convert string to C format array\r
1696#\r
1697def ConvertStringToByteArray(Value):\r
1698 Value = Value.strip()\r
1699 if not Value:\r
1700 return None\r
1701 if Value[0] == '{':\r
1702 if not Value.endswith('}'):\r
1703 return None\r
1704 Value = Value.replace(' ', '').replace('{', '').replace('}', '')\r
1705 ValFields = Value.split(',')\r
1706 try:\r
1707 for Index in range(len(ValFields)):\r
1708 ValFields[Index] = str(int(ValFields[Index], 0))\r
1709 except ValueError:\r
1710 return None\r
1711 Value = '{' + ','.join(ValFields) + '}'\r
1712 return Value\r
1713\r
1714 Unicode = False\r
1715 if Value.startswith('L"'):\r
1716 if not Value.endswith('"'):\r
1717 return None\r
1718 Value = Value[1:]\r
1719 Unicode = True\r
1720 elif not Value.startswith('"') or not Value.endswith('"'):\r
1721 return None\r
1722\r
1723 Value = eval(Value) # translate escape character\r
1724 NewValue = '{'\r
1725 for Index in range(0,len(Value)):\r
1726 if Unicode:\r
1727 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','\r
1728 else:\r
1729 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','\r
1730 Value = NewValue + '0}'\r
1731 return Value\r
1732\r
f51461c8
LG
1733class PathClass(object):\r
1734 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1735 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1736 self.Arch = Arch\r
1737 self.File = str(File)\r
1738 if os.path.isabs(self.File):\r
1739 self.Root = ''\r
1740 self.AlterRoot = ''\r
1741 else:\r
1742 self.Root = str(Root)\r
1743 self.AlterRoot = str(AlterRoot)\r
1744\r
1745 # Remove any '.' and '..' in path\r
1746 if self.Root:\r
05cc51ad 1747 self.Root = mws.getWs(self.Root, self.File)\r
f51461c8
LG
1748 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1749 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1750 # eliminate the side-effect of 'C:'\r
1751 if self.Root[-1] == ':':\r
1752 self.Root += os.path.sep\r
1753 # file path should not start with path separator\r
1754 if self.Root[-1] == os.path.sep:\r
1755 self.File = self.Path[len(self.Root):]\r
1756 else:\r
47fea6af 1757 self.File = self.Path[len(self.Root) + 1:]\r
f51461c8
LG
1758 else:\r
1759 self.Path = os.path.normpath(self.File)\r
1760\r
1761 self.SubDir, self.Name = os.path.split(self.File)\r
1762 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1763\r
1764 if self.Root:\r
1765 if self.SubDir:\r
1766 self.Dir = os.path.join(self.Root, self.SubDir)\r
1767 else:\r
1768 self.Dir = self.Root\r
1769 else:\r
1770 self.Dir = self.SubDir\r
1771\r
1772 if IsBinary:\r
1773 self.Type = Type\r
1774 else:\r
1775 self.Type = self.Ext.lower()\r
1776\r
1777 self.IsBinary = IsBinary\r
1778 self.Target = Target\r
1779 self.TagName = TagName\r
1780 self.ToolCode = ToolCode\r
1781 self.ToolChainFamily = ToolChainFamily\r
1782\r
1783 self._Key = None\r
1784\r
1785 ## Convert the object of this class to a string\r
1786 #\r
1787 # Convert member Path of the class to a string\r
1788 #\r
1789 # @retval string Formatted String\r
1790 #\r
1791 def __str__(self):\r
1792 return self.Path\r
1793\r
1794 ## Override __eq__ function\r
1795 #\r
1796 # Check whether PathClass are the same\r
1797 #\r
1798 # @retval False The two PathClass are different\r
1799 # @retval True The two PathClass are the same\r
1800 #\r
1801 def __eq__(self, Other):\r
1802 if type(Other) == type(self):\r
1803 return self.Path == Other.Path\r
1804 else:\r
1805 return self.Path == str(Other)\r
1806\r
1807 ## Override __cmp__ function\r
1808 #\r
1809 # Customize the comparsion operation of two PathClass\r
1810 #\r
1811 # @retval 0 The two PathClass are different\r
1812 # @retval -1 The first PathClass is less than the second PathClass\r
1813 # @retval 1 The first PathClass is Bigger than the second PathClass\r
1814 def __cmp__(self, Other):\r
1815 if type(Other) == type(self):\r
1816 OtherKey = Other.Path\r
1817 else:\r
1818 OtherKey = str(Other)\r
1819 \r
1820 SelfKey = self.Path\r
1821 if SelfKey == OtherKey:\r
1822 return 0\r
1823 elif SelfKey > OtherKey:\r
1824 return 1\r
1825 else:\r
1826 return -1\r
1827\r
1828 ## Override __hash__ function\r
1829 #\r
1830 # Use Path as key in hash table\r
1831 #\r
1832 # @retval string Key for hash table\r
1833 #\r
1834 def __hash__(self):\r
1835 return hash(self.Path)\r
1836\r
1837 def _GetFileKey(self):\r
1838 if self._Key == None:\r
1839 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target\r
1840 return self._Key\r
1841\r
1842 def _GetTimeStamp(self):\r
1843 return os.stat(self.Path)[8]\r
1844\r
1845 def Validate(self, Type='', CaseSensitive=True):\r
1846 if GlobalData.gCaseInsensitive:\r
1847 CaseSensitive = False\r
1848 if Type and Type.lower() != self.Type:\r
1849 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
1850\r
1851 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
1852 if not RealRoot and not RealFile:\r
1853 RealFile = self.File\r
1854 if self.AlterRoot:\r
1855 RealFile = os.path.join(self.AlterRoot, self.File)\r
1856 elif self.Root:\r
1857 RealFile = os.path.join(self.Root, self.File)\r
05cc51ad
LY
1858 if len (mws.getPkgPath()) == 0:\r
1859 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
1860 else:\r
1861 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
f51461c8
LG
1862\r
1863 ErrorCode = 0\r
1864 ErrorInfo = ''\r
1865 if RealRoot != self.Root or RealFile != self.File:\r
1866 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
1867 ErrorCode = FILE_CASE_MISMATCH\r
1868 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
1869\r
1870 self.SubDir, self.Name = os.path.split(RealFile)\r
1871 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1872 if self.SubDir:\r
1873 self.Dir = os.path.join(RealRoot, self.SubDir)\r
1874 else:\r
1875 self.Dir = RealRoot\r
1876 self.File = RealFile\r
1877 self.Root = RealRoot\r
1878 self.Path = os.path.join(RealRoot, RealFile)\r
1879 return ErrorCode, ErrorInfo\r
1880\r
1881 Key = property(_GetFileKey)\r
1882 TimeStamp = property(_GetTimeStamp)\r
1883\r
1884## Parse PE image to get the required PE informaion.\r
1885#\r
1886class PeImageClass():\r
1887 ## Constructor\r
1888 #\r
1889 # @param File FilePath of PeImage\r
1890 #\r
1891 def __init__(self, PeFile):\r
1892 self.FileName = PeFile\r
1893 self.IsValid = False\r
1894 self.Size = 0\r
1895 self.EntryPoint = 0\r
1896 self.SectionAlignment = 0\r
1897 self.SectionHeaderList = []\r
1898 self.ErrorInfo = ''\r
1899 try:\r
1900 PeObject = open(PeFile, 'rb')\r
1901 except:\r
1902 self.ErrorInfo = self.FileName + ' can not be found\n'\r
1903 return\r
1904 # Read DOS header\r
1905 ByteArray = array.array('B')\r
1906 ByteArray.fromfile(PeObject, 0x3E)\r
1907 ByteList = ByteArray.tolist()\r
1908 # DOS signature should be 'MZ'\r
1909 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
1910 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
1911 return\r
1912\r
1913 # Read 4 byte PE Signature\r
1914 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
1915 PeObject.seek(PeOffset)\r
1916 ByteArray = array.array('B')\r
1917 ByteArray.fromfile(PeObject, 4)\r
1918 # PE signature should be 'PE\0\0'\r
1919 if ByteArray.tostring() != 'PE\0\0':\r
1920 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
1921 return\r
1922\r
1923 # Read PE file header\r
1924 ByteArray = array.array('B')\r
1925 ByteArray.fromfile(PeObject, 0x14)\r
1926 ByteList = ByteArray.tolist()\r
1927 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
1928 if SecNumber == 0:\r
1929 self.ErrorInfo = self.FileName + ' has no section header'\r
1930 return\r
1931\r
1932 # Read PE optional header\r
1933 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
1934 ByteArray = array.array('B')\r
1935 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
1936 ByteList = ByteArray.tolist()\r
1937 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
1938 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
1939 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
1940\r
1941 # Read each Section Header\r
1942 for Index in range(SecNumber):\r
1943 ByteArray = array.array('B')\r
1944 ByteArray.fromfile(PeObject, 0x28)\r
1945 ByteList = ByteArray.tolist()\r
1946 SecName = self._ByteListToStr(ByteList[0:8])\r
1947 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
1948 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
1949 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
1950 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
1951 self.IsValid = True\r
1952 PeObject.close()\r
1953\r
1954 def _ByteListToStr(self, ByteList):\r
1955 String = ''\r
1956 for index in range(len(ByteList)):\r
1957 if ByteList[index] == 0: \r
1958 break\r
1959 String += chr(ByteList[index])\r
1960 return String\r
1961\r
1962 def _ByteListToInt(self, ByteList):\r
1963 Value = 0\r
1964 for index in range(len(ByteList) - 1, -1, -1):\r
1965 Value = (Value << 8) | int(ByteList[index])\r
1966 return Value\r
1967\r
1968\r
1969class SkuClass():\r
1970 \r
1971 DEFAULT = 0\r
1972 SINGLE = 1\r
1973 MULTIPLE =2\r
1974 \r
1975 def __init__(self,SkuIdentifier='', SkuIds={}):\r
1976 \r
1977 self.AvailableSkuIds = sdict()\r
1978 self.SkuIdSet = []\r
1ae469b9 1979 self.SkuIdNumberSet = []\r
f51461c8
LG
1980 if SkuIdentifier == '' or SkuIdentifier is None:\r
1981 self.SkuIdSet = ['DEFAULT']\r
1ae469b9 1982 self.SkuIdNumberSet = ['0U']\r
f51461c8
LG
1983 elif SkuIdentifier == 'ALL':\r
1984 self.SkuIdSet = SkuIds.keys()\r
1ae469b9 1985 self.SkuIdNumberSet = [num.strip() + 'U' for num in SkuIds.values()]\r
f51461c8
LG
1986 else:\r
1987 r = SkuIdentifier.split('|') \r
1988 self.SkuIdSet=[r[k].strip() for k in range(len(r))] \r
1ae469b9
BF
1989 k = None\r
1990 try: \r
1991 self.SkuIdNumberSet = [SkuIds[k].strip() + 'U' for k in self.SkuIdSet] \r
1992 except Exception:\r
1993 EdkLogger.error("build", PARAMETER_INVALID,\r
1994 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
1995 % (k, " ".join(SkuIds.keys())))\r
f51461c8
LG
1996 if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet and SkuIdentifier != 'ALL':\r
1997 self.SkuIdSet.remove('DEFAULT')\r
1ae469b9 1998 self.SkuIdNumberSet.remove('0U')\r
f51461c8
LG
1999 for each in self.SkuIdSet:\r
2000 if each in SkuIds:\r
2001 self.AvailableSkuIds[each] = SkuIds[each]\r
2002 else:\r
2003 EdkLogger.error("build", PARAMETER_INVALID,\r
2004 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
2005 % (each, " ".join(SkuIds.keys())))\r
2006 \r
2007 def __SkuUsageType(self): \r
2008 \r
2009 if len(self.SkuIdSet) == 1:\r
2010 if self.SkuIdSet[0] == 'DEFAULT':\r
2011 return SkuClass.DEFAULT\r
2012 else:\r
2013 return SkuClass.SINGLE\r
2014 else:\r
2015 return SkuClass.MULTIPLE\r
2016\r
2017 def __GetAvailableSkuIds(self):\r
2018 return self.AvailableSkuIds\r
2019 \r
2020 def __GetSystemSkuID(self):\r
2021 if self.__SkuUsageType() == SkuClass.SINGLE:\r
2022 return self.SkuIdSet[0]\r
2023 else:\r
2024 return 'DEFAULT'\r
1ae469b9
BF
2025 def __GetAvailableSkuIdNumber(self):\r
2026 return self.SkuIdNumberSet\r
f51461c8
LG
2027 SystemSkuId = property(__GetSystemSkuID)\r
2028 AvailableSkuIdSet = property(__GetAvailableSkuIds)\r
2029 SkuUsageType = property(__SkuUsageType)\r
1ae469b9 2030 AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)\r
a3251d84
YL
2031\r
2032#\r
2033# Pack a registry format GUID\r
2034#\r
2035def PackRegistryFormatGuid(Guid):\r
2036 Guid = Guid.split('-')\r
2037 return pack('=LHHBBBBBBBB',\r
2038 int(Guid[0], 16),\r
2039 int(Guid[1], 16),\r
2040 int(Guid[2], 16),\r
2041 int(Guid[3][-4:-2], 16),\r
2042 int(Guid[3][-2:], 16),\r
2043 int(Guid[4][-12:-10], 16),\r
2044 int(Guid[4][-10:-8], 16),\r
2045 int(Guid[4][-8:-6], 16),\r
2046 int(Guid[4][-6:-4], 16),\r
2047 int(Guid[4][-4:-2], 16),\r
2048 int(Guid[4][-2:], 16)\r
2049 )\r
2050\r
f51461c8
LG
2051##\r
2052#\r
2053# This acts like the main() function for the script, unless it is 'import'ed into another\r
2054# script.\r
2055#\r
2056if __name__ == '__main__':\r
2057 pass\r
2058\r