]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
Sync EDKII BaseTools to BaseTools project r2093.
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
CommitLineData
30fdf114
LG
1## @file
2# Common routines used by all tools
3#
6780eef1 4# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
40d841f6 5# This program and the accompanying materials
30fdf114
LG
6# are licensed and made available under the terms and conditions of the BSD License
7# which accompanies this distribution. The full text of the license may be found at
8# http://opensource.org/licenses/bsd-license.php
9#
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12#
13
14##
15# Import Modules
16#
17import os
18import sys
19import string
20import thread
21import threading
22import time
23import re
24import cPickle
52302d4d 25import array
30fdf114
LG
26from UserDict import IterableUserDict
27from UserList import UserList
28
29from Common import EdkLogger as EdkLogger
30from Common import GlobalData as GlobalData
6780eef1 31from DataType import *
30fdf114
LG
32from BuildToolError import *
33
34## Regular expression used to find out place holders in string template
35gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)
36
37## Dictionary used to store file time stamp for quick re-access
38gFileTimeStampCache = {} # {file path : file time stamp}
39
40## Dictionary used to store dependencies of files
41gDependencyDatabase = {} # arch : {file path : [dependent files list]}
42
43## callback routine for processing variable option
44#
45# This function can be used to process variable number of option values. The
46# typical usage of it is specify architecure list on command line.
47# (e.g. <tool> -a IA32 X64 IPF)
48#
49# @param Option Standard callback function parameter
50# @param OptionString Standard callback function parameter
51# @param Value Standard callback function parameter
52# @param Parser Standard callback function parameter
53#
54# @retval
55#
56def ProcessVariableArgument(Option, OptionString, Value, Parser):
57 assert Value is None
58 Value = []
59 RawArgs = Parser.rargs
60 while RawArgs:
61 Arg = RawArgs[0]
62 if (Arg[:2] == "--" and len(Arg) > 2) or \
63 (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"):
64 break
65 Value.append(Arg)
66 del RawArgs[0]
67 setattr(Parser.values, Option.dest, Value)
68
69## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
70#
71# @param Guid The GUID string
72#
73# @retval string The GUID string in C structure style
74#
75def GuidStringToGuidStructureString(Guid):
76 GuidList = Guid.split('-')
77 Result = '{'
78 for Index in range(0,3,1):
79 Result = Result + '0x' + GuidList[Index] + ', '
80 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
81 for Index in range(0,12,2):
82 Result = Result + ', 0x' + GuidList[4][Index:Index+2]
83 Result += '}}'
84 return Result
85
86## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
87#
88# @param GuidValue The GUID value in byte array
89#
90# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
91#
92def GuidStructureByteArrayToGuidString(GuidValue):
93 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
94 guidValueList = guidValueString.split(",")
95 if len(guidValueList) != 16:
96 return ''
97 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
98 try:
99 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
100 int(guidValueList[3], 16),
101 int(guidValueList[2], 16),
102 int(guidValueList[1], 16),
103 int(guidValueList[0], 16),
104 int(guidValueList[5], 16),
105 int(guidValueList[4], 16),
106 int(guidValueList[7], 16),
107 int(guidValueList[6], 16),
108 int(guidValueList[8], 16),
109 int(guidValueList[9], 16),
110 int(guidValueList[10], 16),
111 int(guidValueList[11], 16),
112 int(guidValueList[12], 16),
113 int(guidValueList[13], 16),
114 int(guidValueList[14], 16),
115 int(guidValueList[15], 16)
116 )
117 except:
118 return ''
119
120## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
121#
122# @param GuidValue The GUID value in C structure format
123#
124# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
125#
126def GuidStructureStringToGuidString(GuidValue):
127 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
128 guidValueList = guidValueString.split(",")
129 if len(guidValueList) != 11:
130 return ''
131 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
132 try:
133 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
134 int(guidValueList[0], 16),
135 int(guidValueList[1], 16),
136 int(guidValueList[2], 16),
137 int(guidValueList[3], 16),
138 int(guidValueList[4], 16),
139 int(guidValueList[5], 16),
140 int(guidValueList[6], 16),
141 int(guidValueList[7], 16),
142 int(guidValueList[8], 16),
143 int(guidValueList[9], 16),
144 int(guidValueList[10], 16)
145 )
146 except:
147 return ''
148
149## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
150#
151# @param GuidValue The GUID value in C structure format
152#
153# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
154#
155def GuidStructureStringToGuidValueName(GuidValue):
156 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
157 guidValueList = guidValueString.split(",")
158 if len(guidValueList) != 11:
159 EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
160 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
161 int(guidValueList[0], 16),
162 int(guidValueList[1], 16),
163 int(guidValueList[2], 16),
164 int(guidValueList[3], 16),
165 int(guidValueList[4], 16),
166 int(guidValueList[5], 16),
167 int(guidValueList[6], 16),
168 int(guidValueList[7], 16),
169 int(guidValueList[8], 16),
170 int(guidValueList[9], 16),
171 int(guidValueList[10], 16)
172 )
173
174## Create directories
175#
176# @param Directory The directory name
177#
178def CreateDirectory(Directory):
179 if Directory == None or Directory.strip() == "":
180 return True
181 try:
182 if not os.access(Directory, os.F_OK):
183 os.makedirs(Directory)
184 except:
185 return False
186 return True
187
188## Remove directories, including files and sub-directories in it
189#
190# @param Directory The directory name
191#
192def RemoveDirectory(Directory, Recursively=False):
193 if Directory == None or Directory.strip() == "" or not os.path.exists(Directory):
194 return
195 if Recursively:
196 CurrentDirectory = os.getcwd()
197 os.chdir(Directory)
198 for File in os.listdir("."):
199 if os.path.isdir(File):
200 RemoveDirectory(File, Recursively)
201 else:
202 os.remove(File)
203 os.chdir(CurrentDirectory)
204 os.rmdir(Directory)
205
206## Check if given file is changed or not
207#
208# This method is used to check if a file is changed or not between two build
209# actions. It makes use a cache to store files timestamp.
210#
211# @param File The path of file
212#
213# @retval True If the given file is changed, doesn't exist, or can't be
214# found in timestamp cache
215# @retval False If the given file is changed
216#
217def IsChanged(File):
218 if not os.path.exists(File):
219 return True
220
221 FileState = os.stat(File)
222 TimeStamp = FileState[-2]
223
224 if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]:
225 FileChanged = False
226 else:
227 FileChanged = True
228 gFileTimeStampCache[File] = TimeStamp
229
230 return FileChanged
231
232## Store content in file
233#
234# This method is used to save file only when its content is changed. This is
235# quite useful for "make" system to decide what will be re-built and what won't.
236#
237# @param File The path of file
238# @param Content The new content of the file
239# @param IsBinaryFile The flag indicating if the file is binary file or not
240#
241# @retval True If the file content is changed and the file is renewed
242# @retval False If the file content is the same
243#
244def SaveFileOnChange(File, Content, IsBinaryFile=True):
245 if not IsBinaryFile:
246 Content = Content.replace("\n", os.linesep)
247
248 if os.path.exists(File):
249 try:
250 if Content == open(File, "rb").read():
251 return False
252 except:
253 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
254
255 CreateDirectory(os.path.dirname(File))
256 try:
257 if GlobalData.gIsWindows:
258 try:
259 from PyUtility import SaveFileToDisk
260 if not SaveFileToDisk(File, Content):
261 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
262 except:
263 Fd = open(File, "wb")
264 Fd.write(Content)
265 Fd.close()
266 else:
267 Fd = open(File, "wb")
268 Fd.write(Content)
269 Fd.close()
270 except:
271 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
272
273 return True
274
275## Make a Python object persistent on file system
276#
277# @param Data The object to be stored in file
278# @param File The path of file to store the object
279#
280def DataDump(Data, File):
281 Fd = None
282 try:
283 Fd = open(File, 'wb')
284 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)
285 except:
286 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)
287 finally:
288 if Fd != None:
289 Fd.close()
290
291## Restore a Python object from a file
292#
293# @param File The path of file stored the object
294#
295# @retval object A python object
296# @retval None If failure in file operation
297#
298def DataRestore(File):
299 Data = None
300 Fd = None
301 try:
302 Fd = open(File, 'rb')
303 Data = cPickle.load(Fd)
304 except Exception, e:
305 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))
306 Data = None
307 finally:
308 if Fd != None:
309 Fd.close()
310 return Data
311
312## Retrieve and cache the real path name in file system
313#
314# @param Root The root directory of path relative to
315#
316# @retval str The path string if the path exists
317# @retval None If path doesn't exist
318#
319class DirCache:
b303ea72
LG
320 _CACHE_ = set()
321 _UPPER_CACHE_ = {}
30fdf114
LG
322
323 def __init__(self, Root):
324 self._Root = Root
325 for F in os.listdir(Root):
b303ea72
LG
326 self._CACHE_.add(F)
327 self._UPPER_CACHE_[F.upper()] = F
30fdf114
LG
328
329 # =[] operator
330 def __getitem__(self, Path):
331 Path = Path[len(os.path.commonprefix([Path, self._Root])):]
332 if not Path:
333 return self._Root
334 if Path and Path[0] == os.path.sep:
335 Path = Path[1:]
30fdf114 336 if Path in self._CACHE_:
b303ea72
LG
337 return os.path.join(self._Root, Path)
338 UpperPath = Path.upper()
339 if UpperPath in self._UPPER_CACHE_:
340 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
30fdf114
LG
341
342 IndexList = []
343 LastSepIndex = -1
344 SepIndex = Path.find(os.path.sep)
345 while SepIndex > -1:
b303ea72
LG
346 Parent = UpperPath[:SepIndex]
347 if Parent not in self._UPPER_CACHE_:
30fdf114
LG
348 break
349 LastSepIndex = SepIndex
350 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
351
352 if LastSepIndex == -1:
353 return None
354
355 Cwd = os.getcwd()
356 os.chdir(self._Root)
357 SepIndex = LastSepIndex
358 while SepIndex > -1:
b303ea72
LG
359 Parent = Path[:SepIndex]
360 ParentKey = UpperPath[:SepIndex]
361 if ParentKey not in self._UPPER_CACHE_:
30fdf114
LG
362 os.chdir(Cwd)
363 return None
364
b303ea72
LG
365 if Parent in self._CACHE_:
366 ParentDir = Parent
367 else:
368 ParentDir = self._UPPER_CACHE_[ParentKey]
30fdf114
LG
369 for F in os.listdir(ParentDir):
370 Dir = os.path.join(ParentDir, F)
b303ea72
LG
371 self._CACHE_.add(Dir)
372 self._UPPER_CACHE_[Dir.upper()] = Dir
30fdf114
LG
373
374 SepIndex = Path.find(os.path.sep, SepIndex + 1)
375
376 os.chdir(Cwd)
b303ea72
LG
377 if Path in self._CACHE_:
378 return os.path.join(self._Root, Path)
379 elif UpperPath in self._UPPER_CACHE_:
380 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
381 return None
30fdf114
LG
382
383## Get all files of a directory
384#
385# @param Root: Root dir
386# @param SkipList : The files need be skipped
387#
388# @retval A list of all files
389#
390def GetFiles(Root, SkipList=None, FullPath = True):
391 OriPath = Root
392 FileList = []
393 for Root, Dirs, Files in os.walk(Root):
394 if SkipList:
395 for Item in SkipList:
396 if Item in Dirs:
397 Dirs.remove(Item)
398
399 for File in Files:
400 File = os.path.normpath(os.path.join(Root, File))
401 if not FullPath:
402 File = File[len(OriPath) + 1:]
403 FileList.append(File)
404
405 return FileList
406
407## Check if gvien file exists or not
408#
409# @param File File name or path to be checked
410# @param Dir The directory the file is relative to
411#
412# @retval True if file exists
413# @retval False if file doesn't exists
414#
415def ValidFile(File, Ext=None):
416 if Ext != None:
417 Dummy, FileExt = os.path.splitext(File)
418 if FileExt.lower() != Ext.lower():
419 return False
420 if not os.path.exists(File):
421 return False
422 return True
423
424def RealPath(File, Dir='', OverrideDir=''):
425 NewFile = os.path.normpath(os.path.join(Dir, File))
426 NewFile = GlobalData.gAllFiles[NewFile]
427 if not NewFile and OverrideDir:
428 NewFile = os.path.normpath(os.path.join(OverrideDir, File))
429 NewFile = GlobalData.gAllFiles[NewFile]
430 return NewFile
431
432def RealPath2(File, Dir='', OverrideDir=''):
fd171542 433 if OverrideDir:
434 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
435 if NewFile:
436 if OverrideDir[-1] == os.path.sep:
437 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
438 else:
439 return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)]
440
30fdf114
LG
441 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
442 if NewFile:
443 if Dir:
444 if Dir[-1] == os.path.sep:
445 return NewFile[len(Dir):], NewFile[0:len(Dir)]
446 else:
447 return NewFile[len(Dir)+1:], NewFile[0:len(Dir)]
448 else:
449 return NewFile, ''
450
30fdf114
LG
451 return None, None
452
453## Check if gvien file exists or not
454#
455#
456def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
457 NewFile = File
458 if Ext != None:
459 Dummy, FileExt = os.path.splitext(File)
460 if FileExt.lower() != Ext.lower():
461 return False, File
462
463 # Replace the R8 macros
464 if OverrideDir != '' and OverrideDir != None:
465 if OverrideDir.find('$(EFI_SOURCE)') > -1:
466 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
467 if OverrideDir.find('$(EDK_SOURCE)') > -1:
468 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
469
470 # Replace the default dir to current dir
471 if Dir == '.':
472 Dir = os.getcwd()
473 Dir = Dir[len(Workspace)+1:]
474
475 # First check if File has R8 definition itself
476 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
477 NewFile = File.replace('$(EFI_SOURCE)', EfiSource)
478 NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)
479 NewFile = AllFiles[os.path.normpath(NewFile)]
480 if NewFile != None:
481 return True, NewFile
482
483 # Second check the path with override value
484 if OverrideDir != '' and OverrideDir != None:
485 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
486 if NewFile != None:
487 return True, NewFile
488
489 # Last check the path with normal definitions
490 File = os.path.join(Dir, File)
491 NewFile = AllFiles[os.path.normpath(File)]
492 if NewFile != None:
493 return True, NewFile
494
495 return False, File
496
497## Check if gvien file exists or not
498#
499#
500def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
501 # Replace the R8 macros
502 if OverrideDir != '' and OverrideDir != None:
503 if OverrideDir.find('$(EFI_SOURCE)') > -1:
504 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
505 if OverrideDir.find('$(EDK_SOURCE)') > -1:
506 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
507
508 # Replace the default dir to current dir
509 # Dir is current module dir related to workspace
510 if Dir == '.':
511 Dir = os.getcwd()
512 Dir = Dir[len(Workspace)+1:]
513
514 NewFile = File
515 RelaPath = AllFiles[os.path.normpath(Dir)]
516 NewRelaPath = RelaPath
517
518 while(True):
519 # First check if File has R8 definition itself
520 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
521 File = File.replace('$(EFI_SOURCE)', EfiSource)
522 File = File.replace('$(EDK_SOURCE)', EdkSource)
523 NewFile = AllFiles[os.path.normpath(File)]
524 if NewFile != None:
525 NewRelaPath = os.path.dirname(NewFile)
526 File = os.path.basename(NewFile)
527 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
528 break
529
530 # Second check the path with override value
531 if OverrideDir != '' and OverrideDir != None:
532 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
533 if NewFile != None:
534 #NewRelaPath = os.path.dirname(NewFile)
535 NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
536 break
537
538 # Last check the path with normal definitions
539 NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))]
540 if NewFile != None:
541 break
542
543 # No file found
544 break
545
546 return NewRelaPath, RelaPath, File
547
548
549def GetRelPath(Path1, Path2):
550 FileName = os.path.basename(Path2)
551 L1 = os.path.normpath(Path1).split(os.path.normpath('/'))
552 L2 = os.path.normpath(Path2).split(os.path.normpath('/'))
553 for Index in range(0, len(L1)):
554 if L1[Index] != L2[Index]:
555 FileName = '../' * (len(L1) - Index)
556 for Index2 in range(Index, len(L2)):
557 FileName = os.path.join(FileName, L2[Index2])
558 break
559 return os.path.normpath(FileName)
560
561
562## Get GUID value from given packages
563#
564# @param CName The CName of the GUID
565# @param PackageList List of packages looking-up in
566#
567# @retval GuidValue if the CName is found in any given package
568# @retval None if the CName is not found in all given packages
569#
570def GuidValue(CName, PackageList):
571 for P in PackageList:
572 if CName in P.Guids:
573 return P.Guids[CName]
574 return None
575
576## Get Protocol value from given packages
577#
578# @param CName The CName of the GUID
579# @param PackageList List of packages looking-up in
580#
581# @retval GuidValue if the CName is found in any given package
582# @retval None if the CName is not found in all given packages
583#
584def ProtocolValue(CName, PackageList):
585 for P in PackageList:
586 if CName in P.Protocols:
587 return P.Protocols[CName]
588 return None
589
590## Get PPI value from given packages
591#
592# @param CName The CName of the GUID
593# @param PackageList List of packages looking-up in
594#
595# @retval GuidValue if the CName is found in any given package
596# @retval None if the CName is not found in all given packages
597#
598def PpiValue(CName, PackageList):
599 for P in PackageList:
600 if CName in P.Ppis:
601 return P.Ppis[CName]
602 return None
603
604## A string template class
605#
606# This class implements a template for string replacement. A string template
607# looks like following
608#
609# ${BEGIN} other_string ${placeholder_name} other_string ${END}
610#
611# The string between ${BEGIN} and ${END} will be repeated as many times as the
612# length of "placeholder_name", which is a list passed through a dict. The
613# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
614# be not used and, in this case, the "placeholder_name" must not a list and it
615# will just be replaced once.
616#
617class TemplateString(object):
618 _REPEAT_START_FLAG = "BEGIN"
619 _REPEAT_END_FLAG = "END"
620
621 class Section(object):
622 _LIST_TYPES = [type([]), type(set()), type((0,))]
623
624 def __init__(self, TemplateSection, PlaceHolderList):
625 self._Template = TemplateSection
626 self._PlaceHolderList = []
627
628 # Split the section into sub-sections according to the position of placeholders
629 if PlaceHolderList:
630 self._SubSectionList = []
631 SubSectionStart = 0
632 #
633 # The placeholders passed in must be in the format of
634 #
635 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
636 #
637 for PlaceHolder,Start,End in PlaceHolderList:
638 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
639 self._SubSectionList.append(TemplateSection[Start:End])
640 self._PlaceHolderList.append(PlaceHolder)
641 SubSectionStart = End
642 if SubSectionStart < len(TemplateSection):
643 self._SubSectionList.append(TemplateSection[SubSectionStart:])
644 else:
645 self._SubSectionList = [TemplateSection]
646
647 def __str__(self):
648 return self._Template + " : " + str(self._PlaceHolderList)
649
650 def Instantiate(self, PlaceHolderValues):
651 RepeatTime = -1
652 RepeatPlaceHolders = {}
653 NonRepeatPlaceHolders = {}
654
655 for PlaceHolder in self._PlaceHolderList:
656 if PlaceHolder not in PlaceHolderValues:
657 continue
658 Value = PlaceHolderValues[PlaceHolder]
659 if type(Value) in self._LIST_TYPES:
660 if RepeatTime < 0:
661 RepeatTime = len(Value)
662 elif RepeatTime != len(Value):
663 EdkLogger.error(
664 "TemplateString",
665 PARAMETER_INVALID,
666 "${%s} has different repeat time from others!" % PlaceHolder,
667 ExtraData=str(self._Template)
668 )
669 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
670 else:
671 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
672
673 if NonRepeatPlaceHolders:
674 StringList = []
675 for S in self._SubSectionList:
676 if S not in NonRepeatPlaceHolders:
677 StringList.append(S)
678 else:
679 StringList.append(str(NonRepeatPlaceHolders[S]))
680 else:
681 StringList = self._SubSectionList
682
683 if RepeatPlaceHolders:
684 TempStringList = []
685 for Index in range(RepeatTime):
686 for S in StringList:
687 if S not in RepeatPlaceHolders:
688 TempStringList.append(S)
689 else:
690 TempStringList.append(str(RepeatPlaceHolders[S][Index]))
691 StringList = TempStringList
692
693 return "".join(StringList)
694
695 ## Constructor
696 def __init__(self, Template=None):
697 self.String = ''
b303ea72 698 self.IsBinary = False
30fdf114
LG
699 self._Template = Template
700 self._TemplateSectionList = self._Parse(Template)
701
702 ## str() operator
703 #
704 # @retval string The string replaced
705 #
706 def __str__(self):
707 return self.String
708
709 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
710 #
711 # @retval list A list of TemplateString.Section objects
712 #
713 def _Parse(self, Template):
714 SectionStart = 0
715 SearchFrom = 0
716 MatchEnd = 0
717 PlaceHolderList = []
718 TemplateSectionList = []
719 while Template:
720 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
721 if not MatchObj:
e56468c0 722 if MatchEnd <= len(Template):
30fdf114
LG
723 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
724 TemplateSectionList.append(TemplateSection)
725 break
726
727 MatchString = MatchObj.group(1)
728 MatchStart = MatchObj.start()
729 MatchEnd = MatchObj.end()
730
731 if MatchString == self._REPEAT_START_FLAG:
732 if MatchStart > SectionStart:
733 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
734 TemplateSectionList.append(TemplateSection)
735 SectionStart = MatchEnd
736 PlaceHolderList = []
737 elif MatchString == self._REPEAT_END_FLAG:
738 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
739 TemplateSectionList.append(TemplateSection)
740 SectionStart = MatchEnd
741 PlaceHolderList = []
742 else:
743 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
744 SearchFrom = MatchEnd
745 return TemplateSectionList
746
747 ## Replace the string template with dictionary of placeholders and append it to previous one
748 #
749 # @param AppendString The string template to append
750 # @param Dictionary The placeholder dictionaries
751 #
752 def Append(self, AppendString, Dictionary=None):
753 if Dictionary:
754 SectionList = self._Parse(AppendString)
755 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])
756 else:
757 self.String += AppendString
758
759 ## Replace the string template with dictionary of placeholders
760 #
761 # @param Dictionary The placeholder dictionaries
762 #
763 # @retval str The string replaced with placeholder values
764 #
765 def Replace(self, Dictionary=None):
766 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])
767
768## Progress indicator class
769#
770# This class makes use of thread to print progress on console.
771#
772class Progressor:
773 # for avoiding deadloop
774 _StopFlag = None
775 _ProgressThread = None
776 _CheckInterval = 0.25
777
778 ## Constructor
779 #
780 # @param OpenMessage The string printed before progress charaters
781 # @param CloseMessage The string printed after progress charaters
782 # @param ProgressChar The charater used to indicate the progress
783 # @param Interval The interval in seconds between two progress charaters
784 #
785 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
786 self.PromptMessage = OpenMessage
787 self.CodaMessage = CloseMessage
788 self.ProgressChar = ProgressChar
789 self.Interval = Interval
790 if Progressor._StopFlag == None:
791 Progressor._StopFlag = threading.Event()
792
793 ## Start to print progress charater
794 #
795 # @param OpenMessage The string printed before progress charaters
796 #
797 def Start(self, OpenMessage=None):
798 if OpenMessage != None:
799 self.PromptMessage = OpenMessage
800 Progressor._StopFlag.clear()
801 if Progressor._ProgressThread == None:
802 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
803 Progressor._ProgressThread.setDaemon(False)
804 Progressor._ProgressThread.start()
805
806 ## Stop printing progress charater
807 #
808 # @param CloseMessage The string printed after progress charaters
809 #
810 def Stop(self, CloseMessage=None):
811 OriginalCodaMessage = self.CodaMessage
812 if CloseMessage != None:
813 self.CodaMessage = CloseMessage
814 self.Abort()
815 self.CodaMessage = OriginalCodaMessage
816
817 ## Thread entry method
818 def _ProgressThreadEntry(self):
819 sys.stdout.write(self.PromptMessage + " ")
820 sys.stdout.flush()
821 TimeUp = 0.0
822 while not Progressor._StopFlag.isSet():
823 if TimeUp <= 0.0:
824 sys.stdout.write(self.ProgressChar)
825 sys.stdout.flush()
826 TimeUp = self.Interval
827 time.sleep(self._CheckInterval)
828 TimeUp -= self._CheckInterval
829 sys.stdout.write(" " + self.CodaMessage + "\n")
830 sys.stdout.flush()
831
832 ## Abort the progress display
833 @staticmethod
834 def Abort():
835 if Progressor._StopFlag != None:
836 Progressor._StopFlag.set()
837 if Progressor._ProgressThread != None:
838 Progressor._ProgressThread.join()
839 Progressor._ProgressThread = None
840
841## A dict which can access its keys and/or values orderly
842#
843# The class implements a new kind of dict which its keys or values can be
844# accessed in the order they are added into the dict. It guarantees the order
845# by making use of an internal list to keep a copy of keys.
846#
847class sdict(IterableUserDict):
848 ## Constructor
849 def __init__(self):
850 IterableUserDict.__init__(self)
851 self._key_list = []
852
853 ## [] operator
854 def __setitem__(self, key, value):
855 if key not in self._key_list:
856 self._key_list.append(key)
857 IterableUserDict.__setitem__(self, key, value)
858
859 ## del operator
860 def __delitem__(self, key):
861 self._key_list.remove(key)
862 IterableUserDict.__delitem__(self, key)
863
864 ## used in "for k in dict" loop to ensure the correct order
865 def __iter__(self):
866 return self.iterkeys()
867
868 ## len() support
869 def __len__(self):
870 return len(self._key_list)
871
872 ## "in" test support
873 def __contains__(self, key):
874 return key in self._key_list
875
876 ## indexof support
877 def index(self, key):
878 return self._key_list.index(key)
879
880 ## insert support
881 def insert(self, key, newkey, newvalue, order):
882 index = self._key_list.index(key)
883 if order == 'BEFORE':
884 self._key_list.insert(index, newkey)
885 IterableUserDict.__setitem__(self, newkey, newvalue)
886 elif order == 'AFTER':
887 self._key_list.insert(index + 1, newkey)
888 IterableUserDict.__setitem__(self, newkey, newvalue)
889
890 ## append support
891 def append(self, sdict):
892 for key in sdict:
893 if key not in self._key_list:
894 self._key_list.append(key)
895 IterableUserDict.__setitem__(self, key, sdict[key])
896
897 def has_key(self, key):
898 return key in self._key_list
899
900 ## Empty the dict
901 def clear(self):
902 self._key_list = []
903 IterableUserDict.clear(self)
904
905 ## Return a copy of keys
906 def keys(self):
907 keys = []
908 for key in self._key_list:
909 keys.append(key)
910 return keys
911
912 ## Return a copy of values
913 def values(self):
914 values = []
915 for key in self._key_list:
916 values.append(self[key])
917 return values
918
919 ## Return a copy of (key, value) list
920 def items(self):
921 items = []
922 for key in self._key_list:
923 items.append((key, self[key]))
924 return items
925
926 ## Iteration support
927 def iteritems(self):
928 return iter(self.items())
929
930 ## Keys interation support
931 def iterkeys(self):
932 return iter(self.keys())
933
934 ## Values interation support
935 def itervalues(self):
936 return iter(self.values())
937
938 ## Return value related to a key, and remove the (key, value) from the dict
939 def pop(self, key, *dv):
940 value = None
941 if key in self._key_list:
942 value = self[key]
943 self.__delitem__(key)
944 elif len(dv) != 0 :
945 value = kv[0]
946 return value
947
948 ## Return (key, value) pair, and remove the (key, value) from the dict
949 def popitem(self):
950 key = self._key_list[-1]
951 value = self[key]
952 self.__delitem__(key)
953 return key, value
954
955 def update(self, dict=None, **kwargs):
956 if dict != None:
957 for k, v in dict.items():
958 self[k] = v
959 if len(kwargs):
960 for k, v in kwargs.items():
961 self[k] = v
962
963## Dictionary with restricted keys
964#
965class rdict(dict):
966 ## Constructor
967 def __init__(self, KeyList):
968 for Key in KeyList:
969 dict.__setitem__(self, Key, "")
970
971 ## []= operator
972 def __setitem__(self, key, value):
973 if key not in self:
974 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,
975 ExtraData=", ".join(dict.keys(self)))
976 dict.__setitem__(self, key, value)
977
978 ## =[] operator
979 def __getitem__(self, key):
980 if key not in self:
981 return ""
982 return dict.__getitem__(self, key)
983
984 ## del operator
985 def __delitem__(self, key):
986 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")
987
988 ## Empty the dict
989 def clear(self):
990 for Key in self:
991 self.__setitem__(Key, "")
992
993 ## Return value related to a key, and remove the (key, value) from the dict
994 def pop(self, key, *dv):
995 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")
996
997 ## Return (key, value) pair, and remove the (key, value) from the dict
998 def popitem(self):
999 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")
1000
1001## Dictionary using prioritized list as key
1002#
1003class tdict:
1004 _ListType = type([])
1005 _TupleType = type(())
1006 _Wildcard = 'COMMON'
1007 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1008
1009 def __init__(self, _Single_=False, _Level_=2):
1010 self._Level_ = _Level_
1011 self.data = {}
1012 self._Single_ = _Single_
1013
1014 # =[] operator
1015 def __getitem__(self, key):
1016 KeyType = type(key)
1017 RestKeys = None
1018 if KeyType == self._ListType or KeyType == self._TupleType:
1019 FirstKey = key[0]
1020 if len(key) > 1:
1021 RestKeys = key[1:]
1022 elif self._Level_ > 1:
1023 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1024 else:
1025 FirstKey = key
1026 if self._Level_ > 1:
1027 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1028
1029 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:
1030 FirstKey = self._Wildcard
1031
1032 if self._Single_:
1033 return self._GetSingleValue(FirstKey, RestKeys)
1034 else:
1035 return self._GetAllValues(FirstKey, RestKeys)
1036
1037 def _GetSingleValue(self, FirstKey, RestKeys):
1038 Value = None
1039 #print "%s-%s" % (FirstKey, self._Level_) ,
1040 if self._Level_ > 1:
1041 if FirstKey == self._Wildcard:
1042 if FirstKey in self.data:
1043 Value = self.data[FirstKey][RestKeys]
1044 if Value == None:
1045 for Key in self.data:
1046 Value = self.data[Key][RestKeys]
1047 if Value != None: break
1048 else:
1049 if FirstKey in self.data:
1050 Value = self.data[FirstKey][RestKeys]
1051 if Value == None and self._Wildcard in self.data:
1052 #print "Value=None"
1053 Value = self.data[self._Wildcard][RestKeys]
1054 else:
1055 if FirstKey == self._Wildcard:
1056 if FirstKey in self.data:
1057 Value = self.data[FirstKey]
1058 if Value == None:
1059 for Key in self.data:
1060 Value = self.data[Key]
1061 if Value != None: break
1062 else:
1063 if FirstKey in self.data:
1064 Value = self.data[FirstKey]
1065 elif self._Wildcard in self.data:
1066 Value = self.data[self._Wildcard]
1067 return Value
1068
1069 def _GetAllValues(self, FirstKey, RestKeys):
1070 Value = []
1071 if self._Level_ > 1:
1072 if FirstKey == self._Wildcard:
1073 for Key in self.data:
1074 Value += self.data[Key][RestKeys]
1075 else:
1076 if FirstKey in self.data:
1077 Value += self.data[FirstKey][RestKeys]
1078 if self._Wildcard in self.data:
1079 Value += self.data[self._Wildcard][RestKeys]
1080 else:
1081 if FirstKey == self._Wildcard:
1082 for Key in self.data:
1083 Value.append(self.data[Key])
1084 else:
1085 if FirstKey in self.data:
1086 Value.append(self.data[FirstKey])
1087 if self._Wildcard in self.data:
1088 Value.append(self.data[self._Wildcard])
1089 return Value
1090
1091 ## []= operator
1092 def __setitem__(self, key, value):
1093 KeyType = type(key)
1094 RestKeys = None
1095 if KeyType == self._ListType or KeyType == self._TupleType:
1096 FirstKey = key[0]
1097 if len(key) > 1:
1098 RestKeys = key[1:]
1099 else:
1100 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1101 else:
1102 FirstKey = key
1103 if self._Level_ > 1:
1104 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1105
1106 if FirstKey in self._ValidWildcardList:
1107 FirstKey = self._Wildcard
1108
1109 if FirstKey not in self.data and self._Level_ > 0:
1110 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
1111
1112 if self._Level_ > 1:
1113 self.data[FirstKey][RestKeys] = value
1114 else:
1115 self.data[FirstKey] = value
1116
1117 def SetGreedyMode(self):
1118 self._Single_ = False
1119 if self._Level_ > 1:
1120 for Key in self.data:
1121 self.data[Key].SetGreedyMode()
1122
1123 def SetSingleMode(self):
1124 self._Single_ = True
1125 if self._Level_ > 1:
1126 for Key in self.data:
1127 self.data[Key].SetSingleMode()
1128
a709adfa
LG
1129 def GetKeys(self, KeyIndex=0):
1130 assert KeyIndex >= 0
1131 if KeyIndex == 0:
1132 return set(self.data.keys())
1133 else:
1134 keys = set()
1135 for Key in self.data:
1136 keys |= self.data[Key].GetKeys(KeyIndex - 1)
1137 return keys
1138
30fdf114
LG
1139## Boolean chain list
1140#
1141class Blist(UserList):
1142 def __init__(self, initlist=None):
1143 UserList.__init__(self, initlist)
1144 def __setitem__(self, i, item):
1145 if item not in [True, False]:
1146 if item == 0:
1147 item = False
1148 else:
1149 item = True
1150 self.data[i] = item
1151 def _GetResult(self):
1152 Value = True
1153 for item in self.data:
1154 Value &= item
1155 return Value
1156 Result = property(_GetResult)
1157
1158def ParseConsoleLog(Filename):
1159 Opr = open(os.path.normpath(Filename), 'r')
1160 Opw = open(os.path.normpath(Filename + '.New'), 'w+')
1161 for Line in Opr.readlines():
1162 if Line.find('.efi') > -1:
1163 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()
1164 Opw.write('%s\n' % Line)
1165
1166 Opr.close()
1167 Opw.close()
1168
6780eef1
LG
1169## AnalyzePcdData
1170#
1171# Analyze the pcd Value, Datum type and TokenNumber.
1172# Used to avoid split issue while the value string contain "|" character
1173#
1174# @param[in] Setting: A String contain value/datum type/token number information;
1175#
1176# @retval ValueList: A List contain value, datum type and toke number.
1177#
1178def AnalyzePcdData(Setting):
1179 ValueList = ['', '', '']
1180
1181 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1182 PtrValue = ValueRe.findall(Setting)
1183
1184 ValueUpdateFlag = False
1185
1186 if len(PtrValue) >= 1:
1187 Setting = re.sub(ValueRe, '', Setting)
1188 ValueUpdateFlag = True
1189
1190 TokenList = Setting.split(TAB_VALUE_SPLIT)
1191 ValueList[0:len(TokenList)] = TokenList
1192
1193 if ValueUpdateFlag:
1194 ValueList[0] = PtrValue[0]
1195
1196 return ValueList
1197
1198## AnalyzeHiiPcdData
1199#
1200# Analyze the pcd Value, variable name, variable Guid and variable offset.
1201# Used to avoid split issue while the value string contain "|" character
1202#
1203# @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1204#
1205# @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1206#
1207def AnalyzeHiiPcdData(Setting):
1208 ValueList = ['', '', '', '']
1209
1210 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1211 PtrValue = ValueRe.findall(Setting)
1212
1213 ValueUpdateFlag = False
1214
1215 if len(PtrValue) >= 1:
1216 Setting = re.sub(ValueRe, '', Setting)
1217 ValueUpdateFlag = True
1218
1219 TokenList = Setting.split(TAB_VALUE_SPLIT)
1220 ValueList[0:len(TokenList)] = TokenList
1221
1222 if ValueUpdateFlag:
1223 ValueList[0] = PtrValue[0]
1224
1225 return ValueList
1226
1227## AnalyzeVpdPcdData
1228#
1229# Analyze the vpd pcd Value, Datum type and TokenNumber.
1230# Used to avoid split issue while the value string contain "|" character
1231#
1232# @param[in] Setting: A String contain value/datum type/token number information;
1233#
1234# @retval ValueList: A List contain value, datum type and toke number.
1235#
1236def AnalyzeVpdPcdData(Setting):
1237 ValueList = ['', '', '']
1238
1239 ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')
1240 PtrValue = ValueRe.findall(Setting)
1241
1242 ValueUpdateFlag = False
1243
1244 if len(PtrValue) >= 1:
1245 Setting = re.sub(ValueRe, '', Setting)
1246 ValueUpdateFlag = True
1247
1248 TokenList = Setting.split(TAB_VALUE_SPLIT)
1249 ValueList[0:len(TokenList)] = TokenList
1250
1251 if ValueUpdateFlag:
1252 ValueList[2] = PtrValue[0]
1253
1254 return ValueList
1255
30fdf114
LG
1256## check format of PCD value against its the datum type
1257#
1258# For PCD value setting
1259#
1260def CheckPcdDatum(Type, Value):
1261 if Type == "VOID*":
a7252680 1262 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))
30fdf114
LG
1263 or (Value.startswith('{') and Value.endswith('}'))
1264 ):
1265 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1266 ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
1267 elif Type == 'BOOLEAN':
a7252680
LG
1268 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1269 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1270 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)
30fdf114
LG
1271 elif type(Value) == type(""):
1272 try:
1273 Value = long(Value, 0)
1274 except:
1275 return False, "Invalid value [%s] of type [%s];"\
1276 " must be a hexadecimal, decimal or octal in C language format."\
1277 % (Value, Type)
1278
1279 return True, ""
1280
1281## Split command line option string to list
1282#
1283# subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1284# in non-windows platform to launch command
1285#
1286def SplitOption(OptionString):
1287 OptionList = []
1288 LastChar = " "
1289 OptionStart = 0
1290 QuotationMark = ""
1291 for Index in range(0, len(OptionString)):
1292 CurrentChar = OptionString[Index]
1293 if CurrentChar in ['"', "'"]:
1294 if QuotationMark == CurrentChar:
1295 QuotationMark = ""
1296 elif QuotationMark == "":
1297 QuotationMark = CurrentChar
1298 continue
1299 elif QuotationMark:
1300 continue
1301
1302 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
1303 if Index > OptionStart:
1304 OptionList.append(OptionString[OptionStart:Index-1])
1305 OptionStart = Index
1306 LastChar = CurrentChar
1307 OptionList.append(OptionString[OptionStart:])
1308 return OptionList
1309
1310def CommonPath(PathList):
1311 P1 = min(PathList).split(os.path.sep)
1312 P2 = max(PathList).split(os.path.sep)
1313 for Index in xrange(min(len(P1), len(P2))):
1314 if P1[Index] != P2[Index]:
1315 return os.path.sep.join(P1[:Index])
1316 return os.path.sep.join(P1)
1317
1318class PathClass(object):
1319 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
1320 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):
1321 self.Arch = Arch
1322 self.File = str(File)
1323 if os.path.isabs(self.File):
1324 self.Root = ''
1325 self.AlterRoot = ''
1326 else:
1327 self.Root = str(Root)
1328 self.AlterRoot = str(AlterRoot)
1329
1330 # Remove any '.' and '..' in path
1331 if self.Root:
1332 self.Path = os.path.normpath(os.path.join(self.Root, self.File))
1333 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
1334 # eliminate the side-effect of 'C:'
1335 if self.Root[-1] == ':':
1336 self.Root += os.path.sep
1337 # file path should not start with path separator
1338 if self.Root[-1] == os.path.sep:
1339 self.File = self.Path[len(self.Root):]
1340 else:
1341 self.File = self.Path[len(self.Root)+1:]
1342 else:
1343 self.Path = os.path.normpath(self.File)
1344
1345 self.SubDir, self.Name = os.path.split(self.File)
1346 self.BaseName, self.Ext = os.path.splitext(self.Name)
1347
1348 if self.Root:
1349 if self.SubDir:
1350 self.Dir = os.path.join(self.Root, self.SubDir)
1351 else:
1352 self.Dir = self.Root
1353 else:
1354 self.Dir = self.SubDir
1355
1356 if IsBinary:
1357 self.Type = Type
1358 else:
1359 self.Type = self.Ext.lower()
1360
1361 self.IsBinary = IsBinary
1362 self.Target = Target
1363 self.TagName = TagName
1364 self.ToolCode = ToolCode
1365 self.ToolChainFamily = ToolChainFamily
1366
1367 self._Key = None
1368
1369 ## Convert the object of this class to a string
1370 #
1371 # Convert member Path of the class to a string
1372 #
1373 # @retval string Formatted String
1374 #
1375 def __str__(self):
1376 return self.Path
1377
1378 ## Override __eq__ function
1379 #
1380 # Check whether PathClass are the same
1381 #
1382 # @retval False The two PathClass are different
1383 # @retval True The two PathClass are the same
1384 #
1385 def __eq__(self, Other):
1386 if type(Other) == type(self):
1387 return self.Path == Other.Path
1388 else:
1389 return self.Path == str(Other)
1390
1391 ## Override __hash__ function
1392 #
1393 # Use Path as key in hash table
1394 #
1395 # @retval string Key for hash table
1396 #
1397 def __hash__(self):
1398 return hash(self.Path)
1399
1400 def _GetFileKey(self):
1401 if self._Key == None:
1402 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1403 return self._Key
1404
1405 def Validate(self, Type='', CaseSensitive=True):
1406 if GlobalData.gCaseInsensitive:
1407 CaseSensitive = False
1408 if Type and Type.lower() != self.Type:
1409 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)
1410
1411 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
1412 if not RealRoot and not RealFile:
40d841f6
LG
1413 RealFile = self.File
1414 if self.AlterRoot:
1415 RealFile = os.path.join(self.AlterRoot, self.File)
1416 elif self.Root:
1417 RealFile = os.path.join(self.Root, self.File)
1418 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
30fdf114
LG
1419
1420 ErrorCode = 0
1421 ErrorInfo = ''
1422 if RealRoot != self.Root or RealFile != self.File:
1423 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):
1424 ErrorCode = FILE_CASE_MISMATCH
1425 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"
1426
1427 self.SubDir, self.Name = os.path.split(RealFile)
1428 self.BaseName, self.Ext = os.path.splitext(self.Name)
1429 if self.SubDir:
1430 self.Dir = os.path.join(RealRoot, self.SubDir)
1431 else:
1432 self.Dir = RealRoot
1433 self.File = RealFile
1434 self.Root = RealRoot
1435 self.Path = os.path.join(RealRoot, RealFile)
1436 return ErrorCode, ErrorInfo
1437
1438 Key = property(_GetFileKey)
1439
52302d4d
LG
1440## Parse PE image to get the required PE informaion.
1441#
1442class PeImageClass():
1443 ## Constructor
1444 #
1445 # @param File FilePath of PeImage
1446 #
1447 def __init__(self, PeFile):
1448 self.FileName = PeFile
1449 self.IsValid = False
1450 self.Size = 0
1451 self.EntryPoint = 0
1452 self.SectionAlignment = 0
1453 self.SectionHeaderList = []
1454 self.ErrorInfo = ''
1455 try:
1456 PeObject = open(PeFile, 'rb')
1457 except:
1458 self.ErrorInfo = self.FileName + ' can not be found\n'
1459 return
1460 # Read DOS header
1461 ByteArray = array.array('B')
1462 ByteArray.fromfile(PeObject, 0x3E)
1463 ByteList = ByteArray.tolist()
1464 # DOS signature should be 'MZ'
1465 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':
1466 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'
1467 return
1468
1469 # Read 4 byte PE Signature
1470 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])
1471 PeObject.seek(PeOffset)
1472 ByteArray = array.array('B')
1473 ByteArray.fromfile(PeObject, 4)
1474 # PE signature should be 'PE\0\0'
1475 if ByteArray.tostring() != 'PE\0\0':
1476 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'
1477 return
1478
1479 # Read PE file header
1480 ByteArray = array.array('B')
1481 ByteArray.fromfile(PeObject, 0x14)
1482 ByteList = ByteArray.tolist()
1483 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])
1484 if SecNumber == 0:
1485 self.ErrorInfo = self.FileName + ' has no section header'
1486 return
1487
1488 # Read PE optional header
1489 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])
1490 ByteArray = array.array('B')
1491 ByteArray.fromfile(PeObject, OptionalHeaderSize)
1492 ByteList = ByteArray.tolist()
1493 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])
1494 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])
1495 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])
1496
1497 # Read each Section Header
1498 for Index in range(SecNumber):
1499 ByteArray = array.array('B')
1500 ByteArray.fromfile(PeObject, 0x28)
1501 ByteList = ByteArray.tolist()
1502 SecName = self._ByteListToStr(ByteList[0:8])
1503 SecVirtualSize = self._ByteListToInt(ByteList[8:12])
1504 SecRawAddress = self._ByteListToInt(ByteList[20:24])
1505 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])
1506 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))
1507 self.IsValid = True
1508 PeObject.close()
1509
1510 def _ByteListToStr(self, ByteList):
1511 String = ''
1512 for index in range(len(ByteList)):
1513 if ByteList[index] == 0:
1514 break
1515 String += chr(ByteList[index])
1516 return String
1517
1518 def _ByteListToInt(self, ByteList):
1519 Value = 0
1520 for index in range(len(ByteList) - 1, -1, -1):
1521 Value = (Value << 8) | int(ByteList[index])
1522 return Value
1523
30fdf114
LG
1524##
1525#
1526# This acts like the main() function for the script, unless it is 'import'ed into another
1527# script.
1528#
1529if __name__ == '__main__':
1530 pass
1531