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