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