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