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