2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
28 from struct
import pack
29 from UserDict
import IterableUserDict
30 from UserList
import UserList
32 from Common
import EdkLogger
as EdkLogger
33 from Common
import GlobalData
as GlobalData
34 from .DataType
import *
35 from .BuildToolError
import *
36 from CommonDataClass
.DataClass
import *
37 from .Parsing
import GetSplitValueList
38 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
39 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
41 from CommonDataClass
.Exceptions
import BadExpression
43 ## Regular expression used to find out place holders in string template
44 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
46 ## regular expressions for map file processing
47 startPatternGeneral
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
48 addressPatternGeneral
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
49 valuePatternGcc
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
50 pcdPatternGcc
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
51 secReGeneral
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
53 ## Dictionary used to store file time stamp for quick re-access
54 gFileTimeStampCache
= {} # {file path : file time stamp}
56 ## Dictionary used to store dependencies of files
57 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
60 # If a module is built more than once with different PCDs or library classes
61 # a temporary INF file with same content is created, the temporary file is removed
66 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
67 """ Parse map file to get variable offset in current EFI file
68 @param mapfilepath Map file absolution path
69 @param efifilepath: EFI binary file full path
70 @param varnames iteratable container whose elements are variable names to be searched
72 @return List whos elements are tuple with variable name and raw offset
76 f
= open(mapfilepath
, 'r')
82 if len(lines
) == 0: return None
83 firstline
= lines
[0].strip()
84 if (firstline
.startswith("Archive member included ") and
85 firstline
.endswith(" file (symbol)")):
86 return _parseForGCC(lines
, efifilepath
, varnames
)
87 if firstline
.startswith("# Path:"):
88 return _parseForXcode(lines
, efifilepath
, varnames
)
89 return _parseGeneral(lines
, efifilepath
, varnames
)
91 def _parseForXcode(lines
, efifilepath
, varnames
):
96 if status
== 0 and line
== "# Symbols:":
99 if status
== 1 and len(line
) != 0:
100 for varname
in varnames
:
102 # cannot pregenerate this RegEx since it uses varname from varnames.
103 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
105 ret
.append((varname
, m
.group(1)))
108 def _parseForGCC(lines
, efifilepath
, varnames
):
109 """ Parse map file generated by GCC linker """
113 for index
, line
in enumerate(lines
):
115 # status machine transection
116 if status
== 0 and line
== "Memory Configuration":
119 elif status
== 1 and line
== 'Linker script and memory map':
122 elif status
==2 and line
== 'START GROUP':
128 m
= valuePatternGcc
.match(line
)
130 sections
.append(m
.groups(0))
131 for varname
in varnames
:
133 m
= re
.match("^.data.(%s)" % varname
, line
)
135 m
= re
.match(".data.(%s)$" % varname
, line
)
137 Str
= lines
[index
+ 1]
139 Str
= line
[len(".data.%s" % varname
):]
141 m
= pcdPatternGcc
.match(Str
.strip())
143 varoffset
.append((varname
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
147 # get section information from efi file
148 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
149 if efisecs
is None or len(efisecs
) == 0:
153 for efisec
in efisecs
:
154 for section
in sections
:
155 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
156 redirection
= int(section
[1], 16) - efisec
[1]
159 for var
in varoffset
:
160 for efisec
in efisecs
:
161 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
162 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
165 def _parseGeneral(lines
, efifilepath
, varnames
):
166 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
167 secs
= [] # key = section name
169 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
173 if startPatternGeneral
.match(line
):
176 if addressPatternGeneral
.match(line
):
179 if line
.startswith("entry point at"):
182 if status
== 1 and len(line
) != 0:
183 m
= secReGeneral
.match(line
)
184 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
185 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
186 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
187 if status
== 2 and len(line
) != 0:
188 for varname
in varnames
:
189 m
= symRe
.match(line
)
190 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
191 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
192 sec_no
= int(sec_no
, 16)
193 sym_offset
= int(sym_offset
, 16)
194 vir_addr
= int(vir_addr
, 16)
195 # cannot pregenerate this RegEx since it uses varname from varnames.
196 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
198 # fond a binary pcd entry in map file
200 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
201 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
203 if not varoffset
: return []
205 # get section information from efi file
206 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
207 if efisecs
is None or len(efisecs
) == 0:
211 for var
in varoffset
:
213 for efisec
in efisecs
:
215 if var
[1].strip() == efisec
[0].strip():
216 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
217 elif var
[4] == index
:
218 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
222 ## Routine to process duplicated INF
224 # This function is called by following two cases:
227 # Pkg/module/module.inf
228 # Pkg/module/module.inf {
230 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
233 # INF Pkg/module/module.inf
234 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
236 # This function copies Pkg/module/module.inf to
237 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
239 # @param Path Original PathClass object
240 # @param BaseName New file base name
242 # @retval return the new PathClass object
244 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
245 Filename
= os
.path
.split(Path
.File
)[1]
247 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
249 Filename
= BaseName
+ Path
.BaseName
252 # If -N is specified on command line, cache is disabled
253 # The directory has to be created
255 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
256 if not os
.path
.exists(DbDir
):
259 # A temporary INF is copied to database path which must have write permission
260 # The temporary will be removed at the end of build
261 # In case of name conflict, the file name is
262 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
264 TempFullPath
= os
.path
.join(DbDir
,
266 RtPath
= PathClass(Path
.File
, Workspace
)
268 # Modify the full path to temporary path, keep other unchanged
270 # To build same module more than once, the module path with FILE_GUID overridden has
271 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
272 # in DSC which is used as relative path by C files and other files in INF.
273 # A trick was used: all module paths are PathClass instances, after the initialization
274 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
276 # The reason for creating a temporary INF is:
277 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
278 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
279 # A different key for the same module is needed to create different output directory,
280 # retrieve overridden PCDs, library instances.
282 # The BaseName is the FILE_GUID which is also the output directory name.
285 RtPath
.Path
= TempFullPath
286 RtPath
.BaseName
= BaseName
288 # If file exists, compare contents
290 if os
.path
.exists(TempFullPath
):
291 with
open(str(Path
), 'rb') as f1
, open(TempFullPath
, 'rb') as f2
:
292 if f1
.read() == f2
.read():
294 _TempInfs
.append(TempFullPath
)
295 shutil
.copy2(str(Path
), TempFullPath
)
298 ## Remove temporary created INFs whose paths were saved in _TempInfs
300 def ClearDuplicatedInf():
302 File
= _TempInfs
.pop()
303 if os
.path
.exists(File
):
306 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
308 # @param Guid The GUID string
310 # @retval string The GUID string in C structure style
312 def GuidStringToGuidStructureString(Guid
):
313 GuidList
= Guid
.split('-')
315 for Index
in range(0, 3, 1):
316 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
317 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
318 for Index
in range(0, 12, 2):
319 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
323 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
325 # @param GuidValue The GUID value in byte array
327 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
329 def GuidStructureByteArrayToGuidString(GuidValue
):
330 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
331 guidValueList
= guidValueString
.split(",")
332 if len(guidValueList
) != 16:
334 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
336 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
337 int(guidValueList
[3], 16),
338 int(guidValueList
[2], 16),
339 int(guidValueList
[1], 16),
340 int(guidValueList
[0], 16),
341 int(guidValueList
[5], 16),
342 int(guidValueList
[4], 16),
343 int(guidValueList
[7], 16),
344 int(guidValueList
[6], 16),
345 int(guidValueList
[8], 16),
346 int(guidValueList
[9], 16),
347 int(guidValueList
[10], 16),
348 int(guidValueList
[11], 16),
349 int(guidValueList
[12], 16),
350 int(guidValueList
[13], 16),
351 int(guidValueList
[14], 16),
352 int(guidValueList
[15], 16)
357 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
359 # @param GuidValue The GUID value in C structure format
361 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
363 def GuidStructureStringToGuidString(GuidValue
):
364 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
365 guidValueList
= guidValueString
.split(",")
366 if len(guidValueList
) != 11:
368 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
370 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
371 int(guidValueList
[0], 16),
372 int(guidValueList
[1], 16),
373 int(guidValueList
[2], 16),
374 int(guidValueList
[3], 16),
375 int(guidValueList
[4], 16),
376 int(guidValueList
[5], 16),
377 int(guidValueList
[6], 16),
378 int(guidValueList
[7], 16),
379 int(guidValueList
[8], 16),
380 int(guidValueList
[9], 16),
381 int(guidValueList
[10], 16)
386 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
388 # @param GuidValue The GUID value in C structure format
390 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
392 def GuidStructureStringToGuidValueName(GuidValue
):
393 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
394 guidValueList
= guidValueString
.split(",")
395 if len(guidValueList
) != 11:
396 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
397 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
398 int(guidValueList
[0], 16),
399 int(guidValueList
[1], 16),
400 int(guidValueList
[2], 16),
401 int(guidValueList
[3], 16),
402 int(guidValueList
[4], 16),
403 int(guidValueList
[5], 16),
404 int(guidValueList
[6], 16),
405 int(guidValueList
[7], 16),
406 int(guidValueList
[8], 16),
407 int(guidValueList
[9], 16),
408 int(guidValueList
[10], 16)
411 ## Create directories
413 # @param Directory The directory name
415 def CreateDirectory(Directory
):
416 if Directory
is None or Directory
.strip() == "":
419 if not os
.access(Directory
, os
.F_OK
):
420 os
.makedirs(Directory
)
425 ## Remove directories, including files and sub-directories in it
427 # @param Directory The directory name
429 def RemoveDirectory(Directory
, Recursively
=False):
430 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
433 CurrentDirectory
= os
.getcwd()
435 for File
in os
.listdir("."):
436 if os
.path
.isdir(File
):
437 RemoveDirectory(File
, Recursively
)
440 os
.chdir(CurrentDirectory
)
443 ## Store content in file
445 # This method is used to save file only when its content is changed. This is
446 # quite useful for "make" system to decide what will be re-built and what won't.
448 # @param File The path of file
449 # @param Content The new content of the file
450 # @param IsBinaryFile The flag indicating if the file is binary file or not
452 # @retval True If the file content is changed and the file is renewed
453 # @retval False If the file content is the same
455 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
457 Content
= Content
.replace("\n", os
.linesep
)
459 if os
.path
.exists(File
):
461 if Content
== open(File
, "rb").read():
464 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
466 DirName
= os
.path
.dirname(File
)
467 if not CreateDirectory(DirName
):
468 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
471 DirName
= os
.getcwd()
472 if not os
.access(DirName
, os
.W_OK
):
473 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
476 if GlobalData
.gIsWindows
:
478 from .PyUtility
import SaveFileToDisk
479 if not SaveFileToDisk(File
, Content
):
480 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
482 Fd
= open(File
, "wb")
486 Fd
= open(File
, "wb")
490 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
494 ## Make a Python object persistent on file system
496 # @param Data The object to be stored in file
497 # @param File The path of file to store the object
499 def DataDump(Data
, File
):
502 Fd
= open(File
, 'wb')
503 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
505 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
510 ## Restore a Python object from a file
512 # @param File The path of file stored the object
514 # @retval object A python object
515 # @retval None If failure in file operation
517 def DataRestore(File
):
521 Fd
= open(File
, 'rb')
522 Data
= cPickle
.load(Fd
)
523 except Exception as e
:
524 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
531 ## Retrieve and cache the real path name in file system
533 # @param Root The root directory of path relative to
535 # @retval str The path string if the path exists
536 # @retval None If path doesn't exist
542 def __init__(self
, Root
):
544 for F
in os
.listdir(Root
):
546 self
._UPPER
_CACHE
_[F
.upper()] = F
549 def __getitem__(self
, Path
):
550 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
553 if Path
and Path
[0] == os
.path
.sep
:
555 if Path
in self
._CACHE
_:
556 return os
.path
.join(self
._Root
, Path
)
557 UpperPath
= Path
.upper()
558 if UpperPath
in self
._UPPER
_CACHE
_:
559 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
563 SepIndex
= Path
.find(os
.path
.sep
)
565 Parent
= UpperPath
[:SepIndex
]
566 if Parent
not in self
._UPPER
_CACHE
_:
568 LastSepIndex
= SepIndex
569 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
571 if LastSepIndex
== -1:
576 SepIndex
= LastSepIndex
578 Parent
= Path
[:SepIndex
]
579 ParentKey
= UpperPath
[:SepIndex
]
580 if ParentKey
not in self
._UPPER
_CACHE
_:
584 if Parent
in self
._CACHE
_:
587 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
588 for F
in os
.listdir(ParentDir
):
589 Dir
= os
.path
.join(ParentDir
, F
)
590 self
._CACHE
_.add(Dir
)
591 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
593 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
596 if Path
in self
._CACHE
_:
597 return os
.path
.join(self
._Root
, Path
)
598 elif UpperPath
in self
._UPPER
_CACHE
_:
599 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
602 def RealPath(File
, Dir
='', OverrideDir
=''):
603 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
604 NewFile
= GlobalData
.gAllFiles
[NewFile
]
605 if not NewFile
and OverrideDir
:
606 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
607 NewFile
= GlobalData
.gAllFiles
[NewFile
]
610 def RealPath2(File
, Dir
='', OverrideDir
=''):
613 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
615 if OverrideDir
[-1] == os
.path
.sep
:
616 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
618 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
619 if GlobalData
.gAllFiles
:
620 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
622 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
623 if not os
.path
.exists(NewFile
):
627 if Dir
[-1] == os
.path
.sep
:
628 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
630 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
636 ## Get GUID value from given packages
638 # @param CName The CName of the GUID
639 # @param PackageList List of packages looking-up in
640 # @param Inffile The driver file
642 # @retval GuidValue if the CName is found in any given package
643 # @retval None if the CName is not found in all given packages
645 def GuidValue(CName
, PackageList
, Inffile
= None):
646 for P
in PackageList
:
647 GuidKeys
= P
.Guids
.keys()
648 if Inffile
and P
._PrivateGuids
:
649 if not Inffile
.startswith(P
.MetaFile
.Dir
):
650 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
651 if CName
in GuidKeys
:
652 return P
.Guids
[CName
]
655 ## Get Protocol value from given packages
657 # @param CName The CName of the GUID
658 # @param PackageList List of packages looking-up in
659 # @param Inffile The driver file
661 # @retval GuidValue if the CName is found in any given package
662 # @retval None if the CName is not found in all given packages
664 def ProtocolValue(CName
, PackageList
, Inffile
= None):
665 for P
in PackageList
:
666 ProtocolKeys
= P
.Protocols
.keys()
667 if Inffile
and P
._PrivateProtocols
:
668 if not Inffile
.startswith(P
.MetaFile
.Dir
):
669 ProtocolKeys
= [x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
]
670 if CName
in ProtocolKeys
:
671 return P
.Protocols
[CName
]
674 ## Get PPI value from given packages
676 # @param CName The CName of the GUID
677 # @param PackageList List of packages looking-up in
678 # @param Inffile The driver file
680 # @retval GuidValue if the CName is found in any given package
681 # @retval None if the CName is not found in all given packages
683 def PpiValue(CName
, PackageList
, Inffile
= None):
684 for P
in PackageList
:
685 PpiKeys
= P
.Ppis
.keys()
686 if Inffile
and P
._PrivatePpis
:
687 if not Inffile
.startswith(P
.MetaFile
.Dir
):
688 PpiKeys
= [x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
]
693 ## A string template class
695 # This class implements a template for string replacement. A string template
696 # looks like following
698 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
700 # The string between ${BEGIN} and ${END} will be repeated as many times as the
701 # length of "placeholder_name", which is a list passed through a dict. The
702 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
703 # be not used and, in this case, the "placeholder_name" must not a list and it
704 # will just be replaced once.
706 class TemplateString(object):
707 _REPEAT_START_FLAG
= "BEGIN"
708 _REPEAT_END_FLAG
= "END"
710 class Section(object):
711 _LIST_TYPES
= [type([]), type(set()), type((0,))]
713 def __init__(self
, TemplateSection
, PlaceHolderList
):
714 self
._Template
= TemplateSection
715 self
._PlaceHolderList
= []
717 # Split the section into sub-sections according to the position of placeholders
719 self
._SubSectionList
= []
722 # The placeholders passed in must be in the format of
724 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
726 for PlaceHolder
, Start
, End
in PlaceHolderList
:
727 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
728 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
729 self
._PlaceHolderList
.append(PlaceHolder
)
730 SubSectionStart
= End
731 if SubSectionStart
< len(TemplateSection
):
732 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
734 self
._SubSectionList
= [TemplateSection
]
737 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
739 def Instantiate(self
, PlaceHolderValues
):
741 RepeatPlaceHolders
= {}
742 NonRepeatPlaceHolders
= {}
744 for PlaceHolder
in self
._PlaceHolderList
:
745 if PlaceHolder
not in PlaceHolderValues
:
747 Value
= PlaceHolderValues
[PlaceHolder
]
748 if type(Value
) in self
._LIST
_TYPES
:
750 RepeatTime
= len(Value
)
751 elif RepeatTime
!= len(Value
):
755 "${%s} has different repeat time from others!" % PlaceHolder
,
756 ExtraData
=str(self
._Template
)
758 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
760 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
762 if NonRepeatPlaceHolders
:
764 for S
in self
._SubSectionList
:
765 if S
not in NonRepeatPlaceHolders
:
768 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
770 StringList
= self
._SubSectionList
772 if RepeatPlaceHolders
:
774 for Index
in range(RepeatTime
):
776 if S
not in RepeatPlaceHolders
:
777 TempStringList
.append(S
)
779 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
780 StringList
= TempStringList
782 return "".join(StringList
)
785 def __init__(self
, Template
=None):
787 self
.IsBinary
= False
788 self
._Template
= Template
789 self
._TemplateSectionList
= self
._Parse
(Template
)
793 # @retval string The string replaced
798 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
800 # @retval list A list of TemplateString.Section objects
802 def _Parse(self
, Template
):
807 TemplateSectionList
= []
809 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
811 if MatchEnd
<= len(Template
):
812 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
813 TemplateSectionList
.append(TemplateSection
)
816 MatchString
= MatchObj
.group(1)
817 MatchStart
= MatchObj
.start()
818 MatchEnd
= MatchObj
.end()
820 if MatchString
== self
._REPEAT
_START
_FLAG
:
821 if MatchStart
> SectionStart
:
822 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
823 TemplateSectionList
.append(TemplateSection
)
824 SectionStart
= MatchEnd
826 elif MatchString
== self
._REPEAT
_END
_FLAG
:
827 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
828 TemplateSectionList
.append(TemplateSection
)
829 SectionStart
= MatchEnd
832 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
833 SearchFrom
= MatchEnd
834 return TemplateSectionList
836 ## Replace the string template with dictionary of placeholders and append it to previous one
838 # @param AppendString The string template to append
839 # @param Dictionary The placeholder dictionaries
841 def Append(self
, AppendString
, Dictionary
=None):
843 SectionList
= self
._Parse
(AppendString
)
844 self
.String
+= "".join(S
.Instantiate(Dictionary
) for S
in SectionList
)
846 self
.String
+= AppendString
848 ## Replace the string template with dictionary of placeholders
850 # @param Dictionary The placeholder dictionaries
852 # @retval str The string replaced with placeholder values
854 def Replace(self
, Dictionary
=None):
855 return "".join(S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
)
857 ## Progress indicator class
859 # This class makes use of thread to print progress on console.
862 # for avoiding deadloop
864 _ProgressThread
= None
865 _CheckInterval
= 0.25
869 # @param OpenMessage The string printed before progress charaters
870 # @param CloseMessage The string printed after progress charaters
871 # @param ProgressChar The charater used to indicate the progress
872 # @param Interval The interval in seconds between two progress charaters
874 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
875 self
.PromptMessage
= OpenMessage
876 self
.CodaMessage
= CloseMessage
877 self
.ProgressChar
= ProgressChar
878 self
.Interval
= Interval
879 if Progressor
._StopFlag
is None:
880 Progressor
._StopFlag
= threading
.Event()
882 ## Start to print progress charater
884 # @param OpenMessage The string printed before progress charaters
886 def Start(self
, OpenMessage
=None):
887 if OpenMessage
is not None:
888 self
.PromptMessage
= OpenMessage
889 Progressor
._StopFlag
.clear()
890 if Progressor
._ProgressThread
is None:
891 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
892 Progressor
._ProgressThread
.setDaemon(False)
893 Progressor
._ProgressThread
.start()
895 ## Stop printing progress charater
897 # @param CloseMessage The string printed after progress charaters
899 def Stop(self
, CloseMessage
=None):
900 OriginalCodaMessage
= self
.CodaMessage
901 if CloseMessage
is not None:
902 self
.CodaMessage
= CloseMessage
904 self
.CodaMessage
= OriginalCodaMessage
906 ## Thread entry method
907 def _ProgressThreadEntry(self
):
908 sys
.stdout
.write(self
.PromptMessage
+ " ")
911 while not Progressor
._StopFlag
.isSet():
913 sys
.stdout
.write(self
.ProgressChar
)
915 TimeUp
= self
.Interval
916 time
.sleep(self
._CheckInterval
)
917 TimeUp
-= self
._CheckInterval
918 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
921 ## Abort the progress display
924 if Progressor
._StopFlag
is not None:
925 Progressor
._StopFlag
.set()
926 if Progressor
._ProgressThread
is not None:
927 Progressor
._ProgressThread
.join()
928 Progressor
._ProgressThread
= None
930 ## A dict which can access its keys and/or values orderly
932 # The class implements a new kind of dict which its keys or values can be
933 # accessed in the order they are added into the dict. It guarantees the order
934 # by making use of an internal list to keep a copy of keys.
936 class sdict(IterableUserDict
):
939 IterableUserDict
.__init
__(self
)
943 def __setitem__(self
, key
, value
):
944 if key
not in self
._key
_list
:
945 self
._key
_list
.append(key
)
946 IterableUserDict
.__setitem
__(self
, key
, value
)
949 def __delitem__(self
, key
):
950 self
._key
_list
.remove(key
)
951 IterableUserDict
.__delitem
__(self
, key
)
953 ## used in "for k in dict" loop to ensure the correct order
955 return self
.iterkeys()
959 return len(self
._key
_list
)
962 def __contains__(self
, key
):
963 return key
in self
._key
_list
966 def index(self
, key
):
967 return self
._key
_list
.index(key
)
970 def insert(self
, key
, newkey
, newvalue
, order
):
971 index
= self
._key
_list
.index(key
)
972 if order
== 'BEFORE':
973 self
._key
_list
.insert(index
, newkey
)
974 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
975 elif order
== 'AFTER':
976 self
._key
_list
.insert(index
+ 1, newkey
)
977 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
980 def append(self
, sdict
):
982 if key
not in self
._key
_list
:
983 self
._key
_list
.append(key
)
984 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
986 def has_key(self
, key
):
987 return key
in self
._key
_list
992 IterableUserDict
.clear(self
)
994 ## Return a copy of keys
997 for key
in self
._key
_list
:
1001 ## Return a copy of values
1004 for key
in self
._key
_list
:
1005 values
.append(self
[key
])
1008 ## Return a copy of (key, value) list
1011 for key
in self
._key
_list
:
1012 items
.append((key
, self
[key
]))
1015 ## Iteration support
1016 def iteritems(self
):
1017 return iter(self
.items())
1019 ## Keys interation support
1021 return iter(self
.keys())
1023 ## Values interation support
1024 def itervalues(self
):
1025 return iter(self
.values())
1027 ## Return value related to a key, and remove the (key, value) from the dict
1028 def pop(self
, key
, *dv
):
1030 if key
in self
._key
_list
:
1032 self
.__delitem
__(key
)
1037 ## Return (key, value) pair, and remove the (key, value) from the dict
1039 key
= self
._key
_list
[-1]
1041 self
.__delitem
__(key
)
1044 def update(self
, dict=None, **kwargs
):
1045 if dict is not None:
1046 for k
, v
in dict.items():
1049 for k
, v
in kwargs
.items():
1052 ## Dictionary with restricted keys
1056 def __init__(self
, KeyList
):
1058 dict.__setitem
__(self
, Key
, "")
1061 def __setitem__(self
, key
, value
):
1063 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1064 ExtraData
=", ".join(dict.keys(self
)))
1065 dict.__setitem
__(self
, key
, value
)
1068 def __getitem__(self
, key
):
1071 return dict.__getitem
__(self
, key
)
1074 def __delitem__(self
, key
):
1075 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1080 self
.__setitem
__(Key
, "")
1082 ## Return value related to a key, and remove the (key, value) from the dict
1083 def pop(self
, key
, *dv
):
1084 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1086 ## Return (key, value) pair, and remove the (key, value) from the dict
1088 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1090 ## Dictionary using prioritized list as key
1093 _ListType
= type([])
1094 _TupleType
= type(())
1095 _Wildcard
= 'COMMON'
1096 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1098 def __init__(self
, _Single_
=False, _Level_
=2):
1099 self
._Level
_ = _Level_
1101 self
._Single
_ = _Single_
1104 def __getitem__(self
, key
):
1107 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1111 elif self
._Level
_ > 1:
1112 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1115 if self
._Level
_ > 1:
1116 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1118 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1119 FirstKey
= self
._Wildcard
1122 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1124 return self
._GetAllValues
(FirstKey
, RestKeys
)
1126 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1128 #print "%s-%s" % (FirstKey, self._Level_) ,
1129 if self
._Level
_ > 1:
1130 if FirstKey
== self
._Wildcard
:
1131 if FirstKey
in self
.data
:
1132 Value
= self
.data
[FirstKey
][RestKeys
]
1134 for Key
in self
.data
:
1135 Value
= self
.data
[Key
][RestKeys
]
1136 if Value
is not None: break
1138 if FirstKey
in self
.data
:
1139 Value
= self
.data
[FirstKey
][RestKeys
]
1140 if Value
is None and self
._Wildcard
in self
.data
:
1142 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1144 if FirstKey
== self
._Wildcard
:
1145 if FirstKey
in self
.data
:
1146 Value
= self
.data
[FirstKey
]
1148 for Key
in self
.data
:
1149 Value
= self
.data
[Key
]
1150 if Value
is not None: break
1152 if FirstKey
in self
.data
:
1153 Value
= self
.data
[FirstKey
]
1154 elif self
._Wildcard
in self
.data
:
1155 Value
= self
.data
[self
._Wildcard
]
1158 def _GetAllValues(self
, FirstKey
, RestKeys
):
1160 if self
._Level
_ > 1:
1161 if FirstKey
== self
._Wildcard
:
1162 for Key
in self
.data
:
1163 Value
+= self
.data
[Key
][RestKeys
]
1165 if FirstKey
in self
.data
:
1166 Value
+= self
.data
[FirstKey
][RestKeys
]
1167 if self
._Wildcard
in self
.data
:
1168 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1170 if FirstKey
== self
._Wildcard
:
1171 for Key
in self
.data
:
1172 Value
.append(self
.data
[Key
])
1174 if FirstKey
in self
.data
:
1175 Value
.append(self
.data
[FirstKey
])
1176 if self
._Wildcard
in self
.data
:
1177 Value
.append(self
.data
[self
._Wildcard
])
1181 def __setitem__(self
, key
, value
):
1184 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1189 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1192 if self
._Level
_ > 1:
1193 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1195 if FirstKey
in self
._ValidWildcardList
:
1196 FirstKey
= self
._Wildcard
1198 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1199 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1201 if self
._Level
_ > 1:
1202 self
.data
[FirstKey
][RestKeys
] = value
1204 self
.data
[FirstKey
] = value
1206 def SetGreedyMode(self
):
1207 self
._Single
_ = False
1208 if self
._Level
_ > 1:
1209 for Key
in self
.data
:
1210 self
.data
[Key
].SetGreedyMode()
1212 def SetSingleMode(self
):
1213 self
._Single
_ = True
1214 if self
._Level
_ > 1:
1215 for Key
in self
.data
:
1216 self
.data
[Key
].SetSingleMode()
1218 def GetKeys(self
, KeyIndex
=0):
1219 assert KeyIndex
>= 0
1221 return set(self
.data
.keys())
1224 for Key
in self
.data
:
1225 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1228 def IsFieldValueAnArray (Value
):
1229 Value
= Value
.strip()
1230 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1232 if Value
.startswith('L"') and Value
.endswith('"') and len(list(Value
[2:-1])) > 1:
1234 if Value
[0] == '"' and Value
[-1] == '"' and len(list(Value
[1:-1])) > 1:
1236 if Value
[0] == '{' and Value
[-1] == '}':
1238 if Value
.startswith("L'") and Value
.endswith("'") and len(list(Value
[2:-1])) > 1:
1240 if Value
[0] == "'" and Value
[-1] == "'" and len(list(Value
[1:-1])) > 1:
1244 def AnalyzePcdExpression(Setting
):
1245 Setting
= Setting
.strip()
1246 # There might be escaped quote in a string: \", \\\" , \', \\\'
1248 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1250 InSingleQuoteStr
= False
1251 InDoubleQuoteStr
= False
1253 for Index
, ch
in enumerate(Data
):
1254 if ch
== '"' and not InSingleQuoteStr
:
1255 if Data
[Index
- 1] != '\\':
1256 InDoubleQuoteStr
= not InDoubleQuoteStr
1257 elif ch
== "'" and not InDoubleQuoteStr
:
1258 if Data
[Index
- 1] != '\\':
1259 InSingleQuoteStr
= not InSingleQuoteStr
1260 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1262 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1265 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1272 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1274 FieldList
.append(Setting
[StartPos
:].strip())
1276 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1281 def ParseDevPathValue (Value
):
1283 Value
.replace('\\', '/').replace(' ', '')
1285 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1287 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1288 out
, err
= p
.communicate()
1289 except Exception as X
:
1290 raise BadExpression("DevicePath: %s" % (str(X
)) )
1292 subprocess
._cleanup
()
1296 raise BadExpression("DevicePath: %s" % str(err
))
1297 Size
= len(out
.split())
1298 out
= ','.join(out
.split())
1299 return '{' + out
+ '}', Size
1301 def ParseFieldValue (Value
):
1302 if isinstance(Value
, type(0)):
1303 return Value
, (Value
.bit_length() + 7) / 8
1304 if not isinstance(Value
, type('')):
1305 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1306 Value
= Value
.strip()
1307 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1308 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1310 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1312 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1313 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1315 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1317 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1318 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1320 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1322 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1323 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1325 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1327 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1328 Value
= Value
.split('(', 1)[1][:-1].strip()
1329 if Value
[0] == '{' and Value
[-1] == '}':
1330 TmpValue
= GuidStructureStringToGuidString(Value
)
1331 if len(TmpValue
) == 0:
1332 raise BadExpression("Invalid GUID value string %s" % Value
)
1334 if Value
[0] == '"' and Value
[-1] == '"':
1337 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1338 except ValueError as Message
:
1339 raise BadExpression(Message
)
1340 Value
, Size
= ParseFieldValue(Value
)
1342 if Value
.startswith('L"') and Value
.endswith('"'):
1344 # translate escape character
1354 Value
= (Value
<< 16) |
ord(Char
)
1355 return Value
, (len(List
) + 1) * 2
1356 if Value
.startswith('"') and Value
.endswith('"'):
1358 # translate escape character
1367 Value
= (Value
<< 8) |
ord(Char
)
1368 return Value
, len(List
) + 1
1369 if Value
.startswith("L'") and Value
.endswith("'"):
1370 # Unicode Character Constant
1371 # translate escape character
1379 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1383 Value
= (Value
<< 16) |
ord(Char
)
1384 return Value
, len(List
) * 2
1385 if Value
.startswith("'") and Value
.endswith("'"):
1386 # Character constant
1387 # translate escape character
1394 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1398 Value
= (Value
<< 8) |
ord(Char
)
1399 return Value
, len(List
)
1400 if Value
.startswith('{') and Value
.endswith('}'):
1403 List
= [Item
.strip() for Item
in Value
.split(',')]
1408 ItemValue
, Size
= ParseFieldValue(Item
)
1410 for I
in range(Size
):
1411 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1412 return Value
, RetSize
1413 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1414 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1415 Value
= Value
.strip().strip('"')
1416 return ParseDevPathValue(Value
)
1417 if Value
.lower().startswith('0x'):
1418 Value
= int(Value
, 16)
1421 return Value
, (Value
.bit_length() + 7) / 8
1422 if Value
[0].isdigit():
1423 Value
= int(Value
, 10)
1426 return Value
, (Value
.bit_length() + 7) / 8
1427 if Value
.lower() == 'true':
1429 if Value
.lower() == 'false':
1435 # Analyze DSC PCD value, since there is no data type info in DSC
1436 # This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1437 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1438 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1439 # 3. Dynamic default:
1440 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1441 # TokenSpace.PcdCName|PcdValue
1443 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1444 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1446 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1447 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1448 # there might have "|" operator, also in string value.
1450 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1451 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1452 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1454 # ValueList: A List contain fields described above
1455 # IsValid: True if conforming EBNF, otherwise False
1456 # Index: The index where PcdValue is in ValueList
1458 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1459 FieldList
= AnalyzePcdExpression(Setting
)
1462 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1463 Value
= FieldList
[0]
1465 if len(FieldList
) > 1:
1466 if FieldList
[1].upper().startswith("0X") or FieldList
[1].isdigit():
1469 DataType
= FieldList
[1]
1471 if len(FieldList
) > 2:
1474 IsValid
= (len(FieldList
) <= 1)
1476 IsValid
= (len(FieldList
) <= 3)
1477 # Value, Size = ParseFieldValue(Value)
1480 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1484 return [str(Value
), '', str(Size
)], IsValid
, 0
1485 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1486 Value
= FieldList
[0]
1488 if len(FieldList
) > 1:
1492 if len(FieldList
) > 2:
1495 IsValid
= (len(FieldList
) <= 1)
1497 IsValid
= (len(FieldList
) <= 3)
1501 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1505 return [Value
, Type
, str(Size
)], IsValid
, 0
1506 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1507 VpdOffset
= FieldList
[0]
1509 if not DataType
== TAB_VOID
:
1510 if len(FieldList
) > 1:
1511 Value
= FieldList
[1]
1513 if len(FieldList
) > 1:
1515 if len(FieldList
) > 2:
1516 Value
= FieldList
[2]
1518 IsValid
= (len(FieldList
) <= 1)
1520 IsValid
= (len(FieldList
) <= 3)
1523 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1527 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1528 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1529 HiiString
= FieldList
[0]
1530 Guid
= Offset
= Value
= Attribute
= ''
1531 if len(FieldList
) > 1:
1533 if len(FieldList
) > 2:
1534 Offset
= FieldList
[2]
1535 if len(FieldList
) > 3:
1536 Value
= FieldList
[3]
1537 if len(FieldList
) > 4:
1538 Attribute
= FieldList
[4]
1539 IsValid
= (3 <= len(FieldList
) <= 5)
1540 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1545 # Analyze the pcd Value, Datum type and TokenNumber.
1546 # Used to avoid split issue while the value string contain "|" character
1548 # @param[in] Setting: A String contain value/datum type/token number information;
1550 # @retval ValueList: A List contain value, datum type and toke number.
1552 def AnalyzePcdData(Setting
):
1553 ValueList
= ['', '', '']
1555 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1556 PtrValue
= ValueRe
.findall(Setting
)
1558 ValueUpdateFlag
= False
1560 if len(PtrValue
) >= 1:
1561 Setting
= re
.sub(ValueRe
, '', Setting
)
1562 ValueUpdateFlag
= True
1564 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1565 ValueList
[0:len(TokenList
)] = TokenList
1568 ValueList
[0] = PtrValue
[0]
1572 ## check format of PCD value against its the datum type
1574 # For PCD value setting
1576 def CheckPcdDatum(Type
, Value
):
1577 if Type
== TAB_VOID
:
1578 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1579 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1580 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1582 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1583 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1584 elif ValueRe
.match(Value
):
1585 # Check the chars in UnicodeString or CString is printable
1586 if Value
.startswith("L"):
1590 Printset
= set(string
.printable
)
1591 Printset
.remove(TAB_PRINTCHAR_VT
)
1592 Printset
.add(TAB_PRINTCHAR_BS
)
1593 Printset
.add(TAB_PRINTCHAR_NUL
)
1594 if not set(Value
).issubset(Printset
):
1595 PrintList
= sorted(Printset
)
1596 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1597 elif Type
== 'BOOLEAN':
1598 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1599 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1600 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1601 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1603 Value
= long(Value
, 0)
1605 return False, "Invalid value [%s] of type [%s];"\
1606 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1608 return True, "StructurePcd"
1612 ## Split command line option string to list
1614 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1615 # in non-windows platform to launch command
1617 def SplitOption(OptionString
):
1622 for Index
in range(0, len(OptionString
)):
1623 CurrentChar
= OptionString
[Index
]
1624 if CurrentChar
in ['"', "'"]:
1625 if QuotationMark
== CurrentChar
:
1627 elif QuotationMark
== "":
1628 QuotationMark
= CurrentChar
1633 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1634 if Index
> OptionStart
:
1635 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1637 LastChar
= CurrentChar
1638 OptionList
.append(OptionString
[OptionStart
:])
1641 def CommonPath(PathList
):
1642 P1
= min(PathList
).split(os
.path
.sep
)
1643 P2
= max(PathList
).split(os
.path
.sep
)
1644 for Index
in xrange(min(len(P1
), len(P2
))):
1645 if P1
[Index
] != P2
[Index
]:
1646 return os
.path
.sep
.join(P1
[:Index
])
1647 return os
.path
.sep
.join(P1
)
1650 # Convert string to C format array
1652 def ConvertStringToByteArray(Value
):
1653 Value
= Value
.strip()
1657 if not Value
.endswith('}'):
1659 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1660 ValFields
= Value
.split(',')
1662 for Index
in range(len(ValFields
)):
1663 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1666 Value
= '{' + ','.join(ValFields
) + '}'
1670 if Value
.startswith('L"'):
1671 if not Value
.endswith('"'):
1675 elif not Value
.startswith('"') or not Value
.endswith('"'):
1678 Value
= eval(Value
) # translate escape character
1680 for Index
in range(0, len(Value
)):
1682 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1684 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1685 Value
= NewValue
+ '0}'
1688 class PathClass(object):
1689 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1690 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1692 self
.File
= str(File
)
1693 if os
.path
.isabs(self
.File
):
1697 self
.Root
= str(Root
)
1698 self
.AlterRoot
= str(AlterRoot
)
1700 # Remove any '.' and '..' in path
1702 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1703 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1704 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1705 # eliminate the side-effect of 'C:'
1706 if self
.Root
[-1] == ':':
1707 self
.Root
+= os
.path
.sep
1708 # file path should not start with path separator
1709 if self
.Root
[-1] == os
.path
.sep
:
1710 self
.File
= self
.Path
[len(self
.Root
):]
1712 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1714 self
.Path
= os
.path
.normpath(self
.File
)
1716 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1717 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1721 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1723 self
.Dir
= self
.Root
1725 self
.Dir
= self
.SubDir
1730 self
.Type
= self
.Ext
.lower()
1732 self
.IsBinary
= IsBinary
1733 self
.Target
= Target
1734 self
.TagName
= TagName
1735 self
.ToolCode
= ToolCode
1736 self
.ToolChainFamily
= ToolChainFamily
1740 ## Convert the object of this class to a string
1742 # Convert member Path of the class to a string
1744 # @retval string Formatted String
1749 ## Override __eq__ function
1751 # Check whether PathClass are the same
1753 # @retval False The two PathClass are different
1754 # @retval True The two PathClass are the same
1756 def __eq__(self
, Other
):
1757 if isinstance(Other
, type(self
)):
1758 return self
.Path
== Other
.Path
1760 return self
.Path
== str(Other
)
1762 ## Override __cmp__ function
1764 # Customize the comparsion operation of two PathClass
1766 # @retval 0 The two PathClass are different
1767 # @retval -1 The first PathClass is less than the second PathClass
1768 # @retval 1 The first PathClass is Bigger than the second PathClass
1769 def __cmp__(self
, Other
):
1770 if isinstance(Other
, type(self
)):
1771 OtherKey
= Other
.Path
1773 OtherKey
= str(Other
)
1776 if SelfKey
== OtherKey
:
1778 elif SelfKey
> OtherKey
:
1783 ## Override __hash__ function
1785 # Use Path as key in hash table
1787 # @retval string Key for hash table
1790 return hash(self
.Path
)
1792 def _GetFileKey(self
):
1793 if self
._Key
is None:
1794 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1797 def _GetTimeStamp(self
):
1798 return os
.stat(self
.Path
)[8]
1800 def Validate(self
, Type
='', CaseSensitive
=True):
1801 if GlobalData
.gCaseInsensitive
:
1802 CaseSensitive
= False
1803 if Type
and Type
.lower() != self
.Type
:
1804 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1806 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1807 if not RealRoot
and not RealFile
:
1808 RealFile
= self
.File
1810 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1812 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1813 if len (mws
.getPkgPath()) == 0:
1814 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1816 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1820 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1821 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1822 ErrorCode
= FILE_CASE_MISMATCH
1823 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1825 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1826 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1828 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1831 self
.File
= RealFile
1832 self
.Root
= RealRoot
1833 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1834 return ErrorCode
, ErrorInfo
1836 Key
= property(_GetFileKey
)
1837 TimeStamp
= property(_GetTimeStamp
)
1839 ## Parse PE image to get the required PE informaion.
1841 class PeImageClass():
1844 # @param File FilePath of PeImage
1846 def __init__(self
, PeFile
):
1847 self
.FileName
= PeFile
1848 self
.IsValid
= False
1851 self
.SectionAlignment
= 0
1852 self
.SectionHeaderList
= []
1855 PeObject
= open(PeFile
, 'rb')
1857 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1860 ByteArray
= array
.array('B')
1861 ByteArray
.fromfile(PeObject
, 0x3E)
1862 ByteList
= ByteArray
.tolist()
1863 # DOS signature should be 'MZ'
1864 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1865 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1868 # Read 4 byte PE Signature
1869 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1870 PeObject
.seek(PeOffset
)
1871 ByteArray
= array
.array('B')
1872 ByteArray
.fromfile(PeObject
, 4)
1873 # PE signature should be 'PE\0\0'
1874 if ByteArray
.tostring() != 'PE\0\0':
1875 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1878 # Read PE file header
1879 ByteArray
= array
.array('B')
1880 ByteArray
.fromfile(PeObject
, 0x14)
1881 ByteList
= ByteArray
.tolist()
1882 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1884 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1887 # Read PE optional header
1888 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1889 ByteArray
= array
.array('B')
1890 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1891 ByteList
= ByteArray
.tolist()
1892 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1893 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1894 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1896 # Read each Section Header
1897 for Index
in range(SecNumber
):
1898 ByteArray
= array
.array('B')
1899 ByteArray
.fromfile(PeObject
, 0x28)
1900 ByteList
= ByteArray
.tolist()
1901 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1902 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1903 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1904 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1905 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1909 def _ByteListToStr(self
, ByteList
):
1911 for index
in range(len(ByteList
)):
1912 if ByteList
[index
] == 0:
1914 String
+= chr(ByteList
[index
])
1917 def _ByteListToInt(self
, ByteList
):
1919 for index
in range(len(ByteList
) - 1, -1, -1):
1920 Value
= (Value
<< 8) |
int(ByteList
[index
])
1923 class DefaultStore():
1924 def __init__(self
, DefaultStores
):
1926 self
.DefaultStores
= DefaultStores
1927 def DefaultStoreID(self
, DefaultStoreName
):
1928 for key
, value
in self
.DefaultStores
.items():
1929 if value
== DefaultStoreName
:
1932 def GetDefaultDefault(self
):
1933 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1934 return "0", TAB_DEFAULT_STORES_DEFAULT
1936 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1937 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1938 def GetMin(self
, DefaultSIdList
):
1939 if not DefaultSIdList
:
1940 return TAB_DEFAULT_STORES_DEFAULT
1941 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1944 minid
= min(storeidset
)
1945 for sid
, name
in self
.DefaultStores
.values():
1954 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1958 for SkuName
in SkuIds
:
1959 SkuId
= SkuIds
[SkuName
][0]
1960 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1961 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1962 EdkLogger
.error("build", PARAMETER_INVALID
,
1963 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1966 self
.AvailableSkuIds
= sdict()
1968 self
.SkuIdNumberSet
= []
1969 self
.SkuData
= SkuIds
1970 self
.__SkuInherit
= {}
1971 self
.__SkuIdentifier
= SkuIdentifier
1972 if SkuIdentifier
== '' or SkuIdentifier
is None:
1973 self
.SkuIdSet
= ['DEFAULT']
1974 self
.SkuIdNumberSet
= ['0U']
1975 elif SkuIdentifier
== 'ALL':
1976 self
.SkuIdSet
= SkuIds
.keys()
1977 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1979 r
= SkuIdentifier
.split('|')
1980 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1983 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1985 EdkLogger
.error("build", PARAMETER_INVALID
,
1986 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1987 % (k
, " | ".join(SkuIds
.keys())))
1988 for each
in self
.SkuIdSet
:
1990 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1992 EdkLogger
.error("build", PARAMETER_INVALID
,
1993 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1994 % (each
, " | ".join(SkuIds
.keys())))
1995 if self
.SkuUsageType
!= self
.SINGLE
:
1996 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1998 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1999 if 'COMMON' in GlobalData
.gSkuids
:
2000 GlobalData
.gSkuids
.remove('COMMON')
2001 if self
.SkuUsageType
== self
.SINGLE
:
2002 if len(GlobalData
.gSkuids
) != 1:
2003 if 'DEFAULT' in GlobalData
.gSkuids
:
2004 GlobalData
.gSkuids
.remove('DEFAULT')
2005 if GlobalData
.gSkuids
:
2006 GlobalData
.gSkuids
.sort()
2008 def GetNextSkuId(self
, skuname
):
2009 if not self
.__SkuInherit
:
2010 self
.__SkuInherit
= {}
2011 for item
in self
.SkuData
.values():
2012 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
2013 return self
.__SkuInherit
.get(skuname
, "DEFAULT")
2015 def GetSkuChain(self
, sku
):
2016 if sku
== "DEFAULT":
2021 nextsku
= self
.GetNextSkuId(nextsku
)
2022 skulist
.append(nextsku
)
2023 if nextsku
== "DEFAULT":
2027 def SkuOverrideOrder(self
):
2029 for skuname
in self
.SkuIdSet
:
2030 skuorderset
.append(self
.GetSkuChain(skuname
))
2033 for index
in range(max(len(item
) for item
in skuorderset
)):
2034 for subset
in skuorderset
:
2035 if index
> len(subset
)-1:
2037 if subset
[index
] in skuorder
:
2039 skuorder
.append(subset
[index
])
2043 def __SkuUsageType(self
):
2045 if self
.__SkuIdentifier
.upper() == "ALL":
2046 return SkuClass
.MULTIPLE
2048 if len(self
.SkuIdSet
) == 1:
2049 if self
.SkuIdSet
[0] == 'DEFAULT':
2050 return SkuClass
.DEFAULT
2052 return SkuClass
.SINGLE
2053 elif len(self
.SkuIdSet
) == 2:
2054 if 'DEFAULT' in self
.SkuIdSet
:
2055 return SkuClass
.SINGLE
2057 return SkuClass
.MULTIPLE
2059 return SkuClass
.MULTIPLE
2060 def DumpSkuIdArrary(self
):
2063 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2066 for skuname
in self
.AvailableSkuIds
:
2067 if skuname
== "COMMON":
2069 while skuname
!= "DEFAULT":
2070 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2071 skuname
= self
.GetNextSkuId(skuname
)
2072 ArrayStrList
.append("0x0")
2073 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2075 def __GetAvailableSkuIds(self
):
2076 return self
.AvailableSkuIds
2078 def __GetSystemSkuID(self
):
2079 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2080 if len(self
.SkuIdSet
) == 1:
2081 return self
.SkuIdSet
[0]
2083 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2086 def __GetAvailableSkuIdNumber(self
):
2087 return self
.SkuIdNumberSet
2088 SystemSkuId
= property(__GetSystemSkuID
)
2089 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2090 SkuUsageType
= property(__SkuUsageType
)
2091 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2094 # Pack a registry format GUID
2096 def PackRegistryFormatGuid(Guid
):
2097 return PackGUID(Guid
.split('-'))
2099 ## Get the integer value from string like "14U" or integer like 2
2101 # @param Input The object that may be either a integer value or a string
2103 # @retval Value The integer value that the input represents
2105 def GetIntegerValue(Input
):
2106 if type(Input
) in (int, long):
2109 if String
.endswith("U"):
2110 String
= String
[:-1]
2111 if String
.endswith("ULL"):
2112 String
= String
[:-3]
2113 if String
.endswith("LL"):
2114 String
= String
[:-2]
2116 if String
.startswith("0x") or String
.startswith("0X"):
2117 return int(String
, 16)
2124 # Pack a GUID (registry format) list into a buffer and return it
2127 return pack(PACK_PATTERN_GUID
,
2131 int(Guid
[3][-4:-2], 16),
2132 int(Guid
[3][-2:], 16),
2133 int(Guid
[4][-12:-10], 16),
2134 int(Guid
[4][-10:-8], 16),
2135 int(Guid
[4][-8:-6], 16),
2136 int(Guid
[4][-6:-4], 16),
2137 int(Guid
[4][-4:-2], 16),
2138 int(Guid
[4][-2:], 16)
2142 # Pack a GUID (byte) list into a buffer and return it
2144 def PackByteFormatGUID(Guid
):
2145 return pack(PACK_PATTERN_GUID
,
2161 # This acts like the main() function for the script, unless it is 'import'ed into another
2164 if __name__
== '__main__':