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