2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2010, 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.
26 from UserDict
import IterableUserDict
27 from UserList
import UserList
29 from Common
import EdkLogger
as EdkLogger
30 from Common
import GlobalData
as GlobalData
31 from DataType
import *
32 from BuildToolError
import *
33 from CommonDataClass
.DataClass
import *
35 ## Regular expression used to find out place holders in string template
36 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
38 ## Dictionary used to store file time stamp for quick re-access
39 gFileTimeStampCache
= {} # {file path : file time stamp}
41 ## Dictionary used to store dependencies of files
42 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
44 ## callback routine for processing variable option
46 # This function can be used to process variable number of option values. The
47 # typical usage of it is specify architecure list on command line.
48 # (e.g. <tool> -a IA32 X64 IPF)
50 # @param Option Standard callback function parameter
51 # @param OptionString Standard callback function parameter
52 # @param Value Standard callback function parameter
53 # @param Parser Standard callback function parameter
57 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
60 RawArgs
= Parser
.rargs
63 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
64 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
68 setattr(Parser
.values
, Option
.dest
, Value
)
70 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
72 # @param Guid The GUID string
74 # @retval string The GUID string in C structure style
76 def GuidStringToGuidStructureString(Guid
):
77 GuidList
= Guid
.split('-')
79 for Index
in range(0,3,1):
80 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
81 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
82 for Index
in range(0,12,2):
83 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
87 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
89 # @param GuidValue The GUID value in byte array
91 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
93 def GuidStructureByteArrayToGuidString(GuidValue
):
94 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
95 guidValueList
= guidValueString
.split(",")
96 if len(guidValueList
) != 16:
98 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
100 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
101 int(guidValueList
[3], 16),
102 int(guidValueList
[2], 16),
103 int(guidValueList
[1], 16),
104 int(guidValueList
[0], 16),
105 int(guidValueList
[5], 16),
106 int(guidValueList
[4], 16),
107 int(guidValueList
[7], 16),
108 int(guidValueList
[6], 16),
109 int(guidValueList
[8], 16),
110 int(guidValueList
[9], 16),
111 int(guidValueList
[10], 16),
112 int(guidValueList
[11], 16),
113 int(guidValueList
[12], 16),
114 int(guidValueList
[13], 16),
115 int(guidValueList
[14], 16),
116 int(guidValueList
[15], 16)
121 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
123 # @param GuidValue The GUID value in C structure format
125 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
127 def GuidStructureStringToGuidString(GuidValue
):
128 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
129 guidValueList
= guidValueString
.split(",")
130 if len(guidValueList
) != 11:
132 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
134 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
135 int(guidValueList
[0], 16),
136 int(guidValueList
[1], 16),
137 int(guidValueList
[2], 16),
138 int(guidValueList
[3], 16),
139 int(guidValueList
[4], 16),
140 int(guidValueList
[5], 16),
141 int(guidValueList
[6], 16),
142 int(guidValueList
[7], 16),
143 int(guidValueList
[8], 16),
144 int(guidValueList
[9], 16),
145 int(guidValueList
[10], 16)
150 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
152 # @param GuidValue The GUID value in C structure format
154 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
156 def GuidStructureStringToGuidValueName(GuidValue
):
157 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
158 guidValueList
= guidValueString
.split(",")
159 if len(guidValueList
) != 11:
160 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
161 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
162 int(guidValueList
[0], 16),
163 int(guidValueList
[1], 16),
164 int(guidValueList
[2], 16),
165 int(guidValueList
[3], 16),
166 int(guidValueList
[4], 16),
167 int(guidValueList
[5], 16),
168 int(guidValueList
[6], 16),
169 int(guidValueList
[7], 16),
170 int(guidValueList
[8], 16),
171 int(guidValueList
[9], 16),
172 int(guidValueList
[10], 16)
175 ## Create directories
177 # @param Directory The directory name
179 def CreateDirectory(Directory
):
180 if Directory
== None or Directory
.strip() == "":
183 if not os
.access(Directory
, os
.F_OK
):
184 os
.makedirs(Directory
)
189 ## Remove directories, including files and sub-directories in it
191 # @param Directory The directory name
193 def RemoveDirectory(Directory
, Recursively
=False):
194 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
197 CurrentDirectory
= os
.getcwd()
199 for File
in os
.listdir("."):
200 if os
.path
.isdir(File
):
201 RemoveDirectory(File
, Recursively
)
204 os
.chdir(CurrentDirectory
)
207 ## Check if given file is changed or not
209 # This method is used to check if a file is changed or not between two build
210 # actions. It makes use a cache to store files timestamp.
212 # @param File The path of file
214 # @retval True If the given file is changed, doesn't exist, or can't be
215 # found in timestamp cache
216 # @retval False If the given file is changed
219 if not os
.path
.exists(File
):
222 FileState
= os
.stat(File
)
223 TimeStamp
= FileState
[-2]
225 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
229 gFileTimeStampCache
[File
] = TimeStamp
233 ## Store content in file
235 # This method is used to save file only when its content is changed. This is
236 # quite useful for "make" system to decide what will be re-built and what won't.
238 # @param File The path of file
239 # @param Content The new content of the file
240 # @param IsBinaryFile The flag indicating if the file is binary file or not
242 # @retval True If the file content is changed and the file is renewed
243 # @retval False If the file content is the same
245 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
247 Content
= Content
.replace("\n", os
.linesep
)
249 if os
.path
.exists(File
):
251 if Content
== open(File
, "rb").read():
254 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
256 DirName
= os
.path
.dirname(File
)
257 if not CreateDirectory(DirName
):
258 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
261 DirName
= os
.getcwd()
262 if not os
.access(DirName
, os
.W_OK
):
263 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
266 if GlobalData
.gIsWindows
:
268 from PyUtility
import SaveFileToDisk
269 if not SaveFileToDisk(File
, Content
):
270 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
272 Fd
= open(File
, "wb")
276 Fd
= open(File
, "wb")
280 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s'%X)
284 ## Make a Python object persistent on file system
286 # @param Data The object to be stored in file
287 # @param File The path of file to store the object
289 def DataDump(Data
, File
):
292 Fd
= open(File
, 'wb')
293 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
295 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
300 ## Restore a Python object from a file
302 # @param File The path of file stored the object
304 # @retval object A python object
305 # @retval None If failure in file operation
307 def DataRestore(File
):
311 Fd
= open(File
, 'rb')
312 Data
= cPickle
.load(Fd
)
314 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
321 ## Retrieve and cache the real path name in file system
323 # @param Root The root directory of path relative to
325 # @retval str The path string if the path exists
326 # @retval None If path doesn't exist
332 def __init__(self
, Root
):
334 for F
in os
.listdir(Root
):
336 self
._UPPER
_CACHE
_[F
.upper()] = F
339 def __getitem__(self
, Path
):
340 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
343 if Path
and Path
[0] == os
.path
.sep
:
345 if Path
in self
._CACHE
_:
346 return os
.path
.join(self
._Root
, Path
)
347 UpperPath
= Path
.upper()
348 if UpperPath
in self
._UPPER
_CACHE
_:
349 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
353 SepIndex
= Path
.find(os
.path
.sep
)
355 Parent
= UpperPath
[:SepIndex
]
356 if Parent
not in self
._UPPER
_CACHE
_:
358 LastSepIndex
= SepIndex
359 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
361 if LastSepIndex
== -1:
366 SepIndex
= LastSepIndex
368 Parent
= Path
[:SepIndex
]
369 ParentKey
= UpperPath
[:SepIndex
]
370 if ParentKey
not in self
._UPPER
_CACHE
_:
374 if Parent
in self
._CACHE
_:
377 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
378 for F
in os
.listdir(ParentDir
):
379 Dir
= os
.path
.join(ParentDir
, F
)
380 self
._CACHE
_.add(Dir
)
381 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
383 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
386 if Path
in self
._CACHE
_:
387 return os
.path
.join(self
._Root
, Path
)
388 elif UpperPath
in self
._UPPER
_CACHE
_:
389 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
392 ## Get all files of a directory
394 # @param Root: Root dir
395 # @param SkipList : The files need be skipped
397 # @retval A list of all files
399 def GetFiles(Root
, SkipList
=None, FullPath
= True):
402 for Root
, Dirs
, Files
in os
.walk(Root
):
404 for Item
in SkipList
:
409 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
411 File
= File
[len(OriPath
) + 1:]
412 FileList
.append(File
)
416 ## Check if gvien file exists or not
418 # @param File File name or path to be checked
419 # @param Dir The directory the file is relative to
421 # @retval True if file exists
422 # @retval False if file doesn't exists
424 def ValidFile(File
, Ext
=None):
426 Dummy
, FileExt
= os
.path
.splitext(File
)
427 if FileExt
.lower() != Ext
.lower():
429 if not os
.path
.exists(File
):
433 def RealPath(File
, Dir
='', OverrideDir
=''):
434 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
435 NewFile
= GlobalData
.gAllFiles
[NewFile
]
436 if not NewFile
and OverrideDir
:
437 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
438 NewFile
= GlobalData
.gAllFiles
[NewFile
]
441 def RealPath2(File
, Dir
='', OverrideDir
=''):
443 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
445 if OverrideDir
[-1] == os
.path
.sep
:
446 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
448 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
449 if GlobalData
.gAllFiles
:
450 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
452 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
455 if Dir
[-1] == os
.path
.sep
:
456 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
458 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
464 ## Check if gvien file exists or not
467 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
470 Dummy
, FileExt
= os
.path
.splitext(File
)
471 if FileExt
.lower() != Ext
.lower():
474 # Replace the Edk macros
475 if OverrideDir
!= '' and OverrideDir
!= None:
476 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
477 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
478 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
479 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
481 # Replace the default dir to current dir
484 Dir
= Dir
[len(Workspace
)+1:]
486 # First check if File has Edk definition itself
487 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
488 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
489 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
490 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
494 # Second check the path with override value
495 if OverrideDir
!= '' and OverrideDir
!= None:
496 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
500 # Last check the path with normal definitions
501 File
= os
.path
.join(Dir
, File
)
502 NewFile
= AllFiles
[os
.path
.normpath(File
)]
508 ## Check if gvien file exists or not
511 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
512 # Replace the Edk macros
513 if OverrideDir
!= '' and OverrideDir
!= None:
514 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
515 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
516 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
517 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
519 # Replace the default dir to current dir
520 # Dir is current module dir related to workspace
523 Dir
= Dir
[len(Workspace
)+1:]
526 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
527 NewRelaPath
= RelaPath
530 # First check if File has Edk definition itself
531 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
532 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
533 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
534 NewFile
= AllFiles
[os
.path
.normpath(File
)]
536 NewRelaPath
= os
.path
.dirname(NewFile
)
537 File
= os
.path
.basename(NewFile
)
538 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
541 # Second check the path with override value
542 if OverrideDir
!= '' and OverrideDir
!= None:
543 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
545 #NewRelaPath = os.path.dirname(NewFile)
546 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
549 # Last check the path with normal definitions
550 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
557 return NewRelaPath
, RelaPath
, File
560 def GetRelPath(Path1
, Path2
):
561 FileName
= os
.path
.basename(Path2
)
562 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
563 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
564 for Index
in range(0, len(L1
)):
565 if L1
[Index
] != L2
[Index
]:
566 FileName
= '../' * (len(L1
) - Index
)
567 for Index2
in range(Index
, len(L2
)):
568 FileName
= os
.path
.join(FileName
, L2
[Index2
])
570 return os
.path
.normpath(FileName
)
573 ## Get GUID value from given packages
575 # @param CName The CName of the GUID
576 # @param PackageList List of packages looking-up in
578 # @retval GuidValue if the CName is found in any given package
579 # @retval None if the CName is not found in all given packages
581 def GuidValue(CName
, PackageList
):
582 for P
in PackageList
:
584 return P
.Guids
[CName
]
587 ## Get Protocol value from given packages
589 # @param CName The CName of the GUID
590 # @param PackageList List of packages looking-up in
592 # @retval GuidValue if the CName is found in any given package
593 # @retval None if the CName is not found in all given packages
595 def ProtocolValue(CName
, PackageList
):
596 for P
in PackageList
:
597 if CName
in P
.Protocols
:
598 return P
.Protocols
[CName
]
601 ## Get PPI value from given packages
603 # @param CName The CName of the GUID
604 # @param PackageList List of packages looking-up in
606 # @retval GuidValue if the CName is found in any given package
607 # @retval None if the CName is not found in all given packages
609 def PpiValue(CName
, PackageList
):
610 for P
in PackageList
:
615 ## A string template class
617 # This class implements a template for string replacement. A string template
618 # looks like following
620 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
622 # The string between ${BEGIN} and ${END} will be repeated as many times as the
623 # length of "placeholder_name", which is a list passed through a dict. The
624 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
625 # be not used and, in this case, the "placeholder_name" must not a list and it
626 # will just be replaced once.
628 class TemplateString(object):
629 _REPEAT_START_FLAG
= "BEGIN"
630 _REPEAT_END_FLAG
= "END"
632 class Section(object):
633 _LIST_TYPES
= [type([]), type(set()), type((0,))]
635 def __init__(self
, TemplateSection
, PlaceHolderList
):
636 self
._Template
= TemplateSection
637 self
._PlaceHolderList
= []
639 # Split the section into sub-sections according to the position of placeholders
641 self
._SubSectionList
= []
644 # The placeholders passed in must be in the format of
646 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
648 for PlaceHolder
,Start
,End
in PlaceHolderList
:
649 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
650 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
651 self
._PlaceHolderList
.append(PlaceHolder
)
652 SubSectionStart
= End
653 if SubSectionStart
< len(TemplateSection
):
654 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
656 self
._SubSectionList
= [TemplateSection
]
659 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
661 def Instantiate(self
, PlaceHolderValues
):
663 RepeatPlaceHolders
= {}
664 NonRepeatPlaceHolders
= {}
666 for PlaceHolder
in self
._PlaceHolderList
:
667 if PlaceHolder
not in PlaceHolderValues
:
669 Value
= PlaceHolderValues
[PlaceHolder
]
670 if type(Value
) in self
._LIST
_TYPES
:
672 RepeatTime
= len(Value
)
673 elif RepeatTime
!= len(Value
):
677 "${%s} has different repeat time from others!" % PlaceHolder
,
678 ExtraData
=str(self
._Template
)
680 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
682 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
684 if NonRepeatPlaceHolders
:
686 for S
in self
._SubSectionList
:
687 if S
not in NonRepeatPlaceHolders
:
690 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
692 StringList
= self
._SubSectionList
694 if RepeatPlaceHolders
:
696 for Index
in range(RepeatTime
):
698 if S
not in RepeatPlaceHolders
:
699 TempStringList
.append(S
)
701 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
702 StringList
= TempStringList
704 return "".join(StringList
)
707 def __init__(self
, Template
=None):
709 self
.IsBinary
= False
710 self
._Template
= Template
711 self
._TemplateSectionList
= self
._Parse
(Template
)
715 # @retval string The string replaced
720 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
722 # @retval list A list of TemplateString.Section objects
724 def _Parse(self
, Template
):
729 TemplateSectionList
= []
731 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
733 if MatchEnd
<= len(Template
):
734 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
735 TemplateSectionList
.append(TemplateSection
)
738 MatchString
= MatchObj
.group(1)
739 MatchStart
= MatchObj
.start()
740 MatchEnd
= MatchObj
.end()
742 if MatchString
== self
._REPEAT
_START
_FLAG
:
743 if MatchStart
> SectionStart
:
744 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
745 TemplateSectionList
.append(TemplateSection
)
746 SectionStart
= MatchEnd
748 elif MatchString
== self
._REPEAT
_END
_FLAG
:
749 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
750 TemplateSectionList
.append(TemplateSection
)
751 SectionStart
= MatchEnd
754 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
755 SearchFrom
= MatchEnd
756 return TemplateSectionList
758 ## Replace the string template with dictionary of placeholders and append it to previous one
760 # @param AppendString The string template to append
761 # @param Dictionary The placeholder dictionaries
763 def Append(self
, AppendString
, Dictionary
=None):
765 SectionList
= self
._Parse
(AppendString
)
766 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
768 self
.String
+= AppendString
770 ## Replace the string template with dictionary of placeholders
772 # @param Dictionary The placeholder dictionaries
774 # @retval str The string replaced with placeholder values
776 def Replace(self
, Dictionary
=None):
777 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
779 ## Progress indicator class
781 # This class makes use of thread to print progress on console.
784 # for avoiding deadloop
786 _ProgressThread
= None
787 _CheckInterval
= 0.25
791 # @param OpenMessage The string printed before progress charaters
792 # @param CloseMessage The string printed after progress charaters
793 # @param ProgressChar The charater used to indicate the progress
794 # @param Interval The interval in seconds between two progress charaters
796 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
797 self
.PromptMessage
= OpenMessage
798 self
.CodaMessage
= CloseMessage
799 self
.ProgressChar
= ProgressChar
800 self
.Interval
= Interval
801 if Progressor
._StopFlag
== None:
802 Progressor
._StopFlag
= threading
.Event()
804 ## Start to print progress charater
806 # @param OpenMessage The string printed before progress charaters
808 def Start(self
, OpenMessage
=None):
809 if OpenMessage
!= None:
810 self
.PromptMessage
= OpenMessage
811 Progressor
._StopFlag
.clear()
812 if Progressor
._ProgressThread
== None:
813 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
814 Progressor
._ProgressThread
.setDaemon(False)
815 Progressor
._ProgressThread
.start()
817 ## Stop printing progress charater
819 # @param CloseMessage The string printed after progress charaters
821 def Stop(self
, CloseMessage
=None):
822 OriginalCodaMessage
= self
.CodaMessage
823 if CloseMessage
!= None:
824 self
.CodaMessage
= CloseMessage
826 self
.CodaMessage
= OriginalCodaMessage
828 ## Thread entry method
829 def _ProgressThreadEntry(self
):
830 sys
.stdout
.write(self
.PromptMessage
+ " ")
833 while not Progressor
._StopFlag
.isSet():
835 sys
.stdout
.write(self
.ProgressChar
)
837 TimeUp
= self
.Interval
838 time
.sleep(self
._CheckInterval
)
839 TimeUp
-= self
._CheckInterval
840 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
843 ## Abort the progress display
846 if Progressor
._StopFlag
!= None:
847 Progressor
._StopFlag
.set()
848 if Progressor
._ProgressThread
!= None:
849 Progressor
._ProgressThread
.join()
850 Progressor
._ProgressThread
= None
852 ## A dict which can access its keys and/or values orderly
854 # The class implements a new kind of dict which its keys or values can be
855 # accessed in the order they are added into the dict. It guarantees the order
856 # by making use of an internal list to keep a copy of keys.
858 class sdict(IterableUserDict
):
861 IterableUserDict
.__init
__(self
)
865 def __setitem__(self
, key
, value
):
866 if key
not in self
._key
_list
:
867 self
._key
_list
.append(key
)
868 IterableUserDict
.__setitem
__(self
, key
, value
)
871 def __delitem__(self
, key
):
872 self
._key
_list
.remove(key
)
873 IterableUserDict
.__delitem
__(self
, key
)
875 ## used in "for k in dict" loop to ensure the correct order
877 return self
.iterkeys()
881 return len(self
._key
_list
)
884 def __contains__(self
, key
):
885 return key
in self
._key
_list
888 def index(self
, key
):
889 return self
._key
_list
.index(key
)
892 def insert(self
, key
, newkey
, newvalue
, order
):
893 index
= self
._key
_list
.index(key
)
894 if order
== 'BEFORE':
895 self
._key
_list
.insert(index
, newkey
)
896 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
897 elif order
== 'AFTER':
898 self
._key
_list
.insert(index
+ 1, newkey
)
899 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
902 def append(self
, sdict
):
904 if key
not in self
._key
_list
:
905 self
._key
_list
.append(key
)
906 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
908 def has_key(self
, key
):
909 return key
in self
._key
_list
914 IterableUserDict
.clear(self
)
916 ## Return a copy of keys
919 for key
in self
._key
_list
:
923 ## Return a copy of values
926 for key
in self
._key
_list
:
927 values
.append(self
[key
])
930 ## Return a copy of (key, value) list
933 for key
in self
._key
_list
:
934 items
.append((key
, self
[key
]))
939 return iter(self
.items())
941 ## Keys interation support
943 return iter(self
.keys())
945 ## Values interation support
946 def itervalues(self
):
947 return iter(self
.values())
949 ## Return value related to a key, and remove the (key, value) from the dict
950 def pop(self
, key
, *dv
):
952 if key
in self
._key
_list
:
954 self
.__delitem
__(key
)
959 ## Return (key, value) pair, and remove the (key, value) from the dict
961 key
= self
._key
_list
[-1]
963 self
.__delitem
__(key
)
966 def update(self
, dict=None, **kwargs
):
968 for k
, v
in dict.items():
971 for k
, v
in kwargs
.items():
974 ## Dictionary with restricted keys
978 def __init__(self
, KeyList
):
980 dict.__setitem
__(self
, Key
, "")
983 def __setitem__(self
, key
, value
):
985 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
986 ExtraData
=", ".join(dict.keys(self
)))
987 dict.__setitem
__(self
, key
, value
)
990 def __getitem__(self
, key
):
993 return dict.__getitem
__(self
, key
)
996 def __delitem__(self
, key
):
997 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1002 self
.__setitem
__(Key
, "")
1004 ## Return value related to a key, and remove the (key, value) from the dict
1005 def pop(self
, key
, *dv
):
1006 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1008 ## Return (key, value) pair, and remove the (key, value) from the dict
1010 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1012 ## Dictionary using prioritized list as key
1015 _ListType
= type([])
1016 _TupleType
= type(())
1017 _Wildcard
= 'COMMON'
1018 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1020 def __init__(self
, _Single_
=False, _Level_
=2):
1021 self
._Level
_ = _Level_
1023 self
._Single
_ = _Single_
1026 def __getitem__(self
, key
):
1029 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1033 elif self
._Level
_ > 1:
1034 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1037 if self
._Level
_ > 1:
1038 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1040 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1041 FirstKey
= self
._Wildcard
1044 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1046 return self
._GetAllValues
(FirstKey
, RestKeys
)
1048 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1050 #print "%s-%s" % (FirstKey, self._Level_) ,
1051 if self
._Level
_ > 1:
1052 if FirstKey
== self
._Wildcard
:
1053 if FirstKey
in self
.data
:
1054 Value
= self
.data
[FirstKey
][RestKeys
]
1056 for Key
in self
.data
:
1057 Value
= self
.data
[Key
][RestKeys
]
1058 if Value
!= None: break
1060 if FirstKey
in self
.data
:
1061 Value
= self
.data
[FirstKey
][RestKeys
]
1062 if Value
== None and self
._Wildcard
in self
.data
:
1064 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1066 if FirstKey
== self
._Wildcard
:
1067 if FirstKey
in self
.data
:
1068 Value
= self
.data
[FirstKey
]
1070 for Key
in self
.data
:
1071 Value
= self
.data
[Key
]
1072 if Value
!= None: break
1074 if FirstKey
in self
.data
:
1075 Value
= self
.data
[FirstKey
]
1076 elif self
._Wildcard
in self
.data
:
1077 Value
= self
.data
[self
._Wildcard
]
1080 def _GetAllValues(self
, FirstKey
, RestKeys
):
1082 if self
._Level
_ > 1:
1083 if FirstKey
== self
._Wildcard
:
1084 for Key
in self
.data
:
1085 Value
+= self
.data
[Key
][RestKeys
]
1087 if FirstKey
in self
.data
:
1088 Value
+= self
.data
[FirstKey
][RestKeys
]
1089 if self
._Wildcard
in self
.data
:
1090 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1092 if FirstKey
== self
._Wildcard
:
1093 for Key
in self
.data
:
1094 Value
.append(self
.data
[Key
])
1096 if FirstKey
in self
.data
:
1097 Value
.append(self
.data
[FirstKey
])
1098 if self
._Wildcard
in self
.data
:
1099 Value
.append(self
.data
[self
._Wildcard
])
1103 def __setitem__(self
, key
, value
):
1106 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1111 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1114 if self
._Level
_ > 1:
1115 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1117 if FirstKey
in self
._ValidWildcardList
:
1118 FirstKey
= self
._Wildcard
1120 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1121 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1123 if self
._Level
_ > 1:
1124 self
.data
[FirstKey
][RestKeys
] = value
1126 self
.data
[FirstKey
] = value
1128 def SetGreedyMode(self
):
1129 self
._Single
_ = False
1130 if self
._Level
_ > 1:
1131 for Key
in self
.data
:
1132 self
.data
[Key
].SetGreedyMode()
1134 def SetSingleMode(self
):
1135 self
._Single
_ = True
1136 if self
._Level
_ > 1:
1137 for Key
in self
.data
:
1138 self
.data
[Key
].SetSingleMode()
1140 def GetKeys(self
, KeyIndex
=0):
1141 assert KeyIndex
>= 0
1143 return set(self
.data
.keys())
1146 for Key
in self
.data
:
1147 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1150 ## Boolean chain list
1152 class Blist(UserList
):
1153 def __init__(self
, initlist
=None):
1154 UserList
.__init
__(self
, initlist
)
1155 def __setitem__(self
, i
, item
):
1156 if item
not in [True, False]:
1162 def _GetResult(self
):
1164 for item
in self
.data
:
1167 Result
= property(_GetResult
)
1169 def ParseConsoleLog(Filename
):
1170 Opr
= open(os
.path
.normpath(Filename
), 'r')
1171 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1172 for Line
in Opr
.readlines():
1173 if Line
.find('.efi') > -1:
1174 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1175 Opw
.write('%s\n' % Line
)
1182 # Analyze DSC PCD value, since there is no data type info in DSC
1183 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1184 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1185 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1186 # 3. Dynamic default:
1187 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1188 # TokenSpace.PcdCName|PcdValue
1190 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1191 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1193 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1194 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1195 # there might have "|" operator, also in string value.
1197 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1198 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1199 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1201 # ValueList: A List contain fields described above
1202 # IsValid: True if conforming EBNF, otherwise False
1203 # Index: The index where PcdValue is in ValueList
1205 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1206 Setting
= Setting
.strip()
1207 # There might be escaped quote in a string: \", \\\"
1208 Data
= Setting
.replace('\\\\', '//').replace('\\\"', '\\\'')
1209 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1216 elif ch
== '(' and not InStr
:
1218 elif ch
== ')' and not InStr
:
1221 if (Pair
> 0 or InStr
) and ch
== TAB_VALUE_SPLIT
:
1228 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1230 FieldList
.append(Setting
[StartPos
:].strip())
1232 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1236 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1237 Value
= FieldList
[0]
1239 if len(FieldList
) > 1:
1241 if DataType
== 'VOID*':
1242 IsValid
= (len(FieldList
) <= 2)
1244 IsValid
= (len(FieldList
) <= 1)
1245 return [Value
, '', Size
], IsValid
, 0
1246 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1247 Value
= FieldList
[0]
1249 if len(FieldList
) > 1:
1251 if len(FieldList
) > 2:
1253 if DataType
== 'VOID*':
1254 IsValid
= (len(FieldList
) <= 3)
1256 IsValid
= (len(FieldList
) <= 1)
1257 return [Value
, Type
, Size
], IsValid
, 0
1258 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1259 VpdOffset
= FieldList
[0]
1261 if not DataType
== 'VOID*':
1262 if len(FieldList
) > 1:
1263 Value
= FieldList
[1]
1265 if len(FieldList
) > 1:
1267 if len(FieldList
) > 2:
1268 Value
= FieldList
[2]
1269 if DataType
== 'VOID*':
1270 IsValid
= (len(FieldList
) <= 3)
1272 IsValid
= (len(FieldList
) <= 2)
1273 return [VpdOffset
, Size
, Value
], IsValid
, 2
1274 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1275 HiiString
= FieldList
[0]
1276 Guid
= Offset
= Value
= ''
1277 if len(FieldList
) > 1:
1279 if len(FieldList
) > 2:
1280 Offset
= FieldList
[2]
1281 if len(FieldList
) > 3:
1282 Value
= FieldList
[3]
1283 IsValid
= (3 <= len(FieldList
) <= 4)
1284 return [HiiString
, Guid
, Offset
, Value
], IsValid
, 3
1289 # Analyze the pcd Value, Datum type and TokenNumber.
1290 # Used to avoid split issue while the value string contain "|" character
1292 # @param[in] Setting: A String contain value/datum type/token number information;
1294 # @retval ValueList: A List contain value, datum type and toke number.
1296 def AnalyzePcdData(Setting
):
1297 ValueList
= ['', '', '']
1299 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1300 PtrValue
= ValueRe
.findall(Setting
)
1302 ValueUpdateFlag
= False
1304 if len(PtrValue
) >= 1:
1305 Setting
= re
.sub(ValueRe
, '', Setting
)
1306 ValueUpdateFlag
= True
1308 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1309 ValueList
[0:len(TokenList
)] = TokenList
1312 ValueList
[0] = PtrValue
[0]
1316 ## AnalyzeHiiPcdData
1318 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1319 # Used to avoid split issue while the value string contain "|" character
1321 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1323 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1325 def AnalyzeHiiPcdData(Setting
):
1326 ValueList
= ['', '', '', '']
1328 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1329 PtrValue
= ValueRe
.findall(Setting
)
1331 ValueUpdateFlag
= False
1333 if len(PtrValue
) >= 1:
1334 Setting
= re
.sub(ValueRe
, '', Setting
)
1335 ValueUpdateFlag
= True
1337 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1338 ValueList
[0:len(TokenList
)] = TokenList
1341 ValueList
[0] = PtrValue
[0]
1345 ## AnalyzeVpdPcdData
1347 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1348 # Used to avoid split issue while the value string contain "|" character
1350 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1352 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1354 def AnalyzeVpdPcdData(Setting
):
1355 ValueList
= ['', '', '']
1357 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1358 PtrValue
= ValueRe
.findall(Setting
)
1360 ValueUpdateFlag
= False
1362 if len(PtrValue
) >= 1:
1363 Setting
= re
.sub(ValueRe
, '', Setting
)
1364 ValueUpdateFlag
= True
1366 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1367 ValueList
[0:len(TokenList
)] = TokenList
1370 ValueList
[2] = PtrValue
[0]
1374 ## check format of PCD value against its the datum type
1376 # For PCD value setting
1378 def CheckPcdDatum(Type
, Value
):
1380 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1381 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1382 or (Value
.startswith('{') and Value
.endswith('}'))
1384 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1385 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1386 elif ValueRe
.match(Value
):
1387 # Check the chars in UnicodeString or CString is printable
1388 if Value
.startswith("L"):
1392 Printset
= set(string
.printable
)
1393 Printset
.remove(TAB_PRINTCHAR_VT
)
1394 Printset
.add(TAB_PRINTCHAR_BS
)
1395 Printset
.add(TAB_PRINTCHAR_NUL
)
1396 if not set(Value
).issubset(Printset
):
1397 PrintList
= list(Printset
)
1399 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1400 elif Type
== 'BOOLEAN':
1401 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1402 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1403 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1404 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1406 Value
= long(Value
, 0)
1408 return False, "Invalid value [%s] of type [%s];"\
1409 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1411 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type
)
1415 ## Split command line option string to list
1417 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1418 # in non-windows platform to launch command
1420 def SplitOption(OptionString
):
1425 for Index
in range(0, len(OptionString
)):
1426 CurrentChar
= OptionString
[Index
]
1427 if CurrentChar
in ['"', "'"]:
1428 if QuotationMark
== CurrentChar
:
1430 elif QuotationMark
== "":
1431 QuotationMark
= CurrentChar
1436 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1437 if Index
> OptionStart
:
1438 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1440 LastChar
= CurrentChar
1441 OptionList
.append(OptionString
[OptionStart
:])
1444 def CommonPath(PathList
):
1445 P1
= min(PathList
).split(os
.path
.sep
)
1446 P2
= max(PathList
).split(os
.path
.sep
)
1447 for Index
in xrange(min(len(P1
), len(P2
))):
1448 if P1
[Index
] != P2
[Index
]:
1449 return os
.path
.sep
.join(P1
[:Index
])
1450 return os
.path
.sep
.join(P1
)
1452 class PathClass(object):
1453 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1454 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1456 self
.File
= str(File
)
1457 if os
.path
.isabs(self
.File
):
1461 self
.Root
= str(Root
)
1462 self
.AlterRoot
= str(AlterRoot
)
1464 # Remove any '.' and '..' in path
1466 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1467 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1468 # eliminate the side-effect of 'C:'
1469 if self
.Root
[-1] == ':':
1470 self
.Root
+= os
.path
.sep
1471 # file path should not start with path separator
1472 if self
.Root
[-1] == os
.path
.sep
:
1473 self
.File
= self
.Path
[len(self
.Root
):]
1475 self
.File
= self
.Path
[len(self
.Root
)+1:]
1477 self
.Path
= os
.path
.normpath(self
.File
)
1479 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1480 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1484 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1486 self
.Dir
= self
.Root
1488 self
.Dir
= self
.SubDir
1493 self
.Type
= self
.Ext
.lower()
1495 self
.IsBinary
= IsBinary
1496 self
.Target
= Target
1497 self
.TagName
= TagName
1498 self
.ToolCode
= ToolCode
1499 self
.ToolChainFamily
= ToolChainFamily
1503 ## Convert the object of this class to a string
1505 # Convert member Path of the class to a string
1507 # @retval string Formatted String
1512 ## Override __eq__ function
1514 # Check whether PathClass are the same
1516 # @retval False The two PathClass are different
1517 # @retval True The two PathClass are the same
1519 def __eq__(self
, Other
):
1520 if type(Other
) == type(self
):
1521 return self
.Path
== Other
.Path
1523 return self
.Path
== str(Other
)
1525 ## Override __cmp__ function
1527 # Customize the comparsion operation of two PathClass
1529 # @retval 0 The two PathClass are different
1530 # @retval -1 The first PathClass is less than the second PathClass
1531 # @retval 1 The first PathClass is Bigger than the second PathClass
1532 def __cmp__(self
, Other
):
1533 if type(Other
) == type(self
):
1534 OtherKey
= Other
.Path
1536 OtherKey
= str(Other
)
1539 if SelfKey
== OtherKey
:
1541 elif SelfKey
> OtherKey
:
1546 ## Override __hash__ function
1548 # Use Path as key in hash table
1550 # @retval string Key for hash table
1553 return hash(self
.Path
)
1555 def _GetFileKey(self
):
1556 if self
._Key
== None:
1557 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1560 def _GetTimeStamp(self
):
1561 return os
.stat(self
.Path
)[8]
1563 def Validate(self
, Type
='', CaseSensitive
=True):
1564 if GlobalData
.gCaseInsensitive
:
1565 CaseSensitive
= False
1566 if Type
and Type
.lower() != self
.Type
:
1567 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1569 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1570 if not RealRoot
and not RealFile
:
1571 RealFile
= self
.File
1573 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1575 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1576 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1580 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1581 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1582 ErrorCode
= FILE_CASE_MISMATCH
1583 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1585 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1586 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1588 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1591 self
.File
= RealFile
1592 self
.Root
= RealRoot
1593 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1594 return ErrorCode
, ErrorInfo
1596 Key
= property(_GetFileKey
)
1597 TimeStamp
= property(_GetTimeStamp
)
1599 ## Parse PE image to get the required PE informaion.
1601 class PeImageClass():
1604 # @param File FilePath of PeImage
1606 def __init__(self
, PeFile
):
1607 self
.FileName
= PeFile
1608 self
.IsValid
= False
1611 self
.SectionAlignment
= 0
1612 self
.SectionHeaderList
= []
1615 PeObject
= open(PeFile
, 'rb')
1617 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1620 ByteArray
= array
.array('B')
1621 ByteArray
.fromfile(PeObject
, 0x3E)
1622 ByteList
= ByteArray
.tolist()
1623 # DOS signature should be 'MZ'
1624 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1625 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1628 # Read 4 byte PE Signature
1629 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1630 PeObject
.seek(PeOffset
)
1631 ByteArray
= array
.array('B')
1632 ByteArray
.fromfile(PeObject
, 4)
1633 # PE signature should be 'PE\0\0'
1634 if ByteArray
.tostring() != 'PE\0\0':
1635 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1638 # Read PE file header
1639 ByteArray
= array
.array('B')
1640 ByteArray
.fromfile(PeObject
, 0x14)
1641 ByteList
= ByteArray
.tolist()
1642 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1644 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1647 # Read PE optional header
1648 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1649 ByteArray
= array
.array('B')
1650 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1651 ByteList
= ByteArray
.tolist()
1652 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1653 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1654 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1656 # Read each Section Header
1657 for Index
in range(SecNumber
):
1658 ByteArray
= array
.array('B')
1659 ByteArray
.fromfile(PeObject
, 0x28)
1660 ByteList
= ByteArray
.tolist()
1661 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1662 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1663 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1664 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1665 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1669 def _ByteListToStr(self
, ByteList
):
1671 for index
in range(len(ByteList
)):
1672 if ByteList
[index
] == 0:
1674 String
+= chr(ByteList
[index
])
1677 def _ByteListToInt(self
, ByteList
):
1679 for index
in range(len(ByteList
) - 1, -1, -1):
1680 Value
= (Value
<< 8) |
int(ByteList
[index
])
1685 # This acts like the main() function for the script, unless it is 'import'ed into another
1688 if __name__
== '__main__':