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