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