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