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