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