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