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