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