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