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