2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2014, 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
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.
17 import Common
.LongFilePathOs
as os
27 from UserDict
import IterableUserDict
28 from UserList
import UserList
30 from Common
import EdkLogger
as EdkLogger
31 from Common
import GlobalData
as GlobalData
32 from DataType
import *
33 from BuildToolError
import *
34 from CommonDataClass
.DataClass
import *
35 from Parsing
import GetSplitValueList
36 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 ## Regular expression used to find out place holders in string template
39 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
41 ## Dictionary used to store file time stamp for quick re-access
42 gFileTimeStampCache
= {} # {file path : file time stamp}
44 ## Dictionary used to store dependencies of files
45 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
47 ## Routine to process duplicated INF
49 # This function is called by following two cases:
52 # Pkg/module/module.inf
53 # Pkg/module/module.inf {
55 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
58 # INF Pkg/module/module.inf
59 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
61 # This function copies Pkg/module/module.inf to
62 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
64 # @param Path Original PathClass object
65 # @param BaseName New file base name
67 # @retval return the new PathClass object
69 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
70 Filename
= os
.path
.split(Path
.File
)[1]
72 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
74 Filename
= BaseName
+ Path
.BaseName
77 # If -N is specified on command line, cache is disabled
78 # The directory has to be created
80 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
81 if not os
.path
.exists(DbDir
):
84 # A temporary INF is copied to database path which must have write permission
85 # The temporary will be removed at the end of build
86 # In case of name conflict, the file name is
87 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
89 TempFullPath
= os
.path
.join(DbDir
,
91 RtPath
= PathClass(Path
.File
, Workspace
)
93 # Modify the full path to temporary path, keep other unchanged
95 # To build same module more than once, the module path with FILE_GUID overridden has
96 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
97 # in DSC which is used as relative path by C files and other files in INF.
98 # A trick was used: all module paths are PathClass instances, after the initialization
99 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
101 # The reason for creating a temporary INF is:
102 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
103 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
104 # A different key for the same module is needed to create different output directory,
105 # retrieve overridden PCDs, library instances.
107 # The BaseName is the FILE_GUID which is also the output directory name.
110 RtPath
.Path
= TempFullPath
111 RtPath
.BaseName
= BaseName
113 # If file exists, compare contents
115 if os
.path
.exists(TempFullPath
):
116 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
117 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
120 GlobalData
.gTempInfs
.append(TempFullPath
)
121 shutil
.copy2(str(Path
), TempFullPath
)
124 ## Remove temporary created INFs whose paths were saved in gTempInfs
126 def ClearDuplicatedInf():
127 for File
in GlobalData
.gTempInfs
:
128 if os
.path
.exists(File
):
131 ## callback routine for processing variable option
133 # This function can be used to process variable number of option values. The
134 # typical usage of it is specify architecure list on command line.
135 # (e.g. <tool> -a IA32 X64 IPF)
137 # @param Option Standard callback function parameter
138 # @param OptionString Standard callback function parameter
139 # @param Value Standard callback function parameter
140 # @param Parser Standard callback function parameter
144 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
147 RawArgs
= Parser
.rargs
150 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
151 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
155 setattr(Parser
.values
, Option
.dest
, Value
)
157 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
159 # @param Guid The GUID string
161 # @retval string The GUID string in C structure style
163 def GuidStringToGuidStructureString(Guid
):
164 GuidList
= Guid
.split('-')
166 for Index
in range(0,3,1):
167 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
168 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
169 for Index
in range(0,12,2):
170 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
174 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
176 # @param GuidValue The GUID value in byte array
178 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
180 def GuidStructureByteArrayToGuidString(GuidValue
):
181 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
182 guidValueList
= guidValueString
.split(",")
183 if len(guidValueList
) != 16:
185 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
187 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
188 int(guidValueList
[3], 16),
189 int(guidValueList
[2], 16),
190 int(guidValueList
[1], 16),
191 int(guidValueList
[0], 16),
192 int(guidValueList
[5], 16),
193 int(guidValueList
[4], 16),
194 int(guidValueList
[7], 16),
195 int(guidValueList
[6], 16),
196 int(guidValueList
[8], 16),
197 int(guidValueList
[9], 16),
198 int(guidValueList
[10], 16),
199 int(guidValueList
[11], 16),
200 int(guidValueList
[12], 16),
201 int(guidValueList
[13], 16),
202 int(guidValueList
[14], 16),
203 int(guidValueList
[15], 16)
208 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
210 # @param GuidValue The GUID value in C structure format
212 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
214 def GuidStructureStringToGuidString(GuidValue
):
215 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
216 guidValueList
= guidValueString
.split(",")
217 if len(guidValueList
) != 11:
219 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
221 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
222 int(guidValueList
[0], 16),
223 int(guidValueList
[1], 16),
224 int(guidValueList
[2], 16),
225 int(guidValueList
[3], 16),
226 int(guidValueList
[4], 16),
227 int(guidValueList
[5], 16),
228 int(guidValueList
[6], 16),
229 int(guidValueList
[7], 16),
230 int(guidValueList
[8], 16),
231 int(guidValueList
[9], 16),
232 int(guidValueList
[10], 16)
237 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
239 # @param GuidValue The GUID value in C structure format
241 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
243 def GuidStructureStringToGuidValueName(GuidValue
):
244 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
245 guidValueList
= guidValueString
.split(",")
246 if len(guidValueList
) != 11:
247 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
248 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
249 int(guidValueList
[0], 16),
250 int(guidValueList
[1], 16),
251 int(guidValueList
[2], 16),
252 int(guidValueList
[3], 16),
253 int(guidValueList
[4], 16),
254 int(guidValueList
[5], 16),
255 int(guidValueList
[6], 16),
256 int(guidValueList
[7], 16),
257 int(guidValueList
[8], 16),
258 int(guidValueList
[9], 16),
259 int(guidValueList
[10], 16)
262 ## Create directories
264 # @param Directory The directory name
266 def CreateDirectory(Directory
):
267 if Directory
== None or Directory
.strip() == "":
270 if not os
.access(Directory
, os
.F_OK
):
271 os
.makedirs(Directory
)
276 ## Remove directories, including files and sub-directories in it
278 # @param Directory The directory name
280 def RemoveDirectory(Directory
, Recursively
=False):
281 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
284 CurrentDirectory
= os
.getcwd()
286 for File
in os
.listdir("."):
287 if os
.path
.isdir(File
):
288 RemoveDirectory(File
, Recursively
)
291 os
.chdir(CurrentDirectory
)
294 ## Check if given file is changed or not
296 # This method is used to check if a file is changed or not between two build
297 # actions. It makes use a cache to store files timestamp.
299 # @param File The path of file
301 # @retval True If the given file is changed, doesn't exist, or can't be
302 # found in timestamp cache
303 # @retval False If the given file is changed
306 if not os
.path
.exists(File
):
309 FileState
= os
.stat(File
)
310 TimeStamp
= FileState
[-2]
312 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
316 gFileTimeStampCache
[File
] = TimeStamp
320 ## Store content in file
322 # This method is used to save file only when its content is changed. This is
323 # quite useful for "make" system to decide what will be re-built and what won't.
325 # @param File The path of file
326 # @param Content The new content of the file
327 # @param IsBinaryFile The flag indicating if the file is binary file or not
329 # @retval True If the file content is changed and the file is renewed
330 # @retval False If the file content is the same
332 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
334 Content
= Content
.replace("\n", os
.linesep
)
336 if os
.path
.exists(File
):
338 if Content
== open(File
, "rb").read():
341 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
343 DirName
= os
.path
.dirname(File
)
344 if not CreateDirectory(DirName
):
345 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
348 DirName
= os
.getcwd()
349 if not os
.access(DirName
, os
.W_OK
):
350 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
353 if GlobalData
.gIsWindows
:
355 from PyUtility
import SaveFileToDisk
356 if not SaveFileToDisk(File
, Content
):
357 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
359 Fd
= open(File
, "wb")
363 Fd
= open(File
, "wb")
367 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s'%X)
371 ## Make a Python object persistent on file system
373 # @param Data The object to be stored in file
374 # @param File The path of file to store the object
376 def DataDump(Data
, File
):
379 Fd
= open(File
, 'wb')
380 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
382 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
387 ## Restore a Python object from a file
389 # @param File The path of file stored the object
391 # @retval object A python object
392 # @retval None If failure in file operation
394 def DataRestore(File
):
398 Fd
= open(File
, 'rb')
399 Data
= cPickle
.load(Fd
)
401 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
408 ## Retrieve and cache the real path name in file system
410 # @param Root The root directory of path relative to
412 # @retval str The path string if the path exists
413 # @retval None If path doesn't exist
419 def __init__(self
, Root
):
421 for F
in os
.listdir(Root
):
423 self
._UPPER
_CACHE
_[F
.upper()] = F
426 def __getitem__(self
, Path
):
427 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
430 if Path
and Path
[0] == os
.path
.sep
:
432 if Path
in self
._CACHE
_:
433 return os
.path
.join(self
._Root
, Path
)
434 UpperPath
= Path
.upper()
435 if UpperPath
in self
._UPPER
_CACHE
_:
436 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
440 SepIndex
= Path
.find(os
.path
.sep
)
442 Parent
= UpperPath
[:SepIndex
]
443 if Parent
not in self
._UPPER
_CACHE
_:
445 LastSepIndex
= SepIndex
446 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
448 if LastSepIndex
== -1:
453 SepIndex
= LastSepIndex
455 Parent
= Path
[:SepIndex
]
456 ParentKey
= UpperPath
[:SepIndex
]
457 if ParentKey
not in self
._UPPER
_CACHE
_:
461 if Parent
in self
._CACHE
_:
464 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
465 for F
in os
.listdir(ParentDir
):
466 Dir
= os
.path
.join(ParentDir
, F
)
467 self
._CACHE
_.add(Dir
)
468 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
470 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
473 if Path
in self
._CACHE
_:
474 return os
.path
.join(self
._Root
, Path
)
475 elif UpperPath
in self
._UPPER
_CACHE
_:
476 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
479 ## Get all files of a directory
481 # @param Root: Root dir
482 # @param SkipList : The files need be skipped
484 # @retval A list of all files
486 def GetFiles(Root
, SkipList
=None, FullPath
= True):
489 for Root
, Dirs
, Files
in os
.walk(Root
):
491 for Item
in SkipList
:
496 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
498 File
= File
[len(OriPath
) + 1:]
499 FileList
.append(File
)
503 ## Check if gvien file exists or not
505 # @param File File name or path to be checked
506 # @param Dir The directory the file is relative to
508 # @retval True if file exists
509 # @retval False if file doesn't exists
511 def ValidFile(File
, Ext
=None):
513 Dummy
, FileExt
= os
.path
.splitext(File
)
514 if FileExt
.lower() != Ext
.lower():
516 if not os
.path
.exists(File
):
520 def RealPath(File
, Dir
='', OverrideDir
=''):
521 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
522 NewFile
= GlobalData
.gAllFiles
[NewFile
]
523 if not NewFile
and OverrideDir
:
524 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
525 NewFile
= GlobalData
.gAllFiles
[NewFile
]
528 def RealPath2(File
, Dir
='', OverrideDir
=''):
531 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
533 if OverrideDir
[-1] == os
.path
.sep
:
534 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
536 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
537 if GlobalData
.gAllFiles
:
538 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
540 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
541 if not os
.path
.exists(NewFile
):
545 if Dir
[-1] == os
.path
.sep
:
546 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
548 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
554 ## Check if gvien file exists or not
557 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
560 Dummy
, FileExt
= os
.path
.splitext(File
)
561 if FileExt
.lower() != Ext
.lower():
564 # Replace the Edk macros
565 if OverrideDir
!= '' and OverrideDir
!= None:
566 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
567 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
568 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
569 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
571 # Replace the default dir to current dir
574 Dir
= Dir
[len(Workspace
)+1:]
576 # First check if File has Edk definition itself
577 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
578 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
579 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
580 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
584 # Second check the path with override value
585 if OverrideDir
!= '' and OverrideDir
!= None:
586 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
590 # Last check the path with normal definitions
591 File
= os
.path
.join(Dir
, File
)
592 NewFile
= AllFiles
[os
.path
.normpath(File
)]
598 ## Check if gvien file exists or not
601 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
602 # Replace the Edk macros
603 if OverrideDir
!= '' and OverrideDir
!= None:
604 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
605 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
606 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
607 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
609 # Replace the default dir to current dir
610 # Dir is current module dir related to workspace
613 Dir
= Dir
[len(Workspace
)+1:]
616 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
617 NewRelaPath
= RelaPath
620 # First check if File has Edk definition itself
621 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
622 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
623 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
624 NewFile
= AllFiles
[os
.path
.normpath(File
)]
626 NewRelaPath
= os
.path
.dirname(NewFile
)
627 File
= os
.path
.basename(NewFile
)
628 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
631 # Second check the path with override value
632 if OverrideDir
!= '' and OverrideDir
!= None:
633 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
635 #NewRelaPath = os.path.dirname(NewFile)
636 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
639 # Last check the path with normal definitions
640 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
647 return NewRelaPath
, RelaPath
, File
650 def GetRelPath(Path1
, Path2
):
651 FileName
= os
.path
.basename(Path2
)
652 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
653 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
654 for Index
in range(0, len(L1
)):
655 if L1
[Index
] != L2
[Index
]:
656 FileName
= '../' * (len(L1
) - Index
)
657 for Index2
in range(Index
, len(L2
)):
658 FileName
= os
.path
.join(FileName
, L2
[Index2
])
660 return os
.path
.normpath(FileName
)
663 ## Get GUID value from given packages
665 # @param CName The CName of the GUID
666 # @param PackageList List of packages looking-up in
668 # @retval GuidValue if the CName is found in any given package
669 # @retval None if the CName is not found in all given packages
671 def GuidValue(CName
, PackageList
):
672 for P
in PackageList
:
674 return P
.Guids
[CName
]
677 ## Get Protocol value from given packages
679 # @param CName The CName of the GUID
680 # @param PackageList List of packages looking-up in
682 # @retval GuidValue if the CName is found in any given package
683 # @retval None if the CName is not found in all given packages
685 def ProtocolValue(CName
, PackageList
):
686 for P
in PackageList
:
687 if CName
in P
.Protocols
:
688 return P
.Protocols
[CName
]
691 ## Get PPI value from given packages
693 # @param CName The CName of the GUID
694 # @param PackageList List of packages looking-up in
696 # @retval GuidValue if the CName is found in any given package
697 # @retval None if the CName is not found in all given packages
699 def PpiValue(CName
, PackageList
):
700 for P
in PackageList
:
705 ## A string template class
707 # This class implements a template for string replacement. A string template
708 # looks like following
710 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
712 # The string between ${BEGIN} and ${END} will be repeated as many times as the
713 # length of "placeholder_name", which is a list passed through a dict. The
714 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
715 # be not used and, in this case, the "placeholder_name" must not a list and it
716 # will just be replaced once.
718 class TemplateString(object):
719 _REPEAT_START_FLAG
= "BEGIN"
720 _REPEAT_END_FLAG
= "END"
722 class Section(object):
723 _LIST_TYPES
= [type([]), type(set()), type((0,))]
725 def __init__(self
, TemplateSection
, PlaceHolderList
):
726 self
._Template
= TemplateSection
727 self
._PlaceHolderList
= []
729 # Split the section into sub-sections according to the position of placeholders
731 self
._SubSectionList
= []
734 # The placeholders passed in must be in the format of
736 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
738 for PlaceHolder
,Start
,End
in PlaceHolderList
:
739 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
740 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
741 self
._PlaceHolderList
.append(PlaceHolder
)
742 SubSectionStart
= End
743 if SubSectionStart
< len(TemplateSection
):
744 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
746 self
._SubSectionList
= [TemplateSection
]
749 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
751 def Instantiate(self
, PlaceHolderValues
):
753 RepeatPlaceHolders
= {}
754 NonRepeatPlaceHolders
= {}
756 for PlaceHolder
in self
._PlaceHolderList
:
757 if PlaceHolder
not in PlaceHolderValues
:
759 Value
= PlaceHolderValues
[PlaceHolder
]
760 if type(Value
) in self
._LIST
_TYPES
:
762 RepeatTime
= len(Value
)
763 elif RepeatTime
!= len(Value
):
767 "${%s} has different repeat time from others!" % PlaceHolder
,
768 ExtraData
=str(self
._Template
)
770 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
772 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
774 if NonRepeatPlaceHolders
:
776 for S
in self
._SubSectionList
:
777 if S
not in NonRepeatPlaceHolders
:
780 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
782 StringList
= self
._SubSectionList
784 if RepeatPlaceHolders
:
786 for Index
in range(RepeatTime
):
788 if S
not in RepeatPlaceHolders
:
789 TempStringList
.append(S
)
791 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
792 StringList
= TempStringList
794 return "".join(StringList
)
797 def __init__(self
, Template
=None):
799 self
.IsBinary
= False
800 self
._Template
= Template
801 self
._TemplateSectionList
= self
._Parse
(Template
)
805 # @retval string The string replaced
810 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
812 # @retval list A list of TemplateString.Section objects
814 def _Parse(self
, Template
):
819 TemplateSectionList
= []
821 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
823 if MatchEnd
<= len(Template
):
824 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
825 TemplateSectionList
.append(TemplateSection
)
828 MatchString
= MatchObj
.group(1)
829 MatchStart
= MatchObj
.start()
830 MatchEnd
= MatchObj
.end()
832 if MatchString
== self
._REPEAT
_START
_FLAG
:
833 if MatchStart
> SectionStart
:
834 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
835 TemplateSectionList
.append(TemplateSection
)
836 SectionStart
= MatchEnd
838 elif MatchString
== self
._REPEAT
_END
_FLAG
:
839 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
840 TemplateSectionList
.append(TemplateSection
)
841 SectionStart
= MatchEnd
844 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
845 SearchFrom
= MatchEnd
846 return TemplateSectionList
848 ## Replace the string template with dictionary of placeholders and append it to previous one
850 # @param AppendString The string template to append
851 # @param Dictionary The placeholder dictionaries
853 def Append(self
, AppendString
, Dictionary
=None):
855 SectionList
= self
._Parse
(AppendString
)
856 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
858 self
.String
+= AppendString
860 ## Replace the string template with dictionary of placeholders
862 # @param Dictionary The placeholder dictionaries
864 # @retval str The string replaced with placeholder values
866 def Replace(self
, Dictionary
=None):
867 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
869 ## Progress indicator class
871 # This class makes use of thread to print progress on console.
874 # for avoiding deadloop
876 _ProgressThread
= None
877 _CheckInterval
= 0.25
881 # @param OpenMessage The string printed before progress charaters
882 # @param CloseMessage The string printed after progress charaters
883 # @param ProgressChar The charater used to indicate the progress
884 # @param Interval The interval in seconds between two progress charaters
886 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
887 self
.PromptMessage
= OpenMessage
888 self
.CodaMessage
= CloseMessage
889 self
.ProgressChar
= ProgressChar
890 self
.Interval
= Interval
891 if Progressor
._StopFlag
== None:
892 Progressor
._StopFlag
= threading
.Event()
894 ## Start to print progress charater
896 # @param OpenMessage The string printed before progress charaters
898 def Start(self
, OpenMessage
=None):
899 if OpenMessage
!= None:
900 self
.PromptMessage
= OpenMessage
901 Progressor
._StopFlag
.clear()
902 if Progressor
._ProgressThread
== None:
903 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
904 Progressor
._ProgressThread
.setDaemon(False)
905 Progressor
._ProgressThread
.start()
907 ## Stop printing progress charater
909 # @param CloseMessage The string printed after progress charaters
911 def Stop(self
, CloseMessage
=None):
912 OriginalCodaMessage
= self
.CodaMessage
913 if CloseMessage
!= None:
914 self
.CodaMessage
= CloseMessage
916 self
.CodaMessage
= OriginalCodaMessage
918 ## Thread entry method
919 def _ProgressThreadEntry(self
):
920 sys
.stdout
.write(self
.PromptMessage
+ " ")
923 while not Progressor
._StopFlag
.isSet():
925 sys
.stdout
.write(self
.ProgressChar
)
927 TimeUp
= self
.Interval
928 time
.sleep(self
._CheckInterval
)
929 TimeUp
-= self
._CheckInterval
930 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
933 ## Abort the progress display
936 if Progressor
._StopFlag
!= None:
937 Progressor
._StopFlag
.set()
938 if Progressor
._ProgressThread
!= None:
939 Progressor
._ProgressThread
.join()
940 Progressor
._ProgressThread
= None
942 ## A dict which can access its keys and/or values orderly
944 # The class implements a new kind of dict which its keys or values can be
945 # accessed in the order they are added into the dict. It guarantees the order
946 # by making use of an internal list to keep a copy of keys.
948 class sdict(IterableUserDict
):
951 IterableUserDict
.__init
__(self
)
955 def __setitem__(self
, key
, value
):
956 if key
not in self
._key
_list
:
957 self
._key
_list
.append(key
)
958 IterableUserDict
.__setitem
__(self
, key
, value
)
961 def __delitem__(self
, key
):
962 self
._key
_list
.remove(key
)
963 IterableUserDict
.__delitem
__(self
, key
)
965 ## used in "for k in dict" loop to ensure the correct order
967 return self
.iterkeys()
971 return len(self
._key
_list
)
974 def __contains__(self
, key
):
975 return key
in self
._key
_list
978 def index(self
, key
):
979 return self
._key
_list
.index(key
)
982 def insert(self
, key
, newkey
, newvalue
, order
):
983 index
= self
._key
_list
.index(key
)
984 if order
== 'BEFORE':
985 self
._key
_list
.insert(index
, newkey
)
986 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
987 elif order
== 'AFTER':
988 self
._key
_list
.insert(index
+ 1, newkey
)
989 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
992 def append(self
, sdict
):
994 if key
not in self
._key
_list
:
995 self
._key
_list
.append(key
)
996 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
998 def has_key(self
, key
):
999 return key
in self
._key
_list
1004 IterableUserDict
.clear(self
)
1006 ## Return a copy of keys
1009 for key
in self
._key
_list
:
1013 ## Return a copy of values
1016 for key
in self
._key
_list
:
1017 values
.append(self
[key
])
1020 ## Return a copy of (key, value) list
1023 for key
in self
._key
_list
:
1024 items
.append((key
, self
[key
]))
1027 ## Iteration support
1028 def iteritems(self
):
1029 return iter(self
.items())
1031 ## Keys interation support
1033 return iter(self
.keys())
1035 ## Values interation support
1036 def itervalues(self
):
1037 return iter(self
.values())
1039 ## Return value related to a key, and remove the (key, value) from the dict
1040 def pop(self
, key
, *dv
):
1042 if key
in self
._key
_list
:
1044 self
.__delitem
__(key
)
1049 ## Return (key, value) pair, and remove the (key, value) from the dict
1051 key
= self
._key
_list
[-1]
1053 self
.__delitem
__(key
)
1056 def update(self
, dict=None, **kwargs
):
1058 for k
, v
in dict.items():
1061 for k
, v
in kwargs
.items():
1064 ## Dictionary with restricted keys
1068 def __init__(self
, KeyList
):
1070 dict.__setitem
__(self
, Key
, "")
1073 def __setitem__(self
, key
, value
):
1075 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1076 ExtraData
=", ".join(dict.keys(self
)))
1077 dict.__setitem
__(self
, key
, value
)
1080 def __getitem__(self
, key
):
1083 return dict.__getitem
__(self
, key
)
1086 def __delitem__(self
, key
):
1087 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1092 self
.__setitem
__(Key
, "")
1094 ## Return value related to a key, and remove the (key, value) from the dict
1095 def pop(self
, key
, *dv
):
1096 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1098 ## Return (key, value) pair, and remove the (key, value) from the dict
1100 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1102 ## Dictionary using prioritized list as key
1105 _ListType
= type([])
1106 _TupleType
= type(())
1107 _Wildcard
= 'COMMON'
1108 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1110 def __init__(self
, _Single_
=False, _Level_
=2):
1111 self
._Level
_ = _Level_
1113 self
._Single
_ = _Single_
1116 def __getitem__(self
, key
):
1119 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1123 elif self
._Level
_ > 1:
1124 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1127 if self
._Level
_ > 1:
1128 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1130 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1131 FirstKey
= self
._Wildcard
1134 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1136 return self
._GetAllValues
(FirstKey
, RestKeys
)
1138 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1140 #print "%s-%s" % (FirstKey, self._Level_) ,
1141 if self
._Level
_ > 1:
1142 if FirstKey
== self
._Wildcard
:
1143 if FirstKey
in self
.data
:
1144 Value
= self
.data
[FirstKey
][RestKeys
]
1146 for Key
in self
.data
:
1147 Value
= self
.data
[Key
][RestKeys
]
1148 if Value
!= None: break
1150 if FirstKey
in self
.data
:
1151 Value
= self
.data
[FirstKey
][RestKeys
]
1152 if Value
== None and self
._Wildcard
in self
.data
:
1154 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1156 if FirstKey
== self
._Wildcard
:
1157 if FirstKey
in self
.data
:
1158 Value
= self
.data
[FirstKey
]
1160 for Key
in self
.data
:
1161 Value
= self
.data
[Key
]
1162 if Value
!= None: break
1164 if FirstKey
in self
.data
:
1165 Value
= self
.data
[FirstKey
]
1166 elif self
._Wildcard
in self
.data
:
1167 Value
= self
.data
[self
._Wildcard
]
1170 def _GetAllValues(self
, FirstKey
, RestKeys
):
1172 if self
._Level
_ > 1:
1173 if FirstKey
== self
._Wildcard
:
1174 for Key
in self
.data
:
1175 Value
+= self
.data
[Key
][RestKeys
]
1177 if FirstKey
in self
.data
:
1178 Value
+= self
.data
[FirstKey
][RestKeys
]
1179 if self
._Wildcard
in self
.data
:
1180 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1182 if FirstKey
== self
._Wildcard
:
1183 for Key
in self
.data
:
1184 Value
.append(self
.data
[Key
])
1186 if FirstKey
in self
.data
:
1187 Value
.append(self
.data
[FirstKey
])
1188 if self
._Wildcard
in self
.data
:
1189 Value
.append(self
.data
[self
._Wildcard
])
1193 def __setitem__(self
, key
, value
):
1196 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1201 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1204 if self
._Level
_ > 1:
1205 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1207 if FirstKey
in self
._ValidWildcardList
:
1208 FirstKey
= self
._Wildcard
1210 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1211 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1213 if self
._Level
_ > 1:
1214 self
.data
[FirstKey
][RestKeys
] = value
1216 self
.data
[FirstKey
] = value
1218 def SetGreedyMode(self
):
1219 self
._Single
_ = False
1220 if self
._Level
_ > 1:
1221 for Key
in self
.data
:
1222 self
.data
[Key
].SetGreedyMode()
1224 def SetSingleMode(self
):
1225 self
._Single
_ = True
1226 if self
._Level
_ > 1:
1227 for Key
in self
.data
:
1228 self
.data
[Key
].SetSingleMode()
1230 def GetKeys(self
, KeyIndex
=0):
1231 assert KeyIndex
>= 0
1233 return set(self
.data
.keys())
1236 for Key
in self
.data
:
1237 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1240 ## Boolean chain list
1242 class Blist(UserList
):
1243 def __init__(self
, initlist
=None):
1244 UserList
.__init
__(self
, initlist
)
1245 def __setitem__(self
, i
, item
):
1246 if item
not in [True, False]:
1252 def _GetResult(self
):
1254 for item
in self
.data
:
1257 Result
= property(_GetResult
)
1259 def ParseConsoleLog(Filename
):
1260 Opr
= open(os
.path
.normpath(Filename
), 'r')
1261 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1262 for Line
in Opr
.readlines():
1263 if Line
.find('.efi') > -1:
1264 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1265 Opw
.write('%s\n' % Line
)
1272 # Analyze DSC PCD value, since there is no data type info in DSC
1273 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1274 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1275 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1276 # 3. Dynamic default:
1277 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1278 # TokenSpace.PcdCName|PcdValue
1280 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1281 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1283 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1284 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1285 # there might have "|" operator, also in string value.
1287 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1288 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1289 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1291 # ValueList: A List contain fields described above
1292 # IsValid: True if conforming EBNF, otherwise False
1293 # Index: The index where PcdValue is in ValueList
1295 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1296 Setting
= Setting
.strip()
1297 # There might be escaped quote in a string: \", \\\"
1298 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1299 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1306 elif ch
== '(' and not InStr
:
1308 elif ch
== ')' and not InStr
:
1311 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1318 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1320 FieldList
.append(Setting
[StartPos
:].strip())
1322 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1326 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1327 Value
= FieldList
[0]
1329 if len(FieldList
) > 1:
1331 # Fix the PCD type when no DataType input
1336 if len(FieldList
) > 2:
1338 if DataType
== 'VOID*':
1339 IsValid
= (len(FieldList
) <= 3)
1341 IsValid
= (len(FieldList
) <= 1)
1342 return [Value
, '', Size
], IsValid
, 0
1343 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1344 Value
= FieldList
[0]
1346 if len(FieldList
) > 1:
1350 if len(FieldList
) > 2:
1354 if Value
.startswith("L"):
1355 Size
= str((len(Value
)- 3 + 1) * 2)
1356 elif Value
.startswith("{"):
1357 Size
= str(len(Value
.split(",")))
1359 Size
= str(len(Value
) -2 + 1 )
1360 if DataType
== 'VOID*':
1361 IsValid
= (len(FieldList
) <= 3)
1363 IsValid
= (len(FieldList
) <= 1)
1364 return [Value
, Type
, Size
], IsValid
, 0
1365 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1366 VpdOffset
= FieldList
[0]
1368 if not DataType
== 'VOID*':
1369 if len(FieldList
) > 1:
1370 Value
= FieldList
[1]
1372 if len(FieldList
) > 1:
1374 if len(FieldList
) > 2:
1375 Value
= FieldList
[2]
1376 if DataType
== 'VOID*':
1377 IsValid
= (len(FieldList
) <= 3)
1379 IsValid
= (len(FieldList
) <= 2)
1380 return [VpdOffset
, Size
, Value
], IsValid
, 2
1381 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1382 HiiString
= FieldList
[0]
1383 Guid
= Offset
= Value
= ''
1384 if len(FieldList
) > 1:
1386 if len(FieldList
) > 2:
1387 Offset
= FieldList
[2]
1388 if len(FieldList
) > 3:
1389 Value
= FieldList
[3]
1390 IsValid
= (3 <= len(FieldList
) <= 4)
1391 return [HiiString
, Guid
, Offset
, Value
], IsValid
, 3
1396 # Analyze the pcd Value, Datum type and TokenNumber.
1397 # Used to avoid split issue while the value string contain "|" character
1399 # @param[in] Setting: A String contain value/datum type/token number information;
1401 # @retval ValueList: A List contain value, datum type and toke number.
1403 def AnalyzePcdData(Setting
):
1404 ValueList
= ['', '', '']
1406 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1407 PtrValue
= ValueRe
.findall(Setting
)
1409 ValueUpdateFlag
= False
1411 if len(PtrValue
) >= 1:
1412 Setting
= re
.sub(ValueRe
, '', Setting
)
1413 ValueUpdateFlag
= True
1415 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1416 ValueList
[0:len(TokenList
)] = TokenList
1419 ValueList
[0] = PtrValue
[0]
1423 ## AnalyzeHiiPcdData
1425 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1426 # Used to avoid split issue while the value string contain "|" character
1428 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1430 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1432 def AnalyzeHiiPcdData(Setting
):
1433 ValueList
= ['', '', '', '']
1435 TokenList
= GetSplitValueList(Setting
)
1436 ValueList
[0:len(TokenList
)] = TokenList
1440 ## AnalyzeVpdPcdData
1442 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1443 # Used to avoid split issue while the value string contain "|" character
1445 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1447 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1449 def AnalyzeVpdPcdData(Setting
):
1450 ValueList
= ['', '', '']
1452 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1453 PtrValue
= ValueRe
.findall(Setting
)
1455 ValueUpdateFlag
= False
1457 if len(PtrValue
) >= 1:
1458 Setting
= re
.sub(ValueRe
, '', Setting
)
1459 ValueUpdateFlag
= True
1461 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1462 ValueList
[0:len(TokenList
)] = TokenList
1465 ValueList
[2] = PtrValue
[0]
1469 ## check format of PCD value against its the datum type
1471 # For PCD value setting
1473 def CheckPcdDatum(Type
, Value
):
1475 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1476 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1477 or (Value
.startswith('{') and Value
.endswith('}'))
1479 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1480 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1481 elif ValueRe
.match(Value
):
1482 # Check the chars in UnicodeString or CString is printable
1483 if Value
.startswith("L"):
1487 Printset
= set(string
.printable
)
1488 Printset
.remove(TAB_PRINTCHAR_VT
)
1489 Printset
.add(TAB_PRINTCHAR_BS
)
1490 Printset
.add(TAB_PRINTCHAR_NUL
)
1491 if not set(Value
).issubset(Printset
):
1492 PrintList
= list(Printset
)
1494 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1495 elif Type
== 'BOOLEAN':
1496 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1497 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1498 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1499 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1501 Value
= long(Value
, 0)
1503 return False, "Invalid value [%s] of type [%s];"\
1504 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1506 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1510 ## Split command line option string to list
1512 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1513 # in non-windows platform to launch command
1515 def SplitOption(OptionString
):
1520 for Index
in range(0, len(OptionString
)):
1521 CurrentChar
= OptionString
[Index
]
1522 if CurrentChar
in ['"', "'"]:
1523 if QuotationMark
== CurrentChar
:
1525 elif QuotationMark
== "":
1526 QuotationMark
= CurrentChar
1531 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1532 if Index
> OptionStart
:
1533 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1535 LastChar
= CurrentChar
1536 OptionList
.append(OptionString
[OptionStart
:])
1539 def CommonPath(PathList
):
1540 P1
= min(PathList
).split(os
.path
.sep
)
1541 P2
= max(PathList
).split(os
.path
.sep
)
1542 for Index
in xrange(min(len(P1
), len(P2
))):
1543 if P1
[Index
] != P2
[Index
]:
1544 return os
.path
.sep
.join(P1
[:Index
])
1545 return os
.path
.sep
.join(P1
)
1548 # Convert string to C format array
1550 def ConvertStringToByteArray(Value
):
1551 Value
= Value
.strip()
1555 if not Value
.endswith('}'):
1557 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1558 ValFields
= Value
.split(',')
1560 for Index
in range(len(ValFields
)):
1561 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1564 Value
= '{' + ','.join(ValFields
) + '}'
1568 if Value
.startswith('L"'):
1569 if not Value
.endswith('"'):
1573 elif not Value
.startswith('"') or not Value
.endswith('"'):
1576 Value
= eval(Value
) # translate escape character
1578 for Index
in range(0,len(Value
)):
1580 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1582 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1583 Value
= NewValue
+ '0}'
1586 class PathClass(object):
1587 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1588 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1590 self
.File
= str(File
)
1591 if os
.path
.isabs(self
.File
):
1595 self
.Root
= str(Root
)
1596 self
.AlterRoot
= str(AlterRoot
)
1598 # Remove any '.' and '..' in path
1600 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1601 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1602 # eliminate the side-effect of 'C:'
1603 if self
.Root
[-1] == ':':
1604 self
.Root
+= os
.path
.sep
1605 # file path should not start with path separator
1606 if self
.Root
[-1] == os
.path
.sep
:
1607 self
.File
= self
.Path
[len(self
.Root
):]
1609 self
.File
= self
.Path
[len(self
.Root
)+1:]
1611 self
.Path
= os
.path
.normpath(self
.File
)
1613 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1614 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1618 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1620 self
.Dir
= self
.Root
1622 self
.Dir
= self
.SubDir
1627 self
.Type
= self
.Ext
.lower()
1629 self
.IsBinary
= IsBinary
1630 self
.Target
= Target
1631 self
.TagName
= TagName
1632 self
.ToolCode
= ToolCode
1633 self
.ToolChainFamily
= ToolChainFamily
1637 ## Convert the object of this class to a string
1639 # Convert member Path of the class to a string
1641 # @retval string Formatted String
1646 ## Override __eq__ function
1648 # Check whether PathClass are the same
1650 # @retval False The two PathClass are different
1651 # @retval True The two PathClass are the same
1653 def __eq__(self
, Other
):
1654 if type(Other
) == type(self
):
1655 return self
.Path
== Other
.Path
1657 return self
.Path
== str(Other
)
1659 ## Override __cmp__ function
1661 # Customize the comparsion operation of two PathClass
1663 # @retval 0 The two PathClass are different
1664 # @retval -1 The first PathClass is less than the second PathClass
1665 # @retval 1 The first PathClass is Bigger than the second PathClass
1666 def __cmp__(self
, Other
):
1667 if type(Other
) == type(self
):
1668 OtherKey
= Other
.Path
1670 OtherKey
= str(Other
)
1673 if SelfKey
== OtherKey
:
1675 elif SelfKey
> OtherKey
:
1680 ## Override __hash__ function
1682 # Use Path as key in hash table
1684 # @retval string Key for hash table
1687 return hash(self
.Path
)
1689 def _GetFileKey(self
):
1690 if self
._Key
== None:
1691 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1694 def _GetTimeStamp(self
):
1695 return os
.stat(self
.Path
)[8]
1697 def Validate(self
, Type
='', CaseSensitive
=True):
1698 if GlobalData
.gCaseInsensitive
:
1699 CaseSensitive
= False
1700 if Type
and Type
.lower() != self
.Type
:
1701 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1703 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1704 if not RealRoot
and not RealFile
:
1705 RealFile
= self
.File
1707 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1709 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1710 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1714 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1715 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1716 ErrorCode
= FILE_CASE_MISMATCH
1717 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1719 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1720 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1722 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1725 self
.File
= RealFile
1726 self
.Root
= RealRoot
1727 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1728 return ErrorCode
, ErrorInfo
1730 Key
= property(_GetFileKey
)
1731 TimeStamp
= property(_GetTimeStamp
)
1733 ## Parse PE image to get the required PE informaion.
1735 class PeImageClass():
1738 # @param File FilePath of PeImage
1740 def __init__(self
, PeFile
):
1741 self
.FileName
= PeFile
1742 self
.IsValid
= False
1745 self
.SectionAlignment
= 0
1746 self
.SectionHeaderList
= []
1749 PeObject
= open(PeFile
, 'rb')
1751 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1754 ByteArray
= array
.array('B')
1755 ByteArray
.fromfile(PeObject
, 0x3E)
1756 ByteList
= ByteArray
.tolist()
1757 # DOS signature should be 'MZ'
1758 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1759 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1762 # Read 4 byte PE Signature
1763 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1764 PeObject
.seek(PeOffset
)
1765 ByteArray
= array
.array('B')
1766 ByteArray
.fromfile(PeObject
, 4)
1767 # PE signature should be 'PE\0\0'
1768 if ByteArray
.tostring() != 'PE\0\0':
1769 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1772 # Read PE file header
1773 ByteArray
= array
.array('B')
1774 ByteArray
.fromfile(PeObject
, 0x14)
1775 ByteList
= ByteArray
.tolist()
1776 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1778 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1781 # Read PE optional header
1782 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1783 ByteArray
= array
.array('B')
1784 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1785 ByteList
= ByteArray
.tolist()
1786 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1787 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1788 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1790 # Read each Section Header
1791 for Index
in range(SecNumber
):
1792 ByteArray
= array
.array('B')
1793 ByteArray
.fromfile(PeObject
, 0x28)
1794 ByteList
= ByteArray
.tolist()
1795 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1796 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1797 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1798 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1799 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1803 def _ByteListToStr(self
, ByteList
):
1805 for index
in range(len(ByteList
)):
1806 if ByteList
[index
] == 0:
1808 String
+= chr(ByteList
[index
])
1811 def _ByteListToInt(self
, ByteList
):
1813 for index
in range(len(ByteList
) - 1, -1, -1):
1814 Value
= (Value
<< 8) |
int(ByteList
[index
])
1824 def __init__(self
,SkuIdentifier
='', SkuIds
={}):
1826 self
.AvailableSkuIds
= sdict()
1829 if SkuIdentifier
== '' or SkuIdentifier
is None:
1830 self
.SkuIdSet
= ['DEFAULT']
1831 elif SkuIdentifier
== 'ALL':
1832 self
.SkuIdSet
= SkuIds
.keys()
1834 r
= SkuIdentifier
.split('|')
1835 self
.SkuIdSet
=[r
[k
].strip() for k
in range(len(r
))]
1836 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
and SkuIdentifier
!= 'ALL':
1837 self
.SkuIdSet
.remove('DEFAULT')
1839 for each
in self
.SkuIdSet
:
1841 self
.AvailableSkuIds
[each
] = SkuIds
[each
]
1843 EdkLogger
.error("build", PARAMETER_INVALID
,
1844 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1845 % (each
, " ".join(SkuIds
.keys())))
1847 def __SkuUsageType(self
):
1849 if len(self
.SkuIdSet
) == 1:
1850 if self
.SkuIdSet
[0] == 'DEFAULT':
1851 return SkuClass
.DEFAULT
1853 return SkuClass
.SINGLE
1855 return SkuClass
.MULTIPLE
1857 def __GetAvailableSkuIds(self
):
1858 return self
.AvailableSkuIds
1860 def __GetSystemSkuID(self
):
1861 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
1862 return self
.SkuIdSet
[0]
1866 SystemSkuId
= property(__GetSystemSkuID
)
1867 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
1868 SkuUsageType
= property(__SkuUsageType
)
1872 # This acts like the main() function for the script, unless it is 'import'ed into another
1875 if __name__
== '__main__':