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