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