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