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