]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
BaseTools: Add map file parsing support for CLANG9
[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
43 ArrayIndex = re.compile("\[\s*[0-9a-fA-FxX]*\s*\]")
44 ## Regular expression used to find out place holders in string template
45 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)
46
47 ## regular expressions for map file processing
48 startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
49 addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
50 valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
51 pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
52 secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)
53
54 StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$')
55
56 ## Dictionary used to store dependencies of files
57 gDependencyDatabase = {} # arch : {file path : [dependent files list]}
58
59 #
60 # If a module is built more than once with different PCDs or library classes
61 # a temporary INF file with same content is created, the temporary file is removed
62 # when build exits.
63 #
64 _TempInfs = []
65
66 def GetVariableOffset(mapfilepath, efifilepath, varnames):
67 """ Parse map file to get variable offset in current EFI file
68 @param mapfilepath Map file absolution path
69 @param efifilepath: EFI binary file full path
70 @param varnames iteratable container whose elements are variable names to be searched
71
72 @return List whos elements are tuple with variable name and raw offset
73 """
74 lines = []
75 try:
76 f = open(mapfilepath, 'r')
77 lines = f.readlines()
78 f.close()
79 except:
80 return None
81
82 if len(lines) == 0: return None
83 firstline = lines[0].strip()
84 if re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', firstline):
85 return _parseForXcodeAndClang9(lines, efifilepath, varnames)
86 if (firstline.startswith("Archive member included ") and
87 firstline.endswith(" file (symbol)")):
88 return _parseForGCC(lines, efifilepath, varnames)
89 if firstline.startswith("# Path:"):
90 return _parseForXcodeAndClang9(lines, efifilepath, varnames)
91 return _parseGeneral(lines, efifilepath, varnames)
92
93 def _parseForXcodeAndClang9(lines, efifilepath, varnames):
94 status = 0
95 ret = []
96 for line in lines:
97 line = line.strip()
98 if status == 0 and (re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', line) \
99 or line == "# Symbols:"):
100 status = 1
101 continue
102 if status == 1 and len(line) != 0:
103 for varname in varnames:
104 if varname in line:
105 # cannot pregenerate this RegEx since it uses varname from varnames.
106 m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)
107 if m is not None:
108 ret.append((varname, m.group(1)))
109 return ret
110
111 def _parseForGCC(lines, efifilepath, varnames):
112 """ Parse map file generated by GCC linker """
113 status = 0
114 sections = []
115 varoffset = []
116 for index, line in enumerate(lines):
117 line = line.strip()
118 # status machine transection
119 if status == 0 and line == "Memory Configuration":
120 status = 1
121 continue
122 elif status == 1 and line == 'Linker script and memory map':
123 status = 2
124 continue
125 elif status ==2 and line == 'START GROUP':
126 status = 3
127 continue
128
129 # status handler
130 if status == 3:
131 m = valuePatternGcc.match(line)
132 if m is not None:
133 sections.append(m.groups(0))
134 for varname in varnames:
135 Str = ''
136 m = re.match("^.data.(%s)" % varname, line)
137 if m is not None:
138 m = re.match(".data.(%s)$" % varname, line)
139 if m is not None:
140 Str = lines[index + 1]
141 else:
142 Str = line[len(".data.%s" % varname):]
143 if Str:
144 m = pcdPatternGcc.match(Str.strip())
145 if m is not None:
146 varoffset.append((varname, int(m.groups(0)[0], 16), int(sections[-1][1], 16), sections[-1][0]))
147
148 if not varoffset:
149 return []
150 # get section information from efi file
151 efisecs = PeImageClass(efifilepath).SectionHeaderList
152 if efisecs is None or len(efisecs) == 0:
153 return []
154 #redirection
155 redirection = 0
156 for efisec in efisecs:
157 for section in sections:
158 if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':
159 redirection = int(section[1], 16) - efisec[1]
160
161 ret = []
162 for var in varoffset:
163 for efisec in efisecs:
164 if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:
165 ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))
166 return ret
167
168 def _parseGeneral(lines, efifilepath, varnames):
169 status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
170 secs = [] # key = section name
171 varoffset = []
172 symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$-]+) +([\da-fA-F]+)', re.UNICODE)
173
174 for line in lines:
175 line = line.strip()
176 if startPatternGeneral.match(line):
177 status = 1
178 continue
179 if addressPatternGeneral.match(line):
180 status = 2
181 continue
182 if line.startswith("entry point at"):
183 status = 3
184 continue
185 if status == 1 and len(line) != 0:
186 m = secReGeneral.match(line)
187 assert m is not None, "Fail to parse the section in map file , line is %s" % line
188 sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)
189 secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])
190 if status == 2 and len(line) != 0:
191 for varname in varnames:
192 m = symRe.match(line)
193 assert m is not None, "Fail to parse the symbol in map file, line is %s" % line
194 sec_no, sym_offset, sym_name, vir_addr = m.groups(0)
195 sec_no = int(sec_no, 16)
196 sym_offset = int(sym_offset, 16)
197 vir_addr = int(vir_addr, 16)
198 # cannot pregenerate this RegEx since it uses varname from varnames.
199 m2 = re.match('^[_]*(%s)' % varname, sym_name)
200 if m2 is not None:
201 # fond a binary pcd entry in map file
202 for sec in secs:
203 if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):
204 varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])
205
206 if not varoffset: return []
207
208 # get section information from efi file
209 efisecs = PeImageClass(efifilepath).SectionHeaderList
210 if efisecs is None or len(efisecs) == 0:
211 return []
212
213 ret = []
214 for var in varoffset:
215 index = 0
216 for efisec in efisecs:
217 index = index + 1
218 if var[1].strip() == efisec[0].strip():
219 ret.append((var[0], hex(efisec[2] + var[2])))
220 elif var[4] == index:
221 ret.append((var[0], hex(efisec[2] + var[2])))
222
223 return ret
224
225 ## Routine to process duplicated INF
226 #
227 # This function is called by following two cases:
228 # Case 1 in DSC:
229 # [components.arch]
230 # Pkg/module/module.inf
231 # Pkg/module/module.inf {
232 # <Defines>
233 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
234 # }
235 # Case 2 in FDF:
236 # INF Pkg/module/module.inf
237 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
238 #
239 # This function copies Pkg/module/module.inf to
240 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
241 #
242 # @param Path Original PathClass object
243 # @param BaseName New file base name
244 #
245 # @retval return the new PathClass object
246 #
247 def ProcessDuplicatedInf(Path, BaseName, Workspace):
248 Filename = os.path.split(Path.File)[1]
249 if '.' in Filename:
250 Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]
251 else:
252 Filename = BaseName + Path.BaseName
253
254 DbDir = os.path.split(GlobalData.gDatabasePath)[0]
255
256 #
257 # A temporary INF is copied to database path which must have write permission
258 # The temporary will be removed at the end of build
259 # In case of name conflict, the file name is
260 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
261 #
262 TempFullPath = os.path.join(DbDir,
263 Filename)
264 RtPath = PathClass(Path.File, Workspace)
265 #
266 # Modify the full path to temporary path, keep other unchanged
267 #
268 # To build same module more than once, the module path with FILE_GUID overridden has
269 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
270 # in DSC which is used as relative path by C files and other files in INF.
271 # A trick was used: all module paths are PathClass instances, after the initialization
272 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
273 #
274 # The reason for creating a temporary INF is:
275 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
276 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
277 # A different key for the same module is needed to create different output directory,
278 # retrieve overridden PCDs, library instances.
279 #
280 # The BaseName is the FILE_GUID which is also the output directory name.
281 #
282 #
283 RtPath.Path = TempFullPath
284 RtPath.BaseName = BaseName
285 RtPath.OriginalPath = Path
286 #
287 # If file exists, compare contents
288 #
289 if os.path.exists(TempFullPath):
290 with open(str(Path), 'rb') as f1, open(TempFullPath, 'rb') as f2:
291 if f1.read() == f2.read():
292 return RtPath
293 _TempInfs.append(TempFullPath)
294 shutil.copy2(str(Path), TempFullPath)
295 return RtPath
296
297 ## Remove temporary created INFs whose paths were saved in _TempInfs
298 #
299 def ClearDuplicatedInf():
300 while _TempInfs:
301 File = _TempInfs.pop()
302 if os.path.exists(File):
303 os.remove(File)
304
305 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
306 #
307 # @param Guid The GUID string
308 #
309 # @retval string The GUID string in C structure style
310 #
311 def GuidStringToGuidStructureString(Guid):
312 GuidList = Guid.split('-')
313 Result = '{'
314 for Index in range(0, 3, 1):
315 Result = Result + '0x' + GuidList[Index] + ', '
316 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
317 for Index in range(0, 12, 2):
318 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
319 Result += '}}'
320 return Result
321
322 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
323 #
324 # @param GuidValue The GUID value in byte array
325 #
326 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
327 #
328 def GuidStructureByteArrayToGuidString(GuidValue):
329 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
330 guidValueList = guidValueString.split(",")
331 if len(guidValueList) != 16:
332 return ''
333 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
334 try:
335 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
336 int(guidValueList[3], 16),
337 int(guidValueList[2], 16),
338 int(guidValueList[1], 16),
339 int(guidValueList[0], 16),
340 int(guidValueList[5], 16),
341 int(guidValueList[4], 16),
342 int(guidValueList[7], 16),
343 int(guidValueList[6], 16),
344 int(guidValueList[8], 16),
345 int(guidValueList[9], 16),
346 int(guidValueList[10], 16),
347 int(guidValueList[11], 16),
348 int(guidValueList[12], 16),
349 int(guidValueList[13], 16),
350 int(guidValueList[14], 16),
351 int(guidValueList[15], 16)
352 )
353 except:
354 return ''
355
356 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
357 #
358 # @param GuidValue The GUID value in C structure format
359 #
360 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
361 #
362 def GuidStructureStringToGuidString(GuidValue):
363 if not GlobalData.gGuidCFormatPattern.match(GuidValue):
364 return ''
365 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
366 guidValueList = guidValueString.split(",")
367 if len(guidValueList) != 11:
368 return ''
369 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
370 try:
371 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
372 int(guidValueList[0], 16),
373 int(guidValueList[1], 16),
374 int(guidValueList[2], 16),
375 int(guidValueList[3], 16),
376 int(guidValueList[4], 16),
377 int(guidValueList[5], 16),
378 int(guidValueList[6], 16),
379 int(guidValueList[7], 16),
380 int(guidValueList[8], 16),
381 int(guidValueList[9], 16),
382 int(guidValueList[10], 16)
383 )
384 except:
385 return ''
386
387 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
388 #
389 # @param GuidValue The GUID value in C structure format
390 #
391 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
392 #
393 def GuidStructureStringToGuidValueName(GuidValue):
394 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
395 guidValueList = guidValueString.split(",")
396 if len(guidValueList) != 11:
397 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)
398 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
399 int(guidValueList[0], 16),
400 int(guidValueList[1], 16),
401 int(guidValueList[2], 16),
402 int(guidValueList[3], 16),
403 int(guidValueList[4], 16),
404 int(guidValueList[5], 16),
405 int(guidValueList[6], 16),
406 int(guidValueList[7], 16),
407 int(guidValueList[8], 16),
408 int(guidValueList[9], 16),
409 int(guidValueList[10], 16)
410 )
411
412 ## Create directories
413 #
414 # @param Directory The directory name
415 #
416 def CreateDirectory(Directory):
417 if Directory is None or Directory.strip() == "":
418 return True
419 try:
420 if not os.access(Directory, os.F_OK):
421 os.makedirs(Directory)
422 except:
423 return False
424 return True
425
426 ## Remove directories, including files and sub-directories in it
427 #
428 # @param Directory The directory name
429 #
430 def RemoveDirectory(Directory, Recursively=False):
431 if Directory is None or Directory.strip() == "" or not os.path.exists(Directory):
432 return
433 if Recursively:
434 CurrentDirectory = os.getcwd()
435 os.chdir(Directory)
436 for File in os.listdir("."):
437 if os.path.isdir(File):
438 RemoveDirectory(File, Recursively)
439 else:
440 os.remove(File)
441 os.chdir(CurrentDirectory)
442 os.rmdir(Directory)
443
444 ## Store content in file
445 #
446 # This method is used to save file only when its content is changed. This is
447 # quite useful for "make" system to decide what will be re-built and what won't.
448 #
449 # @param File The path of file
450 # @param Content The new content of the file
451 # @param IsBinaryFile The flag indicating if the file is binary file or not
452 #
453 # @retval True If the file content is changed and the file is renewed
454 # @retval False If the file content is the same
455 #
456 def SaveFileOnChange(File, Content, IsBinaryFile=True, FileLock=None):
457
458 # Convert to long file path format
459 File = LongFilePath(File)
460
461 if os.path.exists(File):
462 if IsBinaryFile:
463 try:
464 with open(File, "rb") as f:
465 if Content == f.read():
466 return False
467 except:
468 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
469 else:
470 try:
471 with open(File, "r") as f:
472 if Content == f.read():
473 return False
474 except:
475 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
476
477 DirName = os.path.dirname(File)
478 if not CreateDirectory(DirName):
479 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
480 else:
481 if DirName == '':
482 DirName = os.getcwd()
483 if not os.access(DirName, os.W_OK):
484 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
485
486 OpenMode = "w"
487 if IsBinaryFile:
488 OpenMode = "wb"
489
490 # use default file_lock if no input new lock
491 if not FileLock:
492 FileLock = GlobalData.file_lock
493 if FileLock:
494 FileLock.acquire()
495
496
497 if GlobalData.gIsWindows and not os.path.exists(File):
498 try:
499 with open(File, OpenMode) as tf:
500 tf.write(Content)
501 except IOError as X:
502 if GlobalData.gBinCacheSource:
503 EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))
504 else:
505 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)
506 finally:
507 if FileLock:
508 FileLock.release()
509 else:
510 try:
511 with open(File, OpenMode) as Fd:
512 Fd.write(Content)
513 except IOError as X:
514 if GlobalData.gBinCacheSource:
515 EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))
516 else:
517 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)
518 finally:
519 if FileLock:
520 FileLock.release()
521
522 return True
523
524 ## Copy source file only if it is different from the destination file
525 #
526 # This method is used to copy file only if the source file and destination
527 # file content are different. This is quite useful to avoid duplicated
528 # file writing.
529 #
530 # @param SrcFile The path of source file
531 # @param Dst The path of destination file or folder
532 #
533 # @retval True The two files content are different and the file is copied
534 # @retval False No copy really happen
535 #
536 def CopyFileOnChange(SrcFile, Dst, FileLock=None):
537
538 # Convert to long file path format
539 SrcFile = LongFilePath(SrcFile)
540 Dst = LongFilePath(Dst)
541
542 if os.path.isdir(SrcFile):
543 EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='CopyFileOnChange SrcFile is a dir, not a file: %s' % SrcFile)
544 return False
545
546 if os.path.isdir(Dst):
547 DstFile = os.path.join(Dst, os.path.basename(SrcFile))
548 else:
549 DstFile = Dst
550
551 if os.path.exists(DstFile) and filecmp.cmp(SrcFile, DstFile, shallow=False):
552 return False
553
554 DirName = os.path.dirname(DstFile)
555 if not CreateDirectory(DirName):
556 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
557 else:
558 if DirName == '':
559 DirName = os.getcwd()
560 if not os.access(DirName, os.W_OK):
561 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
562
563 # use default file_lock if no input new lock
564 if not FileLock:
565 FileLock = GlobalData.file_lock
566 if FileLock:
567 FileLock.acquire()
568
569 try:
570 CopyLong(SrcFile, DstFile)
571 except IOError as X:
572 if GlobalData.gBinCacheSource:
573 EdkLogger.quiet("[cache error]:fails to copy file with error: %s" % (X))
574 else:
575 EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='IOError %s' % X)
576 finally:
577 if FileLock:
578 FileLock.release()
579
580 return True
581
582 ## Retrieve and cache the real path name in file system
583 #
584 # @param Root The root directory of path relative to
585 #
586 # @retval str The path string if the path exists
587 # @retval None If path doesn't exist
588 #
589 class DirCache:
590 _CACHE_ = set()
591 _UPPER_CACHE_ = {}
592
593 def __init__(self, Root):
594 self._Root = Root
595 for F in os.listdir(Root):
596 self._CACHE_.add(F)
597 self._UPPER_CACHE_[F.upper()] = F
598
599 # =[] operator
600 def __getitem__(self, Path):
601 Path = Path[len(os.path.commonprefix([Path, self._Root])):]
602 if not Path:
603 return self._Root
604 if Path and Path[0] == os.path.sep:
605 Path = Path[1:]
606 if Path in self._CACHE_:
607 return os.path.join(self._Root, Path)
608 UpperPath = Path.upper()
609 if UpperPath in self._UPPER_CACHE_:
610 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
611
612 IndexList = []
613 LastSepIndex = -1
614 SepIndex = Path.find(os.path.sep)
615 while SepIndex > -1:
616 Parent = UpperPath[:SepIndex]
617 if Parent not in self._UPPER_CACHE_:
618 break
619 LastSepIndex = SepIndex
620 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
621
622 if LastSepIndex == -1:
623 return None
624
625 Cwd = os.getcwd()
626 os.chdir(self._Root)
627 SepIndex = LastSepIndex
628 while SepIndex > -1:
629 Parent = Path[:SepIndex]
630 ParentKey = UpperPath[:SepIndex]
631 if ParentKey not in self._UPPER_CACHE_:
632 os.chdir(Cwd)
633 return None
634
635 if Parent in self._CACHE_:
636 ParentDir = Parent
637 else:
638 ParentDir = self._UPPER_CACHE_[ParentKey]
639 for F in os.listdir(ParentDir):
640 Dir = os.path.join(ParentDir, F)
641 self._CACHE_.add(Dir)
642 self._UPPER_CACHE_[Dir.upper()] = Dir
643
644 SepIndex = Path.find(os.path.sep, SepIndex + 1)
645
646 os.chdir(Cwd)
647 if Path in self._CACHE_:
648 return os.path.join(self._Root, Path)
649 elif UpperPath in self._UPPER_CACHE_:
650 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
651 return None
652
653 def RealPath(File, Dir='', OverrideDir=''):
654 NewFile = os.path.normpath(os.path.join(Dir, File))
655 NewFile = GlobalData.gAllFiles[NewFile]
656 if not NewFile and OverrideDir:
657 NewFile = os.path.normpath(os.path.join(OverrideDir, File))
658 NewFile = GlobalData.gAllFiles[NewFile]
659 return NewFile
660
661 ## Get GUID value from given packages
662 #
663 # @param CName The CName of the GUID
664 # @param PackageList List of packages looking-up in
665 # @param Inffile The driver file
666 #
667 # @retval GuidValue if the CName is found in any given package
668 # @retval None if the CName is not found in all given packages
669 #
670 def GuidValue(CName, PackageList, Inffile = None):
671 for P in PackageList:
672 GuidKeys = list(P.Guids.keys())
673 if Inffile and P._PrivateGuids:
674 if not Inffile.startswith(P.MetaFile.Dir):
675 GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids]
676 if CName in GuidKeys:
677 return P.Guids[CName]
678 return None
679
680 ## A string template class
681 #
682 # This class implements a template for string replacement. A string template
683 # looks like following
684 #
685 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
686 #
687 # The string between ${BEGIN} and ${END} will be repeated as many times as the
688 # length of "placeholder_name", which is a list passed through a dict. The
689 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
690 # be not used and, in this case, the "placeholder_name" must not a list and it
691 # will just be replaced once.
692 #
693 class TemplateString(object):
694 _REPEAT_START_FLAG = "BEGIN"
695 _REPEAT_END_FLAG = "END"
696
697 class Section(object):
698 _LIST_TYPES = [type([]), type(set()), type((0,))]
699
700 def __init__(self, TemplateSection, PlaceHolderList):
701 self._Template = TemplateSection
702 self._PlaceHolderList = []
703
704 # Split the section into sub-sections according to the position of placeholders
705 if PlaceHolderList:
706 self._SubSectionList = []
707 SubSectionStart = 0
708 #
709 # The placeholders passed in must be in the format of
710 #
711 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
712 #
713 for PlaceHolder, Start, End in PlaceHolderList:
714 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
715 self._SubSectionList.append(TemplateSection[Start:End])
716 self._PlaceHolderList.append(PlaceHolder)
717 SubSectionStart = End
718 if SubSectionStart < len(TemplateSection):
719 self._SubSectionList.append(TemplateSection[SubSectionStart:])
720 else:
721 self._SubSectionList = [TemplateSection]
722
723 def __str__(self):
724 return self._Template + " : " + str(self._PlaceHolderList)
725
726 def Instantiate(self, PlaceHolderValues):
727 RepeatTime = -1
728 RepeatPlaceHolders = {}
729 NonRepeatPlaceHolders = {}
730
731 for PlaceHolder in self._PlaceHolderList:
732 if PlaceHolder not in PlaceHolderValues:
733 continue
734 Value = PlaceHolderValues[PlaceHolder]
735 if type(Value) in self._LIST_TYPES:
736 if RepeatTime < 0:
737 RepeatTime = len(Value)
738 elif RepeatTime != len(Value):
739 EdkLogger.error(
740 "TemplateString",
741 PARAMETER_INVALID,
742 "${%s} has different repeat time from others!" % PlaceHolder,
743 ExtraData=str(self._Template)
744 )
745 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
746 else:
747 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
748
749 if NonRepeatPlaceHolders:
750 StringList = []
751 for S in self._SubSectionList:
752 if S not in NonRepeatPlaceHolders:
753 StringList.append(S)
754 else:
755 StringList.append(str(NonRepeatPlaceHolders[S]))
756 else:
757 StringList = self._SubSectionList
758
759 if RepeatPlaceHolders:
760 TempStringList = []
761 for Index in range(RepeatTime):
762 for S in StringList:
763 if S not in RepeatPlaceHolders:
764 TempStringList.append(S)
765 else:
766 TempStringList.append(str(RepeatPlaceHolders[S][Index]))
767 StringList = TempStringList
768
769 return "".join(StringList)
770
771 ## Constructor
772 def __init__(self, Template=None):
773 self.String = []
774 self.IsBinary = False
775 self._Template = Template
776 self._TemplateSectionList = self._Parse(Template)
777
778 ## str() operator
779 #
780 # @retval string The string replaced
781 #
782 def __str__(self):
783 return "".join(self.String)
784
785 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
786 #
787 # @retval list A list of TemplateString.Section objects
788 #
789 def _Parse(self, Template):
790 SectionStart = 0
791 SearchFrom = 0
792 MatchEnd = 0
793 PlaceHolderList = []
794 TemplateSectionList = []
795 while Template:
796 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
797 if not MatchObj:
798 if MatchEnd <= len(Template):
799 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
800 TemplateSectionList.append(TemplateSection)
801 break
802
803 MatchString = MatchObj.group(1)
804 MatchStart = MatchObj.start()
805 MatchEnd = MatchObj.end()
806
807 if MatchString == self._REPEAT_START_FLAG:
808 if MatchStart > SectionStart:
809 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
810 TemplateSectionList.append(TemplateSection)
811 SectionStart = MatchEnd
812 PlaceHolderList = []
813 elif MatchString == self._REPEAT_END_FLAG:
814 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
815 TemplateSectionList.append(TemplateSection)
816 SectionStart = MatchEnd
817 PlaceHolderList = []
818 else:
819 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
820 SearchFrom = MatchEnd
821 return TemplateSectionList
822
823 ## Replace the string template with dictionary of placeholders and append it to previous one
824 #
825 # @param AppendString The string template to append
826 # @param Dictionary The placeholder dictionaries
827 #
828 def Append(self, AppendString, Dictionary=None):
829 if Dictionary:
830 SectionList = self._Parse(AppendString)
831 self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList))
832 else:
833 if isinstance(AppendString,list):
834 self.String.extend(AppendString)
835 else:
836 self.String.append(AppendString)
837
838 ## Replace the string template with dictionary of placeholders
839 #
840 # @param Dictionary The placeholder dictionaries
841 #
842 # @retval str The string replaced with placeholder values
843 #
844 def Replace(self, Dictionary=None):
845 return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList)
846
847 ## Progress indicator class
848 #
849 # This class makes use of thread to print progress on console.
850 #
851 class Progressor:
852 # for avoiding deadloop
853 _StopFlag = None
854 _ProgressThread = None
855 _CheckInterval = 0.25
856
857 ## Constructor
858 #
859 # @param OpenMessage The string printed before progress characters
860 # @param CloseMessage The string printed after progress characters
861 # @param ProgressChar The character used to indicate the progress
862 # @param Interval The interval in seconds between two progress characters
863 #
864 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
865 self.PromptMessage = OpenMessage
866 self.CodaMessage = CloseMessage
867 self.ProgressChar = ProgressChar
868 self.Interval = Interval
869 if Progressor._StopFlag is None:
870 Progressor._StopFlag = threading.Event()
871
872 ## Start to print progress character
873 #
874 # @param OpenMessage The string printed before progress characters
875 #
876 def Start(self, OpenMessage=None):
877 if OpenMessage is not None:
878 self.PromptMessage = OpenMessage
879 Progressor._StopFlag.clear()
880 if Progressor._ProgressThread is None:
881 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
882 Progressor._ProgressThread.setDaemon(False)
883 Progressor._ProgressThread.start()
884
885 ## Stop printing progress character
886 #
887 # @param CloseMessage The string printed after progress characters
888 #
889 def Stop(self, CloseMessage=None):
890 OriginalCodaMessage = self.CodaMessage
891 if CloseMessage is not None:
892 self.CodaMessage = CloseMessage
893 self.Abort()
894 self.CodaMessage = OriginalCodaMessage
895
896 ## Thread entry method
897 def _ProgressThreadEntry(self):
898 sys.stdout.write(self.PromptMessage + " ")
899 sys.stdout.flush()
900 TimeUp = 0.0
901 while not Progressor._StopFlag.isSet():
902 if TimeUp <= 0.0:
903 sys.stdout.write(self.ProgressChar)
904 sys.stdout.flush()
905 TimeUp = self.Interval
906 time.sleep(self._CheckInterval)
907 TimeUp -= self._CheckInterval
908 sys.stdout.write(" " + self.CodaMessage + "\n")
909 sys.stdout.flush()
910
911 ## Abort the progress display
912 @staticmethod
913 def Abort():
914 if Progressor._StopFlag is not None:
915 Progressor._StopFlag.set()
916 if Progressor._ProgressThread is not None:
917 Progressor._ProgressThread.join()
918 Progressor._ProgressThread = None
919
920
921 ## Dictionary using prioritized list as key
922 #
923 class tdict:
924 _ListType = type([])
925 _TupleType = type(())
926 _Wildcard = 'COMMON'
927 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM']
928
929 def __init__(self, _Single_=False, _Level_=2):
930 self._Level_ = _Level_
931 self.data = {}
932 self._Single_ = _Single_
933
934 # =[] operator
935 def __getitem__(self, key):
936 KeyType = type(key)
937 RestKeys = None
938 if KeyType == self._ListType or KeyType == self._TupleType:
939 FirstKey = key[0]
940 if len(key) > 1:
941 RestKeys = key[1:]
942 elif self._Level_ > 1:
943 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
944 else:
945 FirstKey = key
946 if self._Level_ > 1:
947 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
948
949 if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:
950 FirstKey = self._Wildcard
951
952 if self._Single_:
953 return self._GetSingleValue(FirstKey, RestKeys)
954 else:
955 return self._GetAllValues(FirstKey, RestKeys)
956
957 def _GetSingleValue(self, FirstKey, RestKeys):
958 Value = None
959 #print "%s-%s" % (FirstKey, self._Level_) ,
960 if self._Level_ > 1:
961 if FirstKey == self._Wildcard:
962 if FirstKey in self.data:
963 Value = self.data[FirstKey][RestKeys]
964 if Value is None:
965 for Key in self.data:
966 Value = self.data[Key][RestKeys]
967 if Value is not None: break
968 else:
969 if FirstKey in self.data:
970 Value = self.data[FirstKey][RestKeys]
971 if Value is None and self._Wildcard in self.data:
972 #print "Value=None"
973 Value = self.data[self._Wildcard][RestKeys]
974 else:
975 if FirstKey == self._Wildcard:
976 if FirstKey in self.data:
977 Value = self.data[FirstKey]
978 if Value is None:
979 for Key in self.data:
980 Value = self.data[Key]
981 if Value is not None: break
982 else:
983 if FirstKey in self.data:
984 Value = self.data[FirstKey]
985 elif self._Wildcard in self.data:
986 Value = self.data[self._Wildcard]
987 return Value
988
989 def _GetAllValues(self, FirstKey, RestKeys):
990 Value = []
991 if self._Level_ > 1:
992 if FirstKey == self._Wildcard:
993 for Key in self.data:
994 Value += self.data[Key][RestKeys]
995 else:
996 if FirstKey in self.data:
997 Value += self.data[FirstKey][RestKeys]
998 if self._Wildcard in self.data:
999 Value += self.data[self._Wildcard][RestKeys]
1000 else:
1001 if FirstKey == self._Wildcard:
1002 for Key in self.data:
1003 Value.append(self.data[Key])
1004 else:
1005 if FirstKey in self.data:
1006 Value.append(self.data[FirstKey])
1007 if self._Wildcard in self.data:
1008 Value.append(self.data[self._Wildcard])
1009 return Value
1010
1011 ## []= operator
1012 def __setitem__(self, key, value):
1013 KeyType = type(key)
1014 RestKeys = None
1015 if KeyType == self._ListType or KeyType == self._TupleType:
1016 FirstKey = key[0]
1017 if len(key) > 1:
1018 RestKeys = key[1:]
1019 else:
1020 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1021 else:
1022 FirstKey = key
1023 if self._Level_ > 1:
1024 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1025
1026 if FirstKey in self._ValidWildcardList:
1027 FirstKey = self._Wildcard
1028
1029 if FirstKey not in self.data and self._Level_ > 0:
1030 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
1031
1032 if self._Level_ > 1:
1033 self.data[FirstKey][RestKeys] = value
1034 else:
1035 self.data[FirstKey] = value
1036
1037 def SetGreedyMode(self):
1038 self._Single_ = False
1039 if self._Level_ > 1:
1040 for Key in self.data:
1041 self.data[Key].SetGreedyMode()
1042
1043 def SetSingleMode(self):
1044 self._Single_ = True
1045 if self._Level_ > 1:
1046 for Key in self.data:
1047 self.data[Key].SetSingleMode()
1048
1049 def GetKeys(self, KeyIndex=0):
1050 assert KeyIndex >= 0
1051 if KeyIndex == 0:
1052 return set(self.data.keys())
1053 else:
1054 keys = set()
1055 for Key in self.data:
1056 keys |= self.data[Key].GetKeys(KeyIndex - 1)
1057 return keys
1058
1059 def AnalyzePcdExpression(Setting):
1060 RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))
1061 Setting = Setting.replace('\\\\', RanStr).strip()
1062 # There might be escaped quote in a string: \", \\\" , \', \\\'
1063 Data = Setting
1064 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1065 NewStr = ''
1066 InSingleQuoteStr = False
1067 InDoubleQuoteStr = False
1068 Pair = 0
1069 for Index, ch in enumerate(Data):
1070 if ch == '"' and not InSingleQuoteStr:
1071 if Data[Index - 1] != '\\':
1072 InDoubleQuoteStr = not InDoubleQuoteStr
1073 elif ch == "'" and not InDoubleQuoteStr:
1074 if Data[Index - 1] != '\\':
1075 InSingleQuoteStr = not InSingleQuoteStr
1076 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):
1077 Pair += 1
1078 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):
1079 Pair -= 1
1080
1081 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:
1082 NewStr += '-'
1083 else:
1084 NewStr += ch
1085 FieldList = []
1086 StartPos = 0
1087 while True:
1088 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)
1089 if Pos < 0:
1090 FieldList.append(Setting[StartPos:].strip())
1091 break
1092 FieldList.append(Setting[StartPos:Pos].strip())
1093 StartPos = Pos + 1
1094 for i, ch in enumerate(FieldList):
1095 if RanStr in ch:
1096 FieldList[i] = ch.replace(RanStr,'\\\\')
1097 return FieldList
1098
1099 def ParseFieldValue (Value):
1100 def ParseDevPathValue (Value):
1101 if '\\' in Value:
1102 Value.replace('\\', '/').replace(' ', '')
1103
1104 Cmd = 'DevicePath ' + '"' + Value + '"'
1105 try:
1106 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
1107 out, err = p.communicate()
1108 except Exception as X:
1109 raise BadExpression("DevicePath: %s" % (str(X)) )
1110 finally:
1111 subprocess._cleanup()
1112 p.stdout.close()
1113 p.stderr.close()
1114 if err:
1115 raise BadExpression("DevicePath: %s" % str(err))
1116 out = out.decode()
1117 Size = len(out.split())
1118 out = ','.join(out.split())
1119 return '{' + out + '}', Size
1120
1121 if "{CODE(" in Value:
1122 return Value, len(Value.split(","))
1123 if isinstance(Value, type(0)):
1124 return Value, (Value.bit_length() + 7) // 8
1125 if not isinstance(Value, type('')):
1126 raise BadExpression('Type %s is %s' %(Value, type(Value)))
1127 Value = Value.strip()
1128 if Value.startswith(TAB_UINT8) and Value.endswith(')'):
1129 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
1130 if Size > 1:
1131 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
1132 return Value, 1
1133 if Value.startswith(TAB_UINT16) and Value.endswith(')'):
1134 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
1135 if Size > 2:
1136 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
1137 return Value, 2
1138 if Value.startswith(TAB_UINT32) and Value.endswith(')'):
1139 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
1140 if Size > 4:
1141 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
1142 return Value, 4
1143 if Value.startswith(TAB_UINT64) and Value.endswith(')'):
1144 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
1145 if Size > 8:
1146 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))
1147 return Value, 8
1148 if Value.startswith(TAB_GUID) and Value.endswith(')'):
1149 Value = Value.split('(', 1)[1][:-1].strip()
1150 if Value[0] == '{' and Value[-1] == '}':
1151 TmpValue = GuidStructureStringToGuidString(Value)
1152 if not TmpValue:
1153 raise BadExpression("Invalid GUID value string %s" % Value)
1154 Value = TmpValue
1155 if Value[0] == '"' and Value[-1] == '"':
1156 Value = Value[1:-1]
1157 try:
1158 Value = str(uuid.UUID(Value).bytes_le)
1159 if Value.startswith("b'"):
1160 Value = Value[2:-1]
1161 Value = "'" + Value + "'"
1162 except ValueError as Message:
1163 raise BadExpression(Message)
1164 Value, Size = ParseFieldValue(Value)
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.tostring() != b'PE\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)