]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
BaseTools: the list and iterator translation
[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
f8d11e5a 577 GuidKeys = list(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
f8d11e5a 584 return None\r
f51461c8 585\r
f51461c8
LG
586## A string template class\r
587#\r
588# This class implements a template for string replacement. A string template\r
589# looks like following\r
590#\r
591# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
592#\r
593# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
594# length of "placeholder_name", which is a list passed through a dict. The\r
595# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
596# be not used and, in this case, the "placeholder_name" must not a list and it\r
597# will just be replaced once.\r
598#\r
599class TemplateString(object):\r
600 _REPEAT_START_FLAG = "BEGIN"\r
601 _REPEAT_END_FLAG = "END"\r
602\r
603 class Section(object):\r
604 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
605\r
606 def __init__(self, TemplateSection, PlaceHolderList):\r
607 self._Template = TemplateSection\r
608 self._PlaceHolderList = []\r
609\r
610 # Split the section into sub-sections according to the position of placeholders\r
611 if PlaceHolderList:\r
612 self._SubSectionList = []\r
613 SubSectionStart = 0\r
614 #\r
615 # The placeholders passed in must be in the format of\r
616 #\r
617 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
618 #\r
47fea6af 619 for PlaceHolder, Start, End in PlaceHolderList:\r
f51461c8
LG
620 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
621 self._SubSectionList.append(TemplateSection[Start:End])\r
622 self._PlaceHolderList.append(PlaceHolder)\r
623 SubSectionStart = End\r
624 if SubSectionStart < len(TemplateSection):\r
625 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
626 else:\r
627 self._SubSectionList = [TemplateSection]\r
628\r
629 def __str__(self):\r
630 return self._Template + " : " + str(self._PlaceHolderList)\r
631\r
632 def Instantiate(self, PlaceHolderValues):\r
633 RepeatTime = -1\r
634 RepeatPlaceHolders = {}\r
635 NonRepeatPlaceHolders = {}\r
636\r
637 for PlaceHolder in self._PlaceHolderList:\r
638 if PlaceHolder not in PlaceHolderValues:\r
639 continue\r
640 Value = PlaceHolderValues[PlaceHolder]\r
641 if type(Value) in self._LIST_TYPES:\r
642 if RepeatTime < 0:\r
643 RepeatTime = len(Value)\r
644 elif RepeatTime != len(Value):\r
645 EdkLogger.error(\r
646 "TemplateString",\r
647 PARAMETER_INVALID,\r
648 "${%s} has different repeat time from others!" % PlaceHolder,\r
649 ExtraData=str(self._Template)\r
650 )\r
651 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
652 else:\r
653 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
654\r
655 if NonRepeatPlaceHolders:\r
656 StringList = []\r
657 for S in self._SubSectionList:\r
658 if S not in NonRepeatPlaceHolders:\r
659 StringList.append(S)\r
660 else:\r
661 StringList.append(str(NonRepeatPlaceHolders[S]))\r
662 else:\r
663 StringList = self._SubSectionList\r
664\r
665 if RepeatPlaceHolders:\r
666 TempStringList = []\r
667 for Index in range(RepeatTime):\r
668 for S in StringList:\r
669 if S not in RepeatPlaceHolders:\r
670 TempStringList.append(S)\r
671 else:\r
672 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
673 StringList = TempStringList\r
674\r
675 return "".join(StringList)\r
676\r
677 ## Constructor\r
678 def __init__(self, Template=None):\r
4e375707 679 self.String = []\r
f51461c8
LG
680 self.IsBinary = False\r
681 self._Template = Template\r
682 self._TemplateSectionList = self._Parse(Template)\r
683\r
684 ## str() operator\r
685 #\r
686 # @retval string The string replaced\r
687 #\r
688 def __str__(self):\r
4e375707 689 return "".join(self.String)\r
f51461c8
LG
690\r
691 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
692 #\r
693 # @retval list A list of TemplateString.Section objects\r
694 #\r
695 def _Parse(self, Template):\r
696 SectionStart = 0\r
697 SearchFrom = 0\r
698 MatchEnd = 0\r
699 PlaceHolderList = []\r
700 TemplateSectionList = []\r
701 while Template:\r
702 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
703 if not MatchObj:\r
704 if MatchEnd <= len(Template):\r
705 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
706 TemplateSectionList.append(TemplateSection)\r
707 break\r
708\r
709 MatchString = MatchObj.group(1)\r
710 MatchStart = MatchObj.start()\r
711 MatchEnd = MatchObj.end()\r
712\r
713 if MatchString == self._REPEAT_START_FLAG:\r
714 if MatchStart > SectionStart:\r
715 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
716 TemplateSectionList.append(TemplateSection)\r
717 SectionStart = MatchEnd\r
718 PlaceHolderList = []\r
719 elif MatchString == self._REPEAT_END_FLAG:\r
720 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
721 TemplateSectionList.append(TemplateSection)\r
722 SectionStart = MatchEnd\r
723 PlaceHolderList = []\r
724 else:\r
725 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
726 SearchFrom = MatchEnd\r
727 return TemplateSectionList\r
728\r
729 ## Replace the string template with dictionary of placeholders and append it to previous one\r
730 #\r
731 # @param AppendString The string template to append\r
732 # @param Dictionary The placeholder dictionaries\r
733 #\r
734 def Append(self, AppendString, Dictionary=None):\r
735 if Dictionary:\r
736 SectionList = self._Parse(AppendString)\r
4e375707 737 self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList))\r
f51461c8 738 else:\r
4e375707
B
739 if isinstance(AppendString,list):\r
740 self.String.extend(AppendString)\r
741 else:\r
742 self.String.append(AppendString)\r
f51461c8
LG
743\r
744 ## Replace the string template with dictionary of placeholders\r
745 #\r
746 # @param Dictionary The placeholder dictionaries\r
747 #\r
748 # @retval str The string replaced with placeholder values\r
749 #\r
750 def Replace(self, Dictionary=None):\r
8252e6bf 751 return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList)\r
f51461c8
LG
752\r
753## Progress indicator class\r
754#\r
755# This class makes use of thread to print progress on console.\r
756#\r
757class Progressor:\r
758 # for avoiding deadloop\r
759 _StopFlag = None\r
760 _ProgressThread = None\r
761 _CheckInterval = 0.25\r
762\r
763 ## Constructor\r
764 #\r
765 # @param OpenMessage The string printed before progress charaters\r
766 # @param CloseMessage The string printed after progress charaters\r
767 # @param ProgressChar The charater used to indicate the progress\r
768 # @param Interval The interval in seconds between two progress charaters\r
769 #\r
770 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
771 self.PromptMessage = OpenMessage\r
772 self.CodaMessage = CloseMessage\r
773 self.ProgressChar = ProgressChar\r
774 self.Interval = Interval\r
4231a819 775 if Progressor._StopFlag is None:\r
f51461c8
LG
776 Progressor._StopFlag = threading.Event()\r
777\r
778 ## Start to print progress charater\r
779 #\r
780 # @param OpenMessage The string printed before progress charaters\r
781 #\r
782 def Start(self, OpenMessage=None):\r
4231a819 783 if OpenMessage is not None:\r
f51461c8
LG
784 self.PromptMessage = OpenMessage\r
785 Progressor._StopFlag.clear()\r
4231a819 786 if Progressor._ProgressThread is None:\r
f51461c8
LG
787 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
788 Progressor._ProgressThread.setDaemon(False)\r
789 Progressor._ProgressThread.start()\r
790\r
791 ## Stop printing progress charater\r
792 #\r
793 # @param CloseMessage The string printed after progress charaters\r
794 #\r
795 def Stop(self, CloseMessage=None):\r
796 OriginalCodaMessage = self.CodaMessage\r
4231a819 797 if CloseMessage is not None:\r
f51461c8
LG
798 self.CodaMessage = CloseMessage\r
799 self.Abort()\r
800 self.CodaMessage = OriginalCodaMessage\r
801\r
802 ## Thread entry method\r
803 def _ProgressThreadEntry(self):\r
804 sys.stdout.write(self.PromptMessage + " ")\r
805 sys.stdout.flush()\r
806 TimeUp = 0.0\r
807 while not Progressor._StopFlag.isSet():\r
808 if TimeUp <= 0.0:\r
809 sys.stdout.write(self.ProgressChar)\r
810 sys.stdout.flush()\r
811 TimeUp = self.Interval\r
812 time.sleep(self._CheckInterval)\r
813 TimeUp -= self._CheckInterval\r
814 sys.stdout.write(" " + self.CodaMessage + "\n")\r
815 sys.stdout.flush()\r
816\r
817 ## Abort the progress display\r
818 @staticmethod\r
819 def Abort():\r
4231a819 820 if Progressor._StopFlag is not None:\r
f51461c8 821 Progressor._StopFlag.set()\r
4231a819 822 if Progressor._ProgressThread is not None:\r
f51461c8
LG
823 Progressor._ProgressThread.join()\r
824 Progressor._ProgressThread = None\r
825\r
f51461c8 826\r
f51461c8
LG
827## Dictionary using prioritized list as key\r
828#\r
829class tdict:\r
830 _ListType = type([])\r
831 _TupleType = type(())\r
832 _Wildcard = 'COMMON'\r
bc39c5cb 833 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM']\r
f51461c8
LG
834\r
835 def __init__(self, _Single_=False, _Level_=2):\r
836 self._Level_ = _Level_\r
837 self.data = {}\r
838 self._Single_ = _Single_\r
839\r
840 # =[] operator\r
841 def __getitem__(self, key):\r
842 KeyType = type(key)\r
843 RestKeys = None\r
844 if KeyType == self._ListType or KeyType == self._TupleType:\r
845 FirstKey = key[0]\r
846 if len(key) > 1:\r
847 RestKeys = key[1:]\r
848 elif self._Level_ > 1:\r
47fea6af 849 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
850 else:\r
851 FirstKey = key\r
852 if self._Level_ > 1:\r
47fea6af 853 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8 854\r
4231a819 855 if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:\r
f51461c8
LG
856 FirstKey = self._Wildcard\r
857\r
858 if self._Single_:\r
859 return self._GetSingleValue(FirstKey, RestKeys)\r
860 else:\r
861 return self._GetAllValues(FirstKey, RestKeys)\r
862\r
863 def _GetSingleValue(self, FirstKey, RestKeys):\r
864 Value = None\r
865 #print "%s-%s" % (FirstKey, self._Level_) ,\r
866 if self._Level_ > 1:\r
867 if FirstKey == self._Wildcard:\r
868 if FirstKey in self.data:\r
869 Value = self.data[FirstKey][RestKeys]\r
4231a819 870 if Value is None:\r
f51461c8
LG
871 for Key in self.data:\r
872 Value = self.data[Key][RestKeys]\r
4231a819 873 if Value is not None: break\r
f51461c8
LG
874 else:\r
875 if FirstKey in self.data:\r
876 Value = self.data[FirstKey][RestKeys]\r
4231a819 877 if Value is None and self._Wildcard in self.data:\r
f51461c8
LG
878 #print "Value=None"\r
879 Value = self.data[self._Wildcard][RestKeys]\r
880 else:\r
881 if FirstKey == self._Wildcard:\r
882 if FirstKey in self.data:\r
883 Value = self.data[FirstKey]\r
4231a819 884 if Value is None:\r
f51461c8
LG
885 for Key in self.data:\r
886 Value = self.data[Key]\r
4231a819 887 if Value is not None: break\r
f51461c8
LG
888 else:\r
889 if FirstKey in self.data:\r
890 Value = self.data[FirstKey]\r
891 elif self._Wildcard in self.data:\r
892 Value = self.data[self._Wildcard]\r
893 return Value\r
894\r
895 def _GetAllValues(self, FirstKey, RestKeys):\r
896 Value = []\r
897 if self._Level_ > 1:\r
898 if FirstKey == self._Wildcard:\r
899 for Key in self.data:\r
900 Value += self.data[Key][RestKeys]\r
901 else:\r
902 if FirstKey in self.data:\r
903 Value += self.data[FirstKey][RestKeys]\r
904 if self._Wildcard in self.data:\r
905 Value += self.data[self._Wildcard][RestKeys]\r
906 else:\r
907 if FirstKey == self._Wildcard:\r
908 for Key in self.data:\r
909 Value.append(self.data[Key])\r
910 else:\r
911 if FirstKey in self.data:\r
912 Value.append(self.data[FirstKey])\r
913 if self._Wildcard in self.data:\r
914 Value.append(self.data[self._Wildcard])\r
915 return Value\r
916\r
917 ## []= operator\r
918 def __setitem__(self, key, value):\r
919 KeyType = type(key)\r
920 RestKeys = None\r
921 if KeyType == self._ListType or KeyType == self._TupleType:\r
922 FirstKey = key[0]\r
923 if len(key) > 1:\r
924 RestKeys = key[1:]\r
925 else:\r
47fea6af 926 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
927 else:\r
928 FirstKey = key\r
929 if self._Level_ > 1:\r
47fea6af 930 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
931\r
932 if FirstKey in self._ValidWildcardList:\r
933 FirstKey = self._Wildcard\r
934\r
935 if FirstKey not in self.data and self._Level_ > 0:\r
936 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
937\r
938 if self._Level_ > 1:\r
939 self.data[FirstKey][RestKeys] = value\r
940 else:\r
941 self.data[FirstKey] = value\r
942\r
943 def SetGreedyMode(self):\r
944 self._Single_ = False\r
945 if self._Level_ > 1:\r
946 for Key in self.data:\r
947 self.data[Key].SetGreedyMode()\r
948\r
949 def SetSingleMode(self):\r
950 self._Single_ = True\r
951 if self._Level_ > 1:\r
952 for Key in self.data:\r
953 self.data[Key].SetSingleMode()\r
954\r
955 def GetKeys(self, KeyIndex=0):\r
956 assert KeyIndex >= 0\r
957 if KeyIndex == 0:\r
958 return set(self.data.keys())\r
959 else:\r
960 keys = set()\r
961 for Key in self.data:\r
962 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
963 return keys\r
964\r
67e11e4d 965def AnalyzePcdExpression(Setting):\r
d3d97b37 966 RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))\r
967 Setting = Setting.replace('\\\\', RanStr).strip()\r
ea927d2f
FY
968 # There might be escaped quote in a string: \", \\\" , \', \\\'\r
969 Data = Setting\r
f51461c8
LG
970 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
971 NewStr = ''\r
ea927d2f
FY
972 InSingleQuoteStr = False\r
973 InDoubleQuoteStr = False\r
f51461c8 974 Pair = 0\r
ea927d2f
FY
975 for Index, ch in enumerate(Data):\r
976 if ch == '"' and not InSingleQuoteStr:\r
977 if Data[Index - 1] != '\\':\r
978 InDoubleQuoteStr = not InDoubleQuoteStr\r
979 elif ch == "'" and not InDoubleQuoteStr:\r
980 if Data[Index - 1] != '\\':\r
981 InSingleQuoteStr = not InSingleQuoteStr\r
982 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 983 Pair += 1\r
ea927d2f 984 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 985 Pair -= 1\r
47fea6af 986\r
ea927d2f 987 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:\r
f51461c8
LG
988 NewStr += '-'\r
989 else:\r
990 NewStr += ch\r
991 FieldList = []\r
992 StartPos = 0\r
993 while True:\r
994 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
995 if Pos < 0:\r
996 FieldList.append(Setting[StartPos:].strip())\r
997 break\r
998 FieldList.append(Setting[StartPos:Pos].strip())\r
999 StartPos = Pos + 1\r
d3d97b37 1000 for i, ch in enumerate(FieldList):\r
1001 if RanStr in ch:\r
1002 FieldList[i] = ch.replace(RanStr,'\\\\')\r
67e11e4d
YZ
1003 return FieldList\r
1004\r
42bd1750
CJ
1005def ParseFieldValue (Value):\r
1006 def ParseDevPathValue (Value):\r
1007 if '\\' in Value:\r
1008 Value.replace('\\', '/').replace(' ', '')\r
7dbc50bd 1009\r
42bd1750
CJ
1010 Cmd = 'DevicePath ' + '"' + Value + '"'\r
1011 try:\r
1012 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
1013 out, err = p.communicate()\r
1014 except Exception as X:\r
1015 raise BadExpression("DevicePath: %s" % (str(X)) )\r
1016 finally:\r
1017 subprocess._cleanup()\r
1018 p.stdout.close()\r
1019 p.stderr.close()\r
1020 if err:\r
1021 raise BadExpression("DevicePath: %s" % str(err))\r
1022 Size = len(out.split())\r
1023 out = ','.join(out.split())\r
1024 return '{' + out + '}', Size\r
726c501c 1025\r
72a1d776 1026 if "{CODE(" in Value:\r
1027 return Value, len(Value.split(","))\r
0d1f5b2b 1028 if isinstance(Value, type(0)):\r
b3e94a06 1029 return Value, (Value.bit_length() + 7) // 8\r
0d1f5b2b 1030 if not isinstance(Value, type('')):\r
726c501c
YZ
1031 raise BadExpression('Type %s is %s' %(Value, type(Value)))\r
1032 Value = Value.strip()\r
656d2539 1033 if Value.startswith(TAB_UINT8) and Value.endswith(')'):\r
726c501c
YZ
1034 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1035 if Size > 1:\r
1036 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1037 return Value, 1\r
656d2539 1038 if Value.startswith(TAB_UINT16) and Value.endswith(')'):\r
726c501c
YZ
1039 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1040 if Size > 2:\r
1041 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1042 return Value, 2\r
656d2539 1043 if Value.startswith(TAB_UINT32) and Value.endswith(')'):\r
726c501c
YZ
1044 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1045 if Size > 4:\r
1046 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1047 return Value, 4\r
656d2539 1048 if Value.startswith(TAB_UINT64) and Value.endswith(')'):\r
726c501c
YZ
1049 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1050 if Size > 8:\r
1051 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))\r
1052 return Value, 8\r
91fa33ee 1053 if Value.startswith(TAB_GUID) and Value.endswith(')'):\r
726c501c
YZ
1054 Value = Value.split('(', 1)[1][:-1].strip()\r
1055 if Value[0] == '{' and Value[-1] == '}':\r
4344a788 1056 TmpValue = GuidStructureStringToGuidString(Value)\r
85e5d3cf 1057 if not TmpValue:\r
4344a788
FY
1058 raise BadExpression("Invalid GUID value string %s" % Value)\r
1059 Value = TmpValue\r
726c501c
YZ
1060 if Value[0] == '"' and Value[-1] == '"':\r
1061 Value = Value[1:-1]\r
1062 try:\r
00f86d89 1063 Value = "'" + uuid.UUID(Value).bytes_le + "'"\r
5b0671c1 1064 except ValueError as Message:\r
caf74495 1065 raise BadExpression(Message)\r
726c501c
YZ
1066 Value, Size = ParseFieldValue(Value)\r
1067 return Value, 16\r
1068 if Value.startswith('L"') and Value.endswith('"'):\r
1069 # Unicode String\r
4faf1322
FY
1070 # translate escape character\r
1071 Value = Value[1:]\r
1072 try:\r
1073 Value = eval(Value)\r
1074 except:\r
1075 Value = Value[1:-1]\r
1076 List = list(Value)\r
726c501c
YZ
1077 List.reverse()\r
1078 Value = 0\r
1079 for Char in List:\r
1080 Value = (Value << 16) | ord(Char)\r
1081 return Value, (len(List) + 1) * 2\r
1082 if Value.startswith('"') and Value.endswith('"'):\r
1083 # ASCII String\r
4faf1322
FY
1084 # translate escape character\r
1085 try:\r
1086 Value = eval(Value)\r
1087 except:\r
1088 Value = Value[1:-1]\r
1089 List = list(Value)\r
726c501c
YZ
1090 List.reverse()\r
1091 Value = 0\r
1092 for Char in List:\r
1093 Value = (Value << 8) | ord(Char)\r
1094 return Value, len(List) + 1\r
1095 if Value.startswith("L'") and Value.endswith("'"):\r
1096 # Unicode Character Constant\r
4faf1322
FY
1097 # translate escape character\r
1098 Value = Value[1:]\r
1099 try:\r
1100 Value = eval(Value)\r
1101 except:\r
1102 Value = Value[1:-1]\r
1103 List = list(Value)\r
0e6b8673
FY
1104 if len(List) == 0:\r
1105 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1106 List.reverse()\r
1107 Value = 0\r
1108 for Char in List:\r
1109 Value = (Value << 16) | ord(Char)\r
1110 return Value, len(List) * 2\r
1111 if Value.startswith("'") and Value.endswith("'"):\r
1112 # Character constant\r
4faf1322
FY
1113 # translate escape character\r
1114 try:\r
1115 Value = eval(Value)\r
1116 except:\r
1117 Value = Value[1:-1]\r
1118 List = list(Value)\r
0e6b8673
FY
1119 if len(List) == 0:\r
1120 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1121 List.reverse()\r
1122 Value = 0\r
1123 for Char in List:\r
1124 Value = (Value << 8) | ord(Char)\r
1125 return Value, len(List)\r
1126 if Value.startswith('{') and Value.endswith('}'):\r
1127 # Byte array\r
1128 Value = Value[1:-1]\r
1129 List = [Item.strip() for Item in Value.split(',')]\r
1130 List.reverse()\r
1131 Value = 0\r
1132 RetSize = 0\r
1133 for Item in List:\r
1134 ItemValue, Size = ParseFieldValue(Item)\r
1135 RetSize += Size\r
1136 for I in range(Size):\r
1137 Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)\r
1138 return Value, RetSize\r
1139 if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):\r
8ad5f10a
FY
1140 Value = Value.replace("DEVICE_PATH(", '').rstrip(')')\r
1141 Value = Value.strip().strip('"')\r
726c501c
YZ
1142 return ParseDevPathValue(Value)\r
1143 if Value.lower().startswith('0x'):\r
b62cbfb7 1144 try:\r
1145 Value = int(Value, 16)\r
1146 except:\r
1147 raise BadExpression("invalid hex value: %s" % Value)\r
726c501c
YZ
1148 if Value == 0:\r
1149 return 0, 1\r
b3e94a06 1150 return Value, (Value.bit_length() + 7) // 8\r
726c501c
YZ
1151 if Value[0].isdigit():\r
1152 Value = int(Value, 10)\r
1153 if Value == 0:\r
1154 return 0, 1\r
b3e94a06 1155 return Value, (Value.bit_length() + 7) // 8\r
726c501c
YZ
1156 if Value.lower() == 'true':\r
1157 return 1, 1\r
1158 if Value.lower() == 'false':\r
1159 return 0, 1\r
ae7b6df8 1160 return Value, 1\r
ae7b6df8 1161\r
67e11e4d
YZ
1162## AnalyzeDscPcd\r
1163#\r
1164# Analyze DSC PCD value, since there is no data type info in DSC\r
f2cc33d8 1165# This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database\r
67e11e4d 1166# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
f2cc33d8 1167# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
67e11e4d
YZ
1168# 3. Dynamic default:\r
1169# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1170# TokenSpace.PcdCName|PcdValue\r
1171# 4. Dynamic VPD:\r
1172# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1173# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1174# 5. Dynamic HII:\r
f2cc33d8 1175# TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]\r
67e11e4d
YZ
1176# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1177# there might have "|" operator, also in string value.\r
1178#\r
1179# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1180# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1181# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1182# @retval:\r
1183# ValueList: A List contain fields described above\r
1184# IsValid: True if conforming EBNF, otherwise False\r
1185# Index: The index where PcdValue is in ValueList\r
1186#\r
1187def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1188 FieldList = AnalyzePcdExpression(Setting)\r
1189\r
f51461c8 1190 IsValid = True\r
f2cc33d8 1191 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
1192 Value = FieldList[0]\r
1193 Size = ''\r
f2cc33d8 1194 if len(FieldList) > 1 and FieldList[1]:\r
1195 DataType = FieldList[1]\r
ff4d0f85 1196 if FieldList[1] != TAB_VOID and StructPattern.match(FieldList[1]) is None:\r
520365de 1197 IsValid = False\r
f51461c8
LG
1198 if len(FieldList) > 2:\r
1199 Size = FieldList[2]\r
f2cc33d8 1200 if IsValid:\r
1201 if DataType == "":\r
1202 IsValid = (len(FieldList) <= 1)\r
1203 else:\r
1204 IsValid = (len(FieldList) <= 3)\r
520365de
B
1205\r
1206 if Size:\r
1207 try:\r
ccaa7754 1208 int(Size, 16) if Size.upper().startswith("0X") else int(Size)\r
520365de
B
1209 except:\r
1210 IsValid = False\r
1211 Size = -1\r
f2cc33d8 1212 return [str(Value), DataType, str(Size)], IsValid, 0\r
1213 elif PcdType == MODEL_PCD_FEATURE_FLAG:\r
1214 Value = FieldList[0]\r
1215 Size = ''\r
1216 IsValid = (len(FieldList) <= 1)\r
1217 return [Value, DataType, str(Size)], IsValid, 0\r
f51461c8
LG
1218 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1219 VpdOffset = FieldList[0]\r
1220 Value = Size = ''\r
656d2539 1221 if not DataType == TAB_VOID:\r
f51461c8
LG
1222 if len(FieldList) > 1:\r
1223 Value = FieldList[1]\r
1224 else:\r
1225 if len(FieldList) > 1:\r
1226 Size = FieldList[1]\r
1227 if len(FieldList) > 2:\r
1228 Value = FieldList[2]\r
ae7b6df8
LG
1229 if DataType == "":\r
1230 IsValid = (len(FieldList) <= 1)\r
f51461c8 1231 else:\r
ae7b6df8 1232 IsValid = (len(FieldList) <= 3)\r
520365de
B
1233 if Size:\r
1234 try:\r
ccaa7754 1235 int(Size, 16) if Size.upper().startswith("0X") else int(Size)\r
520365de
B
1236 except:\r
1237 IsValid = False\r
1238 Size = -1\r
1239 return [VpdOffset, str(Size), Value], IsValid, 2\r
f51461c8 1240 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
24bd035c 1241 IsValid = (3 <= len(FieldList) <= 5)\r
f51461c8 1242 HiiString = FieldList[0]\r
82a6a960 1243 Guid = Offset = Value = Attribute = ''\r
f51461c8
LG
1244 if len(FieldList) > 1:\r
1245 Guid = FieldList[1]\r
1246 if len(FieldList) > 2:\r
1247 Offset = FieldList[2]\r
1248 if len(FieldList) > 3:\r
1249 Value = FieldList[3]\r
82a6a960
BF
1250 if len(FieldList) > 4:\r
1251 Attribute = FieldList[4]\r
82a6a960 1252 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
f51461c8
LG
1253 return [], False, 0\r
1254\r
1255## AnalyzePcdData\r
1256#\r
1257# Analyze the pcd Value, Datum type and TokenNumber.\r
1258# Used to avoid split issue while the value string contain "|" character\r
1259#\r
1260# @param[in] Setting: A String contain value/datum type/token number information;\r
f7496d71
LG
1261#\r
1262# @retval ValueList: A List contain value, datum type and toke number.\r
f51461c8 1263#\r
47fea6af
YZ
1264def AnalyzePcdData(Setting):\r
1265 ValueList = ['', '', '']\r
1266\r
1267 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
f51461c8 1268 PtrValue = ValueRe.findall(Setting)\r
f7496d71 1269\r
f51461c8 1270 ValueUpdateFlag = False\r
f7496d71 1271\r
f51461c8
LG
1272 if len(PtrValue) >= 1:\r
1273 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1274 ValueUpdateFlag = True\r
f51461c8
LG
1275\r
1276 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1277 ValueList[0:len(TokenList)] = TokenList\r
f7496d71 1278\r
f51461c8
LG
1279 if ValueUpdateFlag:\r
1280 ValueList[0] = PtrValue[0]\r
f7496d71
LG
1281\r
1282 return ValueList\r
1283\r
f51461c8
LG
1284## check format of PCD value against its the datum type\r
1285#\r
1286# For PCD value setting\r
1287#\r
1288def CheckPcdDatum(Type, Value):\r
656d2539 1289 if Type == TAB_VOID:\r
47fea6af 1290 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
f51461c8 1291 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
d5988a8a 1292 or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))\r
f51461c8
LG
1293 ):\r
1294 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
d5988a8a 1295 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)\r
f51461c8
LG
1296 elif ValueRe.match(Value):\r
1297 # Check the chars in UnicodeString or CString is printable\r
1298 if Value.startswith("L"):\r
1299 Value = Value[2:-1]\r
1300 else:\r
1301 Value = Value[1:-1]\r
1302 Printset = set(string.printable)\r
1303 Printset.remove(TAB_PRINTCHAR_VT)\r
1304 Printset.add(TAB_PRINTCHAR_BS)\r
1305 Printset.add(TAB_PRINTCHAR_NUL)\r
1306 if not set(Value).issubset(Printset):\r
0d1f5b2b 1307 PrintList = sorted(Printset)\r
f51461c8
LG
1308 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1309 elif Type == 'BOOLEAN':\r
1310 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1311 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1312 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1313 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
94c91295 1314 if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):\r
1590d123 1315 Value = Value.lstrip('0')\r
f51461c8 1316 try:\r
1590d123
ZF
1317 if Value and int(Value, 0) < 0:\r
1318 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value, Type)\r
af881abc 1319 Value = int(Value, 0)\r
1ccc4d89
LG
1320 if Value > MAX_VAL_TYPE[Type]:\r
1321 return False, "Too large PCD value[%s] for datum type [%s]" % (Value, Type)\r
f51461c8 1322 except:\r
1ccc4d89
LG
1323 return False, "Invalid value [%s] of type [%s];"\\r
1324 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
f51461c8 1325 else:\r
ae7b6df8 1326 return True, "StructurePcd"\r
f51461c8
LG
1327\r
1328 return True, ""\r
1329\r
f51461c8
LG
1330def CommonPath(PathList):\r
1331 P1 = min(PathList).split(os.path.sep)\r
1332 P2 = max(PathList).split(os.path.sep)\r
e77e59c9 1333 for Index in range(min(len(P1), len(P2))):\r
f51461c8
LG
1334 if P1[Index] != P2[Index]:\r
1335 return os.path.sep.join(P1[:Index])\r
1336 return os.path.sep.join(P1)\r
1337\r
1338class PathClass(object):\r
1339 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1340 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1341 self.Arch = Arch\r
1342 self.File = str(File)\r
1343 if os.path.isabs(self.File):\r
1344 self.Root = ''\r
1345 self.AlterRoot = ''\r
1346 else:\r
1347 self.Root = str(Root)\r
1348 self.AlterRoot = str(AlterRoot)\r
1349\r
1350 # Remove any '.' and '..' in path\r
1351 if self.Root:\r
05cc51ad 1352 self.Root = mws.getWs(self.Root, self.File)\r
f51461c8
LG
1353 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1354 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1355 # eliminate the side-effect of 'C:'\r
1356 if self.Root[-1] == ':':\r
1357 self.Root += os.path.sep\r
1358 # file path should not start with path separator\r
1359 if self.Root[-1] == os.path.sep:\r
1360 self.File = self.Path[len(self.Root):]\r
1361 else:\r
47fea6af 1362 self.File = self.Path[len(self.Root) + 1:]\r
f51461c8
LG
1363 else:\r
1364 self.Path = os.path.normpath(self.File)\r
1365\r
1366 self.SubDir, self.Name = os.path.split(self.File)\r
1367 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1368\r
1369 if self.Root:\r
1370 if self.SubDir:\r
1371 self.Dir = os.path.join(self.Root, self.SubDir)\r
1372 else:\r
1373 self.Dir = self.Root\r
1374 else:\r
1375 self.Dir = self.SubDir\r
1376\r
1377 if IsBinary:\r
1378 self.Type = Type\r
1379 else:\r
1380 self.Type = self.Ext.lower()\r
1381\r
1382 self.IsBinary = IsBinary\r
1383 self.Target = Target\r
1384 self.TagName = TagName\r
1385 self.ToolCode = ToolCode\r
1386 self.ToolChainFamily = ToolChainFamily\r
1387\r
f51461c8
LG
1388 ## Convert the object of this class to a string\r
1389 #\r
1390 # Convert member Path of the class to a string\r
1391 #\r
1392 # @retval string Formatted String\r
1393 #\r
1394 def __str__(self):\r
1395 return self.Path\r
1396\r
1397 ## Override __eq__ function\r
1398 #\r
1399 # Check whether PathClass are the same\r
1400 #\r
1401 # @retval False The two PathClass are different\r
1402 # @retval True The two PathClass are the same\r
1403 #\r
1404 def __eq__(self, Other):\r
4e375707 1405 return self.Path == str(Other)\r
f51461c8
LG
1406\r
1407 ## Override __cmp__ function\r
1408 #\r
1409 # Customize the comparsion operation of two PathClass\r
1410 #\r
1411 # @retval 0 The two PathClass are different\r
1412 # @retval -1 The first PathClass is less than the second PathClass\r
1413 # @retval 1 The first PathClass is Bigger than the second PathClass\r
1414 def __cmp__(self, Other):\r
4e375707 1415 OtherKey = str(Other)\r
f7496d71 1416\r
f51461c8
LG
1417 SelfKey = self.Path\r
1418 if SelfKey == OtherKey:\r
1419 return 0\r
1420 elif SelfKey > OtherKey:\r
1421 return 1\r
1422 else:\r
1423 return -1\r
1424\r
1425 ## Override __hash__ function\r
1426 #\r
1427 # Use Path as key in hash table\r
1428 #\r
1429 # @retval string Key for hash table\r
1430 #\r
1431 def __hash__(self):\r
1432 return hash(self.Path)\r
1433\r
6c204ed4
CJ
1434 @cached_property\r
1435 def Key(self):\r
1436 return self.Path.upper()\r
f51461c8 1437\r
6c204ed4
CJ
1438 @property\r
1439 def TimeStamp(self):\r
f51461c8
LG
1440 return os.stat(self.Path)[8]\r
1441\r
1442 def Validate(self, Type='', CaseSensitive=True):\r
42bd1750
CJ
1443 def RealPath2(File, Dir='', OverrideDir=''):\r
1444 NewFile = None\r
1445 if OverrideDir:\r
1446 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
1447 if NewFile:\r
1448 if OverrideDir[-1] == os.path.sep:\r
1449 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
1450 else:\r
1451 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]\r
1452 if GlobalData.gAllFiles:\r
1453 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]\r
1454 if not NewFile:\r
1455 NewFile = os.path.normpath(os.path.join(Dir, File))\r
1456 if not os.path.exists(NewFile):\r
1457 return None, None\r
1458 if NewFile:\r
1459 if Dir:\r
1460 if Dir[-1] == os.path.sep:\r
1461 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
1462 else:\r
1463 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
1464 else:\r
1465 return NewFile, ''\r
1466\r
1467 return None, None\r
1468\r
f51461c8
LG
1469 if GlobalData.gCaseInsensitive:\r
1470 CaseSensitive = False\r
1471 if Type and Type.lower() != self.Type:\r
1472 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
1473\r
1474 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
1475 if not RealRoot and not RealFile:\r
1476 RealFile = self.File\r
1477 if self.AlterRoot:\r
1478 RealFile = os.path.join(self.AlterRoot, self.File)\r
1479 elif self.Root:\r
1480 RealFile = os.path.join(self.Root, self.File)\r
05cc51ad
LY
1481 if len (mws.getPkgPath()) == 0:\r
1482 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
1483 else:\r
1484 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
f51461c8
LG
1485\r
1486 ErrorCode = 0\r
1487 ErrorInfo = ''\r
1488 if RealRoot != self.Root or RealFile != self.File:\r
1489 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
1490 ErrorCode = FILE_CASE_MISMATCH\r
1491 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
1492\r
1493 self.SubDir, self.Name = os.path.split(RealFile)\r
1494 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1495 if self.SubDir:\r
1496 self.Dir = os.path.join(RealRoot, self.SubDir)\r
1497 else:\r
1498 self.Dir = RealRoot\r
1499 self.File = RealFile\r
1500 self.Root = RealRoot\r
1501 self.Path = os.path.join(RealRoot, RealFile)\r
1502 return ErrorCode, ErrorInfo\r
1503\r
f51461c8
LG
1504## Parse PE image to get the required PE informaion.\r
1505#\r
1506class PeImageClass():\r
1507 ## Constructor\r
1508 #\r
1509 # @param File FilePath of PeImage\r
1510 #\r
1511 def __init__(self, PeFile):\r
1512 self.FileName = PeFile\r
1513 self.IsValid = False\r
1514 self.Size = 0\r
1515 self.EntryPoint = 0\r
1516 self.SectionAlignment = 0\r
1517 self.SectionHeaderList = []\r
1518 self.ErrorInfo = ''\r
1519 try:\r
1520 PeObject = open(PeFile, 'rb')\r
1521 except:\r
1522 self.ErrorInfo = self.FileName + ' can not be found\n'\r
1523 return\r
1524 # Read DOS header\r
1525 ByteArray = array.array('B')\r
1526 ByteArray.fromfile(PeObject, 0x3E)\r
1527 ByteList = ByteArray.tolist()\r
1528 # DOS signature should be 'MZ'\r
1529 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
1530 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
1531 return\r
1532\r
1533 # Read 4 byte PE Signature\r
1534 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
1535 PeObject.seek(PeOffset)\r
1536 ByteArray = array.array('B')\r
1537 ByteArray.fromfile(PeObject, 4)\r
1538 # PE signature should be 'PE\0\0'\r
1ccc4d89 1539 if ByteArray.tostring() != 'PE\0\0':\r
f51461c8
LG
1540 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
1541 return\r
1542\r
1543 # Read PE file header\r
1544 ByteArray = array.array('B')\r
1545 ByteArray.fromfile(PeObject, 0x14)\r
1546 ByteList = ByteArray.tolist()\r
1547 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
1548 if SecNumber == 0:\r
1549 self.ErrorInfo = self.FileName + ' has no section header'\r
1550 return\r
1551\r
1552 # Read PE optional header\r
1553 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
1554 ByteArray = array.array('B')\r
1555 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
1556 ByteList = ByteArray.tolist()\r
1557 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
1558 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
1559 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
1560\r
1561 # Read each Section Header\r
1562 for Index in range(SecNumber):\r
1563 ByteArray = array.array('B')\r
1564 ByteArray.fromfile(PeObject, 0x28)\r
1565 ByteList = ByteArray.tolist()\r
1566 SecName = self._ByteListToStr(ByteList[0:8])\r
1567 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
1568 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
1569 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
1570 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
1571 self.IsValid = True\r
1572 PeObject.close()\r
1573\r
1574 def _ByteListToStr(self, ByteList):\r
1575 String = ''\r
1576 for index in range(len(ByteList)):\r
f7496d71 1577 if ByteList[index] == 0:\r
f51461c8
LG
1578 break\r
1579 String += chr(ByteList[index])\r
1580 return String\r
1581\r
1582 def _ByteListToInt(self, ByteList):\r
1583 Value = 0\r
1584 for index in range(len(ByteList) - 1, -1, -1):\r
1585 Value = (Value << 8) | int(ByteList[index])\r
1586 return Value\r
1587\r
8518bf0b 1588class DefaultStore():\r
ccaa7754 1589 def __init__(self, DefaultStores ):\r
8518bf0b
LG
1590\r
1591 self.DefaultStores = DefaultStores\r
ccaa7754
GL
1592 def DefaultStoreID(self, DefaultStoreName):\r
1593 for key, value in self.DefaultStores.items():\r
8518bf0b
LG
1594 if value == DefaultStoreName:\r
1595 return key\r
1596 return None\r
1597 def GetDefaultDefault(self):\r
1598 if not self.DefaultStores or "0" in self.DefaultStores:\r
ccaa7754 1599 return "0", TAB_DEFAULT_STORES_DEFAULT\r
8518bf0b 1600 else:\r
8252e6bf 1601 minvalue = min(int(value_str) for value_str in self.DefaultStores)\r
8518bf0b 1602 return (str(minvalue), self.DefaultStores[str(minvalue)])\r
ccaa7754 1603 def GetMin(self, DefaultSIdList):\r
8518bf0b 1604 if not DefaultSIdList:\r
4d3b9389 1605 return TAB_DEFAULT_STORES_DEFAULT\r
2b8a6c44
LG
1606 storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}\r
1607 if not storeidset:\r
1608 return ""\r
1609 minid = min(storeidset )\r
ccaa7754 1610 for sid, name in self.DefaultStores.values():\r
8518bf0b
LG
1611 if sid == minid:\r
1612 return name\r
f7496d71 1613\r
6c204ed4 1614class SkuClass():\r
f51461c8
LG
1615 DEFAULT = 0\r
1616 SINGLE = 1\r
1617 MULTIPLE =2\r
f7496d71 1618\r
8518bf0b
LG
1619 def __init__(self,SkuIdentifier='', SkuIds=None):\r
1620 if SkuIds is None:\r
1621 SkuIds = {}\r
c05c2c05
LG
1622\r
1623 for SkuName in SkuIds:\r
1624 SkuId = SkuIds[SkuName][0]\r
ccaa7754 1625 skuid_num = int(SkuId, 16) if SkuId.upper().startswith("0X") else int(SkuId)\r
e4ff28c3 1626 if skuid_num > 0xFFFFFFFFFFFFFFFF:\r
c05c2c05 1627 EdkLogger.error("build", PARAMETER_INVALID,\r
e4ff28c3
LG
1628 ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"\r
1629 % (SkuName, SkuId))\r
f7496d71 1630\r
f56c83f8 1631 self.AvailableSkuIds = OrderedDict()\r
f51461c8 1632 self.SkuIdSet = []\r
1ae469b9 1633 self.SkuIdNumberSet = []\r
8518bf0b 1634 self.SkuData = SkuIds\r
6c204ed4
CJ
1635 self._SkuInherit = {}\r
1636 self._SkuIdentifier = SkuIdentifier\r
f51461c8
LG
1637 if SkuIdentifier == '' or SkuIdentifier is None:\r
1638 self.SkuIdSet = ['DEFAULT']\r
1ae469b9 1639 self.SkuIdNumberSet = ['0U']\r
f51461c8 1640 elif SkuIdentifier == 'ALL':\r
f8d11e5a 1641 self.SkuIdSet = list(SkuIds.keys())\r
8518bf0b 1642 self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]\r
f51461c8 1643 else:\r
f7496d71 1644 r = SkuIdentifier.split('|')\r
8518bf0b 1645 self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]\r
1ae469b9 1646 k = None\r
f7496d71 1647 try:\r
8518bf0b 1648 self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]\r
1ae469b9
BF
1649 except Exception:\r
1650 EdkLogger.error("build", PARAMETER_INVALID,\r
1651 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1652 % (k, " | ".join(SkuIds.keys())))\r
f51461c8
LG
1653 for each in self.SkuIdSet:\r
1654 if each in SkuIds:\r
8518bf0b 1655 self.AvailableSkuIds[each] = SkuIds[each][0]\r
f51461c8
LG
1656 else:\r
1657 EdkLogger.error("build", PARAMETER_INVALID,\r
1658 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1659 % (each, " | ".join(SkuIds.keys())))\r
6c204ed4 1660 if self.SkuUsageType != SkuClass.SINGLE:\r
8518bf0b 1661 self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})\r
e651d06c
LG
1662 if self.SkuIdSet:\r
1663 GlobalData.gSkuids = (self.SkuIdSet)\r
1664 if 'COMMON' in GlobalData.gSkuids:\r
1665 GlobalData.gSkuids.remove('COMMON')\r
8aaa8f7b
YZ
1666 if self.SkuUsageType == self.SINGLE:\r
1667 if len(GlobalData.gSkuids) != 1:\r
1668 if 'DEFAULT' in GlobalData.gSkuids:\r
1669 GlobalData.gSkuids.remove('DEFAULT')\r
e651d06c
LG
1670 if GlobalData.gSkuids:\r
1671 GlobalData.gSkuids.sort()\r
1672\r
8518bf0b 1673 def GetNextSkuId(self, skuname):\r
6c204ed4
CJ
1674 if not self._SkuInherit:\r
1675 self._SkuInherit = {}\r
8518bf0b 1676 for item in self.SkuData.values():\r
6c204ed4
CJ
1677 self._SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"\r
1678 return self._SkuInherit.get(skuname, "DEFAULT")\r
c05c2c05 1679\r
ccaa7754 1680 def GetSkuChain(self, sku):\r
09c80b07
B
1681 if sku == "DEFAULT":\r
1682 return ["DEFAULT"]\r
c05c2c05
LG
1683 skulist = [sku]\r
1684 nextsku = sku\r
0d1f5b2b 1685 while True:\r
c05c2c05
LG
1686 nextsku = self.GetNextSkuId(nextsku)\r
1687 skulist.append(nextsku)\r
1688 if nextsku == "DEFAULT":\r
1689 break\r
1690 skulist.reverse()\r
1691 return skulist\r
1692 def SkuOverrideOrder(self):\r
1693 skuorderset = []\r
1694 for skuname in self.SkuIdSet:\r
1695 skuorderset.append(self.GetSkuChain(skuname))\r
f7496d71 1696\r
c05c2c05 1697 skuorder = []\r
8252e6bf 1698 for index in range(max(len(item) for item in skuorderset)):\r
c05c2c05
LG
1699 for subset in skuorderset:\r
1700 if index > len(subset)-1:\r
1701 continue\r
1702 if subset[index] in skuorder:\r
1703 continue\r
1704 skuorder.append(subset[index])\r
1705\r
1706 return skuorder\r
1707\r
6c204ed4
CJ
1708 @property\r
1709 def SkuUsageType(self):\r
1710 if self._SkuIdentifier.upper() == "ALL":\r
c05c2c05
LG
1711 return SkuClass.MULTIPLE\r
1712\r
f51461c8
LG
1713 if len(self.SkuIdSet) == 1:\r
1714 if self.SkuIdSet[0] == 'DEFAULT':\r
1715 return SkuClass.DEFAULT\r
6c204ed4
CJ
1716 return SkuClass.SINGLE\r
1717 if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet:\r
1718 return SkuClass.SINGLE\r
1719 return SkuClass.MULTIPLE\r
f51461c8 1720\r
6c204ed4 1721 def DumpSkuIdArrary(self):\r
8518bf0b 1722 if self.SkuUsageType == SkuClass.SINGLE:\r
6c204ed4
CJ
1723 return "{0x0}"\r
1724 ArrayStrList = []\r
1725 for skuname in self.AvailableSkuIds:\r
1726 if skuname == "COMMON":\r
1727 continue\r
1728 while skuname != "DEFAULT":\r
1729 ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))\r
1730 skuname = self.GetNextSkuId(skuname)\r
1731 ArrayStrList.append("0x0")\r
1732 return "{{{myList}}}".format(myList=",".join(ArrayStrList))\r
1733\r
1734 @property\r
1735 def AvailableSkuIdSet(self):\r
f51461c8 1736 return self.AvailableSkuIds\r
f7496d71 1737\r
6c204ed4
CJ
1738 @property\r
1739 def SystemSkuId(self):\r
1740 if self.SkuUsageType == SkuClass.SINGLE:\r
c05c2c05
LG
1741 if len(self.SkuIdSet) == 1:\r
1742 return self.SkuIdSet[0]\r
1743 else:\r
1744 return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]\r
f51461c8
LG
1745 else:\r
1746 return 'DEFAULT'\r
a3251d84 1747\r
34952f49
LG
1748## Get the integer value from string like "14U" or integer like 2\r
1749#\r
1750# @param Input The object that may be either a integer value or a string\r
1751#\r
1752# @retval Value The integer value that the input represents\r
1753#\r
1754def GetIntegerValue(Input):\r
1ccc4d89 1755 if type(Input) in (int, long):\r
34952f49
LG
1756 return Input\r
1757 String = Input\r
1758 if String.endswith("U"):\r
1759 String = String[:-1]\r
1760 if String.endswith("ULL"):\r
1761 String = String[:-3]\r
1762 if String.endswith("LL"):\r
1763 String = String[:-2]\r
1764\r
1765 if String.startswith("0x") or String.startswith("0X"):\r
1766 return int(String, 16)\r
1767 elif String == '':\r
1768 return 0\r
1769 else:\r
1770 return int(String)\r
db55dac7 1771\r
d0a0c52c
CJ
1772#\r
1773# Pack a GUID (registry format) list into a buffer and return it\r
1774#\r
1775def PackGUID(Guid):\r
1776 return pack(PACK_PATTERN_GUID,\r
1777 int(Guid[0], 16),\r
1778 int(Guid[1], 16),\r
1779 int(Guid[2], 16),\r
1780 int(Guid[3][-4:-2], 16),\r
1781 int(Guid[3][-2:], 16),\r
1782 int(Guid[4][-12:-10], 16),\r
1783 int(Guid[4][-10:-8], 16),\r
1784 int(Guid[4][-8:-6], 16),\r
1785 int(Guid[4][-6:-4], 16),\r
1786 int(Guid[4][-4:-2], 16),\r
1787 int(Guid[4][-2:], 16)\r
1788 )\r
1789\r
1790#\r
1791# Pack a GUID (byte) list into a buffer and return it\r
1792#\r
1793def PackByteFormatGUID(Guid):\r
1794 return pack(PACK_PATTERN_GUID,\r
1795 Guid[0],\r
1796 Guid[1],\r
1797 Guid[2],\r
1798 Guid[3],\r
1799 Guid[4],\r
1800 Guid[5],\r
1801 Guid[6],\r
1802 Guid[7],\r
1803 Guid[8],\r
1804 Guid[9],\r
1805 Guid[10],\r
1806 )\r
1807\r
bf9e6366
B
1808## DeepCopy dict/OrderedDict recusively\r
1809#\r
1810# @param ori_dict a nested dict or ordereddict\r
1811#\r
1812# @retval new dict or orderdict\r
1813#\r
1814def CopyDict(ori_dict):\r
1815 dict_type = ori_dict.__class__\r
9bf86b12
FB
1816 if dict_type not in (dict,OrderedDict):\r
1817 return ori_dict\r
bf9e6366
B
1818 new_dict = dict_type()\r
1819 for key in ori_dict:\r
1820 if isinstance(ori_dict[key],(dict,OrderedDict)):\r
1821 new_dict[key] = CopyDict(ori_dict[key])\r
1822 else:\r
1823 new_dict[key] = ori_dict[key]\r
1824 return new_dict\r
4c6e6f9f
FB
1825\r
1826#\r
1827# Remove the c/c++ comments: // and /* */\r
1828#\r
1829def RemoveCComments(ctext):\r
1830 return re.sub('//.*?\n|/\*.*?\*/', '\n', ctext, flags=re.S)\r