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