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 import Common
.LongFilePathOs
as os
27 from struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 from CommonDataClass
.Exceptions
import BadExpression
42 ## Regular expression used to find out place holders in string template
43 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
45 ## regular expressions for map file processing
46 startPatternGeneral
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
47 addressPatternGeneral
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
48 valuePatternGcc
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
49 pcdPatternGcc
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
50 secReGeneral
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
52 ## Dictionary used to store file time stamp for quick re-access
53 gFileTimeStampCache
= {} # {file path : file time stamp}
55 ## Dictionary used to store dependencies of files
56 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
59 # If a module is built more than once with different PCDs or library classes
60 # a temporary INF file with same content is created, the temporary file is removed
65 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
66 """ Parse map file to get variable offset in current EFI file
67 @param mapfilepath Map file absolution path
68 @param efifilepath: EFI binary file full path
69 @param varnames iteratable container whose elements are variable names to be searched
71 @return List whos elements are tuple with variable name and raw offset
75 f
= open(mapfilepath
, 'r')
81 if len(lines
) == 0: return None
82 firstline
= lines
[0].strip()
83 if (firstline
.startswith("Archive member included ") and
84 firstline
.endswith(" file (symbol)")):
85 return _parseForGCC(lines
, efifilepath
, varnames
)
86 if firstline
.startswith("# Path:"):
87 return _parseForXcode(lines
, efifilepath
, varnames
)
88 return _parseGeneral(lines
, efifilepath
, varnames
)
90 def _parseForXcode(lines
, efifilepath
, varnames
):
95 if status
== 0 and line
== "# Symbols:":
98 if status
== 1 and len(line
) != 0:
99 for varname
in varnames
:
101 # cannot pregenerate this RegEx since it uses varname from varnames.
102 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
104 ret
.append((varname
, m
.group(1)))
107 def _parseForGCC(lines
, efifilepath
, varnames
):
108 """ Parse map file generated by GCC linker """
112 for index
, line
in enumerate(lines
):
114 # status machine transection
115 if status
== 0 and line
== "Memory Configuration":
118 elif status
== 1 and line
== 'Linker script and memory map':
121 elif status
==2 and line
== 'START GROUP':
127 m
= valuePatternGcc
.match(line
)
129 sections
.append(m
.groups(0))
130 for varname
in varnames
:
132 m
= re
.match("^.data.(%s)" % varname
, line
)
134 m
= re
.match(".data.(%s)$" % varname
, line
)
136 Str
= lines
[index
+ 1]
138 Str
= line
[len(".data.%s" % varname
):]
140 m
= pcdPatternGcc
.match(Str
.strip())
142 varoffset
.append((varname
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
146 # get section information from efi file
147 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
148 if efisecs
is None or len(efisecs
) == 0:
152 for efisec
in efisecs
:
153 for section
in sections
:
154 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
155 redirection
= int(section
[1], 16) - efisec
[1]
158 for var
in varoffset
:
159 for efisec
in efisecs
:
160 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
161 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
164 def _parseGeneral(lines
, efifilepath
, varnames
):
165 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
166 secs
= [] # key = section name
168 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
172 if startPatternGeneral
.match(line
):
175 if addressPatternGeneral
.match(line
):
178 if line
.startswith("entry point at"):
181 if status
== 1 and len(line
) != 0:
182 m
= secReGeneral
.match(line
)
183 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
184 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
185 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
186 if status
== 2 and len(line
) != 0:
187 for varname
in varnames
:
188 m
= symRe
.match(line
)
189 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
190 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
191 sec_no
= int(sec_no
, 16)
192 sym_offset
= int(sym_offset
, 16)
193 vir_addr
= int(vir_addr
, 16)
194 # cannot pregenerate this RegEx since it uses varname from varnames.
195 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
197 # fond a binary pcd entry in map file
199 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
200 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
202 if not varoffset
: return []
204 # get section information from efi file
205 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
206 if efisecs
is None or len(efisecs
) == 0:
210 for var
in varoffset
:
212 for efisec
in efisecs
:
214 if var
[1].strip() == efisec
[0].strip():
215 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
216 elif var
[4] == index
:
217 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
221 ## Routine to process duplicated INF
223 # This function is called by following two cases:
226 # Pkg/module/module.inf
227 # Pkg/module/module.inf {
229 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
232 # INF Pkg/module/module.inf
233 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
235 # This function copies Pkg/module/module.inf to
236 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
238 # @param Path Original PathClass object
239 # @param BaseName New file base name
241 # @retval return the new PathClass object
243 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
244 Filename
= os
.path
.split(Path
.File
)[1]
246 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
248 Filename
= BaseName
+ Path
.BaseName
251 # If -N is specified on command line, cache is disabled
252 # The directory has to be created
254 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
255 if not os
.path
.exists(DbDir
):
258 # A temporary INF is copied to database path which must have write permission
259 # The temporary will be removed at the end of build
260 # In case of name conflict, the file name is
261 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
263 TempFullPath
= os
.path
.join(DbDir
,
265 RtPath
= PathClass(Path
.File
, Workspace
)
267 # Modify the full path to temporary path, keep other unchanged
269 # To build same module more than once, the module path with FILE_GUID overridden has
270 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
271 # in DSC which is used as relative path by C files and other files in INF.
272 # A trick was used: all module paths are PathClass instances, after the initialization
273 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
275 # The reason for creating a temporary INF is:
276 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
277 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
278 # A different key for the same module is needed to create different output directory,
279 # retrieve overridden PCDs, library instances.
281 # The BaseName is the FILE_GUID which is also the output directory name.
284 RtPath
.Path
= TempFullPath
285 RtPath
.BaseName
= BaseName
287 # If file exists, compare contents
289 if os
.path
.exists(TempFullPath
):
290 with
open(str(Path
), 'rb') as f1
, open(TempFullPath
, 'rb') as f2
:
291 if f1
.read() == f2
.read():
293 _TempInfs
.append(TempFullPath
)
294 shutil
.copy2(str(Path
), TempFullPath
)
297 ## Remove temporary created INFs whose paths were saved in _TempInfs
299 def ClearDuplicatedInf():
301 File
= _TempInfs
.pop()
302 if os
.path
.exists(File
):
305 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
307 # @param Guid The GUID string
309 # @retval string The GUID string in C structure style
311 def GuidStringToGuidStructureString(Guid
):
312 GuidList
= Guid
.split('-')
314 for Index
in range(0, 3, 1):
315 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
316 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
317 for Index
in range(0, 12, 2):
318 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
322 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
324 # @param GuidValue The GUID value in byte array
326 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
328 def GuidStructureByteArrayToGuidString(GuidValue
):
329 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
330 guidValueList
= guidValueString
.split(",")
331 if len(guidValueList
) != 16:
333 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
335 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
336 int(guidValueList
[3], 16),
337 int(guidValueList
[2], 16),
338 int(guidValueList
[1], 16),
339 int(guidValueList
[0], 16),
340 int(guidValueList
[5], 16),
341 int(guidValueList
[4], 16),
342 int(guidValueList
[7], 16),
343 int(guidValueList
[6], 16),
344 int(guidValueList
[8], 16),
345 int(guidValueList
[9], 16),
346 int(guidValueList
[10], 16),
347 int(guidValueList
[11], 16),
348 int(guidValueList
[12], 16),
349 int(guidValueList
[13], 16),
350 int(guidValueList
[14], 16),
351 int(guidValueList
[15], 16)
356 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
358 # @param GuidValue The GUID value in C structure format
360 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
362 def GuidStructureStringToGuidString(GuidValue
):
363 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
364 guidValueList
= guidValueString
.split(",")
365 if len(guidValueList
) != 11:
367 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
369 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
370 int(guidValueList
[0], 16),
371 int(guidValueList
[1], 16),
372 int(guidValueList
[2], 16),
373 int(guidValueList
[3], 16),
374 int(guidValueList
[4], 16),
375 int(guidValueList
[5], 16),
376 int(guidValueList
[6], 16),
377 int(guidValueList
[7], 16),
378 int(guidValueList
[8], 16),
379 int(guidValueList
[9], 16),
380 int(guidValueList
[10], 16)
385 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
387 # @param GuidValue The GUID value in C structure format
389 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
391 def GuidStructureStringToGuidValueName(GuidValue
):
392 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
393 guidValueList
= guidValueString
.split(",")
394 if len(guidValueList
) != 11:
395 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
396 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
397 int(guidValueList
[0], 16),
398 int(guidValueList
[1], 16),
399 int(guidValueList
[2], 16),
400 int(guidValueList
[3], 16),
401 int(guidValueList
[4], 16),
402 int(guidValueList
[5], 16),
403 int(guidValueList
[6], 16),
404 int(guidValueList
[7], 16),
405 int(guidValueList
[8], 16),
406 int(guidValueList
[9], 16),
407 int(guidValueList
[10], 16)
410 ## Create directories
412 # @param Directory The directory name
414 def CreateDirectory(Directory
):
415 if Directory
is None or Directory
.strip() == "":
418 if not os
.access(Directory
, os
.F_OK
):
419 os
.makedirs(Directory
)
424 ## Remove directories, including files and sub-directories in it
426 # @param Directory The directory name
428 def RemoveDirectory(Directory
, Recursively
=False):
429 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
432 CurrentDirectory
= os
.getcwd()
434 for File
in os
.listdir("."):
435 if os
.path
.isdir(File
):
436 RemoveDirectory(File
, Recursively
)
439 os
.chdir(CurrentDirectory
)
442 ## Store content in file
444 # This method is used to save file only when its content is changed. This is
445 # quite useful for "make" system to decide what will be re-built and what won't.
447 # @param File The path of file
448 # @param Content The new content of the file
449 # @param IsBinaryFile The flag indicating if the file is binary file or not
451 # @retval True If the file content is changed and the file is renewed
452 # @retval False If the file content is the same
454 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
456 Content
= Content
.replace("\n", os
.linesep
)
458 if os
.path
.exists(File
):
460 if Content
== open(File
, "rb").read():
463 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
465 DirName
= os
.path
.dirname(File
)
466 if not CreateDirectory(DirName
):
467 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
470 DirName
= os
.getcwd()
471 if not os
.access(DirName
, os
.W_OK
):
472 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
475 if GlobalData
.gIsWindows
:
477 from PyUtility
import SaveFileToDisk
478 if not SaveFileToDisk(File
, Content
):
479 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
481 Fd
= open(File
, "wb")
485 Fd
= open(File
, "wb")
489 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
493 ## Make a Python object persistent on file system
495 # @param Data The object to be stored in file
496 # @param File The path of file to store the object
498 def DataDump(Data
, File
):
501 Fd
= open(File
, 'wb')
502 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
504 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
509 ## Restore a Python object from a file
511 # @param File The path of file stored the object
513 # @retval object A python object
514 # @retval None If failure in file operation
516 def DataRestore(File
):
520 Fd
= open(File
, 'rb')
521 Data
= cPickle
.load(Fd
)
522 except Exception as e
:
523 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
530 ## Retrieve and cache the real path name in file system
532 # @param Root The root directory of path relative to
534 # @retval str The path string if the path exists
535 # @retval None If path doesn't exist
541 def __init__(self
, Root
):
543 for F
in os
.listdir(Root
):
545 self
._UPPER
_CACHE
_[F
.upper()] = F
548 def __getitem__(self
, Path
):
549 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
552 if Path
and Path
[0] == os
.path
.sep
:
554 if Path
in self
._CACHE
_:
555 return os
.path
.join(self
._Root
, Path
)
556 UpperPath
= Path
.upper()
557 if UpperPath
in self
._UPPER
_CACHE
_:
558 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
562 SepIndex
= Path
.find(os
.path
.sep
)
564 Parent
= UpperPath
[:SepIndex
]
565 if Parent
not in self
._UPPER
_CACHE
_:
567 LastSepIndex
= SepIndex
568 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
570 if LastSepIndex
== -1:
575 SepIndex
= LastSepIndex
577 Parent
= Path
[:SepIndex
]
578 ParentKey
= UpperPath
[:SepIndex
]
579 if ParentKey
not in self
._UPPER
_CACHE
_:
583 if Parent
in self
._CACHE
_:
586 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
587 for F
in os
.listdir(ParentDir
):
588 Dir
= os
.path
.join(ParentDir
, F
)
589 self
._CACHE
_.add(Dir
)
590 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
592 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
595 if Path
in self
._CACHE
_:
596 return os
.path
.join(self
._Root
, Path
)
597 elif UpperPath
in self
._UPPER
_CACHE
_:
598 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
601 def RealPath(File
, Dir
='', OverrideDir
=''):
602 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
603 NewFile
= GlobalData
.gAllFiles
[NewFile
]
604 if not NewFile
and OverrideDir
:
605 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
606 NewFile
= GlobalData
.gAllFiles
[NewFile
]
609 def RealPath2(File
, Dir
='', OverrideDir
=''):
612 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
614 if OverrideDir
[-1] == os
.path
.sep
:
615 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
617 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
618 if GlobalData
.gAllFiles
:
619 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
621 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
622 if not os
.path
.exists(NewFile
):
626 if Dir
[-1] == os
.path
.sep
:
627 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
629 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
635 ## Get GUID value from given packages
637 # @param CName The CName of the GUID
638 # @param PackageList List of packages looking-up in
639 # @param Inffile The driver file
641 # @retval GuidValue if the CName is found in any given package
642 # @retval None if the CName is not found in all given packages
644 def GuidValue(CName
, PackageList
, Inffile
= None):
645 for P
in PackageList
:
646 GuidKeys
= P
.Guids
.keys()
647 if Inffile
and P
._PrivateGuids
:
648 if not Inffile
.startswith(P
.MetaFile
.Dir
):
649 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
650 if CName
in GuidKeys
:
651 return P
.Guids
[CName
]
654 ## Get Protocol value from given packages
656 # @param CName The CName of the GUID
657 # @param PackageList List of packages looking-up in
658 # @param Inffile The driver file
660 # @retval GuidValue if the CName is found in any given package
661 # @retval None if the CName is not found in all given packages
663 def ProtocolValue(CName
, PackageList
, Inffile
= None):
664 for P
in PackageList
:
665 ProtocolKeys
= P
.Protocols
.keys()
666 if Inffile
and P
._PrivateProtocols
:
667 if not Inffile
.startswith(P
.MetaFile
.Dir
):
668 ProtocolKeys
= [x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
]
669 if CName
in ProtocolKeys
:
670 return P
.Protocols
[CName
]
673 ## Get PPI value from given packages
675 # @param CName The CName of the GUID
676 # @param PackageList List of packages looking-up in
677 # @param Inffile The driver file
679 # @retval GuidValue if the CName is found in any given package
680 # @retval None if the CName is not found in all given packages
682 def PpiValue(CName
, PackageList
, Inffile
= None):
683 for P
in PackageList
:
684 PpiKeys
= P
.Ppis
.keys()
685 if Inffile
and P
._PrivatePpis
:
686 if not Inffile
.startswith(P
.MetaFile
.Dir
):
687 PpiKeys
= [x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
]
692 ## A string template class
694 # This class implements a template for string replacement. A string template
695 # looks like following
697 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
699 # The string between ${BEGIN} and ${END} will be repeated as many times as the
700 # length of "placeholder_name", which is a list passed through a dict. The
701 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
702 # be not used and, in this case, the "placeholder_name" must not a list and it
703 # will just be replaced once.
705 class TemplateString(object):
706 _REPEAT_START_FLAG
= "BEGIN"
707 _REPEAT_END_FLAG
= "END"
709 class Section(object):
710 _LIST_TYPES
= [type([]), type(set()), type((0,))]
712 def __init__(self
, TemplateSection
, PlaceHolderList
):
713 self
._Template
= TemplateSection
714 self
._PlaceHolderList
= []
716 # Split the section into sub-sections according to the position of placeholders
718 self
._SubSectionList
= []
721 # The placeholders passed in must be in the format of
723 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
725 for PlaceHolder
, Start
, End
in PlaceHolderList
:
726 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
727 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
728 self
._PlaceHolderList
.append(PlaceHolder
)
729 SubSectionStart
= End
730 if SubSectionStart
< len(TemplateSection
):
731 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
733 self
._SubSectionList
= [TemplateSection
]
736 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
738 def Instantiate(self
, PlaceHolderValues
):
740 RepeatPlaceHolders
= {}
741 NonRepeatPlaceHolders
= {}
743 for PlaceHolder
in self
._PlaceHolderList
:
744 if PlaceHolder
not in PlaceHolderValues
:
746 Value
= PlaceHolderValues
[PlaceHolder
]
747 if type(Value
) in self
._LIST
_TYPES
:
749 RepeatTime
= len(Value
)
750 elif RepeatTime
!= len(Value
):
754 "${%s} has different repeat time from others!" % PlaceHolder
,
755 ExtraData
=str(self
._Template
)
757 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
759 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
761 if NonRepeatPlaceHolders
:
763 for S
in self
._SubSectionList
:
764 if S
not in NonRepeatPlaceHolders
:
767 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
769 StringList
= self
._SubSectionList
771 if RepeatPlaceHolders
:
773 for Index
in range(RepeatTime
):
775 if S
not in RepeatPlaceHolders
:
776 TempStringList
.append(S
)
778 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
779 StringList
= TempStringList
781 return "".join(StringList
)
784 def __init__(self
, Template
=None):
786 self
.IsBinary
= False
787 self
._Template
= Template
788 self
._TemplateSectionList
= self
._Parse
(Template
)
792 # @retval string The string replaced
797 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
799 # @retval list A list of TemplateString.Section objects
801 def _Parse(self
, Template
):
806 TemplateSectionList
= []
808 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
810 if MatchEnd
<= len(Template
):
811 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
812 TemplateSectionList
.append(TemplateSection
)
815 MatchString
= MatchObj
.group(1)
816 MatchStart
= MatchObj
.start()
817 MatchEnd
= MatchObj
.end()
819 if MatchString
== self
._REPEAT
_START
_FLAG
:
820 if MatchStart
> SectionStart
:
821 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
822 TemplateSectionList
.append(TemplateSection
)
823 SectionStart
= MatchEnd
825 elif MatchString
== self
._REPEAT
_END
_FLAG
:
826 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
827 TemplateSectionList
.append(TemplateSection
)
828 SectionStart
= MatchEnd
831 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
832 SearchFrom
= MatchEnd
833 return TemplateSectionList
835 ## Replace the string template with dictionary of placeholders and append it to previous one
837 # @param AppendString The string template to append
838 # @param Dictionary The placeholder dictionaries
840 def Append(self
, AppendString
, Dictionary
=None):
842 SectionList
= self
._Parse
(AppendString
)
843 self
.String
+= "".join(S
.Instantiate(Dictionary
) for S
in SectionList
)
845 self
.String
+= AppendString
847 ## Replace the string template with dictionary of placeholders
849 # @param Dictionary The placeholder dictionaries
851 # @retval str The string replaced with placeholder values
853 def Replace(self
, Dictionary
=None):
854 return "".join(S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
)
856 ## Progress indicator class
858 # This class makes use of thread to print progress on console.
861 # for avoiding deadloop
863 _ProgressThread
= None
864 _CheckInterval
= 0.25
868 # @param OpenMessage The string printed before progress charaters
869 # @param CloseMessage The string printed after progress charaters
870 # @param ProgressChar The charater used to indicate the progress
871 # @param Interval The interval in seconds between two progress charaters
873 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
874 self
.PromptMessage
= OpenMessage
875 self
.CodaMessage
= CloseMessage
876 self
.ProgressChar
= ProgressChar
877 self
.Interval
= Interval
878 if Progressor
._StopFlag
is None:
879 Progressor
._StopFlag
= threading
.Event()
881 ## Start to print progress charater
883 # @param OpenMessage The string printed before progress charaters
885 def Start(self
, OpenMessage
=None):
886 if OpenMessage
is not None:
887 self
.PromptMessage
= OpenMessage
888 Progressor
._StopFlag
.clear()
889 if Progressor
._ProgressThread
is None:
890 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
891 Progressor
._ProgressThread
.setDaemon(False)
892 Progressor
._ProgressThread
.start()
894 ## Stop printing progress charater
896 # @param CloseMessage The string printed after progress charaters
898 def Stop(self
, CloseMessage
=None):
899 OriginalCodaMessage
= self
.CodaMessage
900 if CloseMessage
is not None:
901 self
.CodaMessage
= CloseMessage
903 self
.CodaMessage
= OriginalCodaMessage
905 ## Thread entry method
906 def _ProgressThreadEntry(self
):
907 sys
.stdout
.write(self
.PromptMessage
+ " ")
910 while not Progressor
._StopFlag
.isSet():
912 sys
.stdout
.write(self
.ProgressChar
)
914 TimeUp
= self
.Interval
915 time
.sleep(self
._CheckInterval
)
916 TimeUp
-= self
._CheckInterval
917 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
920 ## Abort the progress display
923 if Progressor
._StopFlag
is not None:
924 Progressor
._StopFlag
.set()
925 if Progressor
._ProgressThread
is not None:
926 Progressor
._ProgressThread
.join()
927 Progressor
._ProgressThread
= None
929 ## A dict which can access its keys and/or values orderly
931 # The class implements a new kind of dict which its keys or values can be
932 # accessed in the order they are added into the dict. It guarantees the order
933 # by making use of an internal list to keep a copy of keys.
935 class sdict(IterableUserDict
):
938 IterableUserDict
.__init
__(self
)
942 def __setitem__(self
, key
, value
):
943 if key
not in self
._key
_list
:
944 self
._key
_list
.append(key
)
945 IterableUserDict
.__setitem
__(self
, key
, value
)
948 def __delitem__(self
, key
):
949 self
._key
_list
.remove(key
)
950 IterableUserDict
.__delitem
__(self
, key
)
952 ## used in "for k in dict" loop to ensure the correct order
954 return self
.iterkeys()
958 return len(self
._key
_list
)
961 def __contains__(self
, key
):
962 return key
in self
._key
_list
965 def index(self
, key
):
966 return self
._key
_list
.index(key
)
969 def insert(self
, key
, newkey
, newvalue
, order
):
970 index
= self
._key
_list
.index(key
)
971 if order
== 'BEFORE':
972 self
._key
_list
.insert(index
, newkey
)
973 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
974 elif order
== 'AFTER':
975 self
._key
_list
.insert(index
+ 1, newkey
)
976 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
979 def append(self
, sdict
):
981 if key
not in self
._key
_list
:
982 self
._key
_list
.append(key
)
983 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
985 def has_key(self
, key
):
986 return key
in self
._key
_list
991 IterableUserDict
.clear(self
)
993 ## Return a copy of keys
996 for key
in self
._key
_list
:
1000 ## Return a copy of values
1003 for key
in self
._key
_list
:
1004 values
.append(self
[key
])
1007 ## Return a copy of (key, value) list
1010 for key
in self
._key
_list
:
1011 items
.append((key
, self
[key
]))
1014 ## Iteration support
1015 def iteritems(self
):
1016 return iter(self
.items())
1018 ## Keys interation support
1020 return iter(self
.keys())
1022 ## Values interation support
1023 def itervalues(self
):
1024 return iter(self
.values())
1026 ## Return value related to a key, and remove the (key, value) from the dict
1027 def pop(self
, key
, *dv
):
1029 if key
in self
._key
_list
:
1031 self
.__delitem
__(key
)
1036 ## Return (key, value) pair, and remove the (key, value) from the dict
1038 key
= self
._key
_list
[-1]
1040 self
.__delitem
__(key
)
1043 def update(self
, dict=None, **kwargs
):
1044 if dict is not None:
1045 for k
, v
in dict.items():
1048 for k
, v
in kwargs
.items():
1051 ## Dictionary with restricted keys
1055 def __init__(self
, KeyList
):
1057 dict.__setitem
__(self
, Key
, "")
1060 def __setitem__(self
, key
, value
):
1062 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1063 ExtraData
=", ".join(dict.keys(self
)))
1064 dict.__setitem
__(self
, key
, value
)
1067 def __getitem__(self
, key
):
1070 return dict.__getitem
__(self
, key
)
1073 def __delitem__(self
, key
):
1074 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1079 self
.__setitem
__(Key
, "")
1081 ## Return value related to a key, and remove the (key, value) from the dict
1082 def pop(self
, key
, *dv
):
1083 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1085 ## Return (key, value) pair, and remove the (key, value) from the dict
1087 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1089 ## Dictionary using prioritized list as key
1092 _ListType
= type([])
1093 _TupleType
= type(())
1094 _Wildcard
= 'COMMON'
1095 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1097 def __init__(self
, _Single_
=False, _Level_
=2):
1098 self
._Level
_ = _Level_
1100 self
._Single
_ = _Single_
1103 def __getitem__(self
, key
):
1106 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1110 elif self
._Level
_ > 1:
1111 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1114 if self
._Level
_ > 1:
1115 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1117 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1118 FirstKey
= self
._Wildcard
1121 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1123 return self
._GetAllValues
(FirstKey
, RestKeys
)
1125 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1127 #print "%s-%s" % (FirstKey, self._Level_) ,
1128 if self
._Level
_ > 1:
1129 if FirstKey
== self
._Wildcard
:
1130 if FirstKey
in self
.data
:
1131 Value
= self
.data
[FirstKey
][RestKeys
]
1133 for Key
in self
.data
:
1134 Value
= self
.data
[Key
][RestKeys
]
1135 if Value
is not None: break
1137 if FirstKey
in self
.data
:
1138 Value
= self
.data
[FirstKey
][RestKeys
]
1139 if Value
is None and self
._Wildcard
in self
.data
:
1141 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1143 if FirstKey
== self
._Wildcard
:
1144 if FirstKey
in self
.data
:
1145 Value
= self
.data
[FirstKey
]
1147 for Key
in self
.data
:
1148 Value
= self
.data
[Key
]
1149 if Value
is not None: break
1151 if FirstKey
in self
.data
:
1152 Value
= self
.data
[FirstKey
]
1153 elif self
._Wildcard
in self
.data
:
1154 Value
= self
.data
[self
._Wildcard
]
1157 def _GetAllValues(self
, FirstKey
, RestKeys
):
1159 if self
._Level
_ > 1:
1160 if FirstKey
== self
._Wildcard
:
1161 for Key
in self
.data
:
1162 Value
+= self
.data
[Key
][RestKeys
]
1164 if FirstKey
in self
.data
:
1165 Value
+= self
.data
[FirstKey
][RestKeys
]
1166 if self
._Wildcard
in self
.data
:
1167 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1169 if FirstKey
== self
._Wildcard
:
1170 for Key
in self
.data
:
1171 Value
.append(self
.data
[Key
])
1173 if FirstKey
in self
.data
:
1174 Value
.append(self
.data
[FirstKey
])
1175 if self
._Wildcard
in self
.data
:
1176 Value
.append(self
.data
[self
._Wildcard
])
1180 def __setitem__(self
, key
, value
):
1183 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1188 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1191 if self
._Level
_ > 1:
1192 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1194 if FirstKey
in self
._ValidWildcardList
:
1195 FirstKey
= self
._Wildcard
1197 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1198 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1200 if self
._Level
_ > 1:
1201 self
.data
[FirstKey
][RestKeys
] = value
1203 self
.data
[FirstKey
] = value
1205 def SetGreedyMode(self
):
1206 self
._Single
_ = False
1207 if self
._Level
_ > 1:
1208 for Key
in self
.data
:
1209 self
.data
[Key
].SetGreedyMode()
1211 def SetSingleMode(self
):
1212 self
._Single
_ = True
1213 if self
._Level
_ > 1:
1214 for Key
in self
.data
:
1215 self
.data
[Key
].SetSingleMode()
1217 def GetKeys(self
, KeyIndex
=0):
1218 assert KeyIndex
>= 0
1220 return set(self
.data
.keys())
1223 for Key
in self
.data
:
1224 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1227 def IsFieldValueAnArray (Value
):
1228 Value
= Value
.strip()
1229 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1231 if Value
.startswith('L"') and Value
.endswith('"') and len(list(Value
[2:-1])) > 1:
1233 if Value
[0] == '"' and Value
[-1] == '"' and len(list(Value
[1:-1])) > 1:
1235 if Value
[0] == '{' and Value
[-1] == '}':
1237 if Value
.startswith("L'") and Value
.endswith("'") and len(list(Value
[2:-1])) > 1:
1239 if Value
[0] == "'" and Value
[-1] == "'" and len(list(Value
[1:-1])) > 1:
1243 def AnalyzePcdExpression(Setting
):
1244 Setting
= Setting
.strip()
1245 # There might be escaped quote in a string: \", \\\" , \', \\\'
1247 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1249 InSingleQuoteStr
= False
1250 InDoubleQuoteStr
= False
1252 for Index
, ch
in enumerate(Data
):
1253 if ch
== '"' and not InSingleQuoteStr
:
1254 if Data
[Index
- 1] != '\\':
1255 InDoubleQuoteStr
= not InDoubleQuoteStr
1256 elif ch
== "'" and not InDoubleQuoteStr
:
1257 if Data
[Index
- 1] != '\\':
1258 InSingleQuoteStr
= not InSingleQuoteStr
1259 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1261 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1264 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1271 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1273 FieldList
.append(Setting
[StartPos
:].strip())
1275 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1280 def ParseDevPathValue (Value
):
1282 Value
.replace('\\', '/').replace(' ', '')
1284 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1286 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1287 out
, err
= p
.communicate()
1288 except Exception as X
:
1289 raise BadExpression("DevicePath: %s" % (str(X
)) )
1291 subprocess
._cleanup
()
1295 raise BadExpression("DevicePath: %s" % str(err
))
1296 Size
= len(out
.split())
1297 out
= ','.join(out
.split())
1298 return '{' + out
+ '}', Size
1300 def ParseFieldValue (Value
):
1301 if isinstance(Value
, type(0)):
1302 return Value
, (Value
.bit_length() + 7) / 8
1303 if not isinstance(Value
, type('')):
1304 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1305 Value
= Value
.strip()
1306 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1307 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1309 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1311 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1312 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1314 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1316 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1317 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1319 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1321 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1322 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1324 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1326 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1327 Value
= Value
.split('(', 1)[1][:-1].strip()
1328 if Value
[0] == '{' and Value
[-1] == '}':
1329 TmpValue
= GuidStructureStringToGuidString(Value
)
1330 if len(TmpValue
) == 0:
1331 raise BadExpression("Invalid GUID value string %s" % Value
)
1333 if Value
[0] == '"' and Value
[-1] == '"':
1336 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1337 except ValueError as Message
:
1338 raise BadExpression(Message
)
1339 Value
, Size
= ParseFieldValue(Value
)
1341 if Value
.startswith('L"') and Value
.endswith('"'):
1343 # translate escape character
1353 Value
= (Value
<< 16) |
ord(Char
)
1354 return Value
, (len(List
) + 1) * 2
1355 if Value
.startswith('"') and Value
.endswith('"'):
1357 # translate escape character
1366 Value
= (Value
<< 8) |
ord(Char
)
1367 return Value
, len(List
) + 1
1368 if Value
.startswith("L'") and Value
.endswith("'"):
1369 # Unicode Character Constant
1370 # translate escape character
1378 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1382 Value
= (Value
<< 16) |
ord(Char
)
1383 return Value
, len(List
) * 2
1384 if Value
.startswith("'") and Value
.endswith("'"):
1385 # Character constant
1386 # translate escape character
1393 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1397 Value
= (Value
<< 8) |
ord(Char
)
1398 return Value
, len(List
)
1399 if Value
.startswith('{') and Value
.endswith('}'):
1402 List
= [Item
.strip() for Item
in Value
.split(',')]
1407 ItemValue
, Size
= ParseFieldValue(Item
)
1409 for I
in range(Size
):
1410 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1411 return Value
, RetSize
1412 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1413 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1414 Value
= Value
.strip().strip('"')
1415 return ParseDevPathValue(Value
)
1416 if Value
.lower().startswith('0x'):
1417 Value
= int(Value
, 16)
1420 return Value
, (Value
.bit_length() + 7) / 8
1421 if Value
[0].isdigit():
1422 Value
= int(Value
, 10)
1425 return Value
, (Value
.bit_length() + 7) / 8
1426 if Value
.lower() == 'true':
1428 if Value
.lower() == 'false':
1434 # Analyze DSC PCD value, since there is no data type info in DSC
1435 # This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1436 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1437 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1438 # 3. Dynamic default:
1439 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1440 # TokenSpace.PcdCName|PcdValue
1442 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1443 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1445 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1446 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1447 # there might have "|" operator, also in string value.
1449 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1450 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1451 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1453 # ValueList: A List contain fields described above
1454 # IsValid: True if conforming EBNF, otherwise False
1455 # Index: The index where PcdValue is in ValueList
1457 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1458 FieldList
= AnalyzePcdExpression(Setting
)
1461 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1462 Value
= FieldList
[0]
1464 if len(FieldList
) > 1:
1465 if FieldList
[1].upper().startswith("0X") or FieldList
[1].isdigit():
1468 DataType
= FieldList
[1]
1470 if len(FieldList
) > 2:
1473 IsValid
= (len(FieldList
) <= 1)
1475 IsValid
= (len(FieldList
) <= 3)
1476 # Value, Size = ParseFieldValue(Value)
1479 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1483 return [str(Value
), '', str(Size
)], IsValid
, 0
1484 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1485 Value
= FieldList
[0]
1487 if len(FieldList
) > 1:
1491 if len(FieldList
) > 2:
1494 IsValid
= (len(FieldList
) <= 1)
1496 IsValid
= (len(FieldList
) <= 3)
1500 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1504 return [Value
, Type
, str(Size
)], IsValid
, 0
1505 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1506 VpdOffset
= FieldList
[0]
1508 if not DataType
== TAB_VOID
:
1509 if len(FieldList
) > 1:
1510 Value
= FieldList
[1]
1512 if len(FieldList
) > 1:
1514 if len(FieldList
) > 2:
1515 Value
= FieldList
[2]
1517 IsValid
= (len(FieldList
) <= 1)
1519 IsValid
= (len(FieldList
) <= 3)
1522 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1526 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1527 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1528 HiiString
= FieldList
[0]
1529 Guid
= Offset
= Value
= Attribute
= ''
1530 if len(FieldList
) > 1:
1532 if len(FieldList
) > 2:
1533 Offset
= FieldList
[2]
1534 if len(FieldList
) > 3:
1535 Value
= FieldList
[3]
1536 if len(FieldList
) > 4:
1537 Attribute
= FieldList
[4]
1538 IsValid
= (3 <= len(FieldList
) <= 5)
1539 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1544 # Analyze the pcd Value, Datum type and TokenNumber.
1545 # Used to avoid split issue while the value string contain "|" character
1547 # @param[in] Setting: A String contain value/datum type/token number information;
1549 # @retval ValueList: A List contain value, datum type and toke number.
1551 def AnalyzePcdData(Setting
):
1552 ValueList
= ['', '', '']
1554 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1555 PtrValue
= ValueRe
.findall(Setting
)
1557 ValueUpdateFlag
= False
1559 if len(PtrValue
) >= 1:
1560 Setting
= re
.sub(ValueRe
, '', Setting
)
1561 ValueUpdateFlag
= True
1563 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1564 ValueList
[0:len(TokenList
)] = TokenList
1567 ValueList
[0] = PtrValue
[0]
1571 ## check format of PCD value against its the datum type
1573 # For PCD value setting
1575 def CheckPcdDatum(Type
, Value
):
1576 if Type
== TAB_VOID
:
1577 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1578 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1579 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1581 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1582 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1583 elif ValueRe
.match(Value
):
1584 # Check the chars in UnicodeString or CString is printable
1585 if Value
.startswith("L"):
1589 Printset
= set(string
.printable
)
1590 Printset
.remove(TAB_PRINTCHAR_VT
)
1591 Printset
.add(TAB_PRINTCHAR_BS
)
1592 Printset
.add(TAB_PRINTCHAR_NUL
)
1593 if not set(Value
).issubset(Printset
):
1594 PrintList
= sorted(Printset
)
1595 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1596 elif Type
== 'BOOLEAN':
1597 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1598 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1599 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1600 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1602 Value
= long(Value
, 0)
1604 return False, "Invalid value [%s] of type [%s];"\
1605 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1607 return True, "StructurePcd"
1611 ## Split command line option string to list
1613 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1614 # in non-windows platform to launch command
1616 def SplitOption(OptionString
):
1621 for Index
in range(0, len(OptionString
)):
1622 CurrentChar
= OptionString
[Index
]
1623 if CurrentChar
in ['"', "'"]:
1624 if QuotationMark
== CurrentChar
:
1626 elif QuotationMark
== "":
1627 QuotationMark
= CurrentChar
1632 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1633 if Index
> OptionStart
:
1634 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1636 LastChar
= CurrentChar
1637 OptionList
.append(OptionString
[OptionStart
:])
1640 def CommonPath(PathList
):
1641 P1
= min(PathList
).split(os
.path
.sep
)
1642 P2
= max(PathList
).split(os
.path
.sep
)
1643 for Index
in xrange(min(len(P1
), len(P2
))):
1644 if P1
[Index
] != P2
[Index
]:
1645 return os
.path
.sep
.join(P1
[:Index
])
1646 return os
.path
.sep
.join(P1
)
1649 # Convert string to C format array
1651 def ConvertStringToByteArray(Value
):
1652 Value
= Value
.strip()
1656 if not Value
.endswith('}'):
1658 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1659 ValFields
= Value
.split(',')
1661 for Index
in range(len(ValFields
)):
1662 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1665 Value
= '{' + ','.join(ValFields
) + '}'
1669 if Value
.startswith('L"'):
1670 if not Value
.endswith('"'):
1674 elif not Value
.startswith('"') or not Value
.endswith('"'):
1677 Value
= eval(Value
) # translate escape character
1679 for Index
in range(0, len(Value
)):
1681 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1683 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1684 Value
= NewValue
+ '0}'
1687 class PathClass(object):
1688 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1689 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1691 self
.File
= str(File
)
1692 if os
.path
.isabs(self
.File
):
1696 self
.Root
= str(Root
)
1697 self
.AlterRoot
= str(AlterRoot
)
1699 # Remove any '.' and '..' in path
1701 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1702 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1703 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1704 # eliminate the side-effect of 'C:'
1705 if self
.Root
[-1] == ':':
1706 self
.Root
+= os
.path
.sep
1707 # file path should not start with path separator
1708 if self
.Root
[-1] == os
.path
.sep
:
1709 self
.File
= self
.Path
[len(self
.Root
):]
1711 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1713 self
.Path
= os
.path
.normpath(self
.File
)
1715 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1716 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1720 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1722 self
.Dir
= self
.Root
1724 self
.Dir
= self
.SubDir
1729 self
.Type
= self
.Ext
.lower()
1731 self
.IsBinary
= IsBinary
1732 self
.Target
= Target
1733 self
.TagName
= TagName
1734 self
.ToolCode
= ToolCode
1735 self
.ToolChainFamily
= ToolChainFamily
1739 ## Convert the object of this class to a string
1741 # Convert member Path of the class to a string
1743 # @retval string Formatted String
1748 ## Override __eq__ function
1750 # Check whether PathClass are the same
1752 # @retval False The two PathClass are different
1753 # @retval True The two PathClass are the same
1755 def __eq__(self
, Other
):
1756 if isinstance(Other
, type(self
)):
1757 return self
.Path
== Other
.Path
1759 return self
.Path
== str(Other
)
1761 ## Override __cmp__ function
1763 # Customize the comparsion operation of two PathClass
1765 # @retval 0 The two PathClass are different
1766 # @retval -1 The first PathClass is less than the second PathClass
1767 # @retval 1 The first PathClass is Bigger than the second PathClass
1768 def __cmp__(self
, Other
):
1769 if isinstance(Other
, type(self
)):
1770 OtherKey
= Other
.Path
1772 OtherKey
= str(Other
)
1775 if SelfKey
== OtherKey
:
1777 elif SelfKey
> OtherKey
:
1782 ## Override __hash__ function
1784 # Use Path as key in hash table
1786 # @retval string Key for hash table
1789 return hash(self
.Path
)
1791 def _GetFileKey(self
):
1792 if self
._Key
is None:
1793 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1796 def _GetTimeStamp(self
):
1797 return os
.stat(self
.Path
)[8]
1799 def Validate(self
, Type
='', CaseSensitive
=True):
1800 if GlobalData
.gCaseInsensitive
:
1801 CaseSensitive
= False
1802 if Type
and Type
.lower() != self
.Type
:
1803 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1805 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1806 if not RealRoot
and not RealFile
:
1807 RealFile
= self
.File
1809 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1811 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1812 if len (mws
.getPkgPath()) == 0:
1813 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1815 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1819 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1820 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1821 ErrorCode
= FILE_CASE_MISMATCH
1822 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1824 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1825 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1827 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1830 self
.File
= RealFile
1831 self
.Root
= RealRoot
1832 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1833 return ErrorCode
, ErrorInfo
1835 Key
= property(_GetFileKey
)
1836 TimeStamp
= property(_GetTimeStamp
)
1838 ## Parse PE image to get the required PE informaion.
1840 class PeImageClass():
1843 # @param File FilePath of PeImage
1845 def __init__(self
, PeFile
):
1846 self
.FileName
= PeFile
1847 self
.IsValid
= False
1850 self
.SectionAlignment
= 0
1851 self
.SectionHeaderList
= []
1854 PeObject
= open(PeFile
, 'rb')
1856 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1859 ByteArray
= array
.array('B')
1860 ByteArray
.fromfile(PeObject
, 0x3E)
1861 ByteList
= ByteArray
.tolist()
1862 # DOS signature should be 'MZ'
1863 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1864 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1867 # Read 4 byte PE Signature
1868 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1869 PeObject
.seek(PeOffset
)
1870 ByteArray
= array
.array('B')
1871 ByteArray
.fromfile(PeObject
, 4)
1872 # PE signature should be 'PE\0\0'
1873 if ByteArray
.tostring() != 'PE\0\0':
1874 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1877 # Read PE file header
1878 ByteArray
= array
.array('B')
1879 ByteArray
.fromfile(PeObject
, 0x14)
1880 ByteList
= ByteArray
.tolist()
1881 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1883 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1886 # Read PE optional header
1887 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1888 ByteArray
= array
.array('B')
1889 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1890 ByteList
= ByteArray
.tolist()
1891 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1892 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1893 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1895 # Read each Section Header
1896 for Index
in range(SecNumber
):
1897 ByteArray
= array
.array('B')
1898 ByteArray
.fromfile(PeObject
, 0x28)
1899 ByteList
= ByteArray
.tolist()
1900 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1901 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1902 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1903 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1904 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1908 def _ByteListToStr(self
, ByteList
):
1910 for index
in range(len(ByteList
)):
1911 if ByteList
[index
] == 0:
1913 String
+= chr(ByteList
[index
])
1916 def _ByteListToInt(self
, ByteList
):
1918 for index
in range(len(ByteList
) - 1, -1, -1):
1919 Value
= (Value
<< 8) |
int(ByteList
[index
])
1922 class DefaultStore():
1923 def __init__(self
, DefaultStores
):
1925 self
.DefaultStores
= DefaultStores
1926 def DefaultStoreID(self
, DefaultStoreName
):
1927 for key
, value
in self
.DefaultStores
.items():
1928 if value
== DefaultStoreName
:
1931 def GetDefaultDefault(self
):
1932 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1933 return "0", TAB_DEFAULT_STORES_DEFAULT
1935 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1936 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1937 def GetMin(self
, DefaultSIdList
):
1938 if not DefaultSIdList
:
1939 return TAB_DEFAULT_STORES_DEFAULT
1940 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1943 minid
= min(storeidset
)
1944 for sid
, name
in self
.DefaultStores
.values():
1953 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1957 for SkuName
in SkuIds
:
1958 SkuId
= SkuIds
[SkuName
][0]
1959 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1960 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1961 EdkLogger
.error("build", PARAMETER_INVALID
,
1962 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1965 self
.AvailableSkuIds
= sdict()
1967 self
.SkuIdNumberSet
= []
1968 self
.SkuData
= SkuIds
1969 self
.__SkuInherit
= {}
1970 self
.__SkuIdentifier
= SkuIdentifier
1971 if SkuIdentifier
== '' or SkuIdentifier
is None:
1972 self
.SkuIdSet
= ['DEFAULT']
1973 self
.SkuIdNumberSet
= ['0U']
1974 elif SkuIdentifier
== 'ALL':
1975 self
.SkuIdSet
= SkuIds
.keys()
1976 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1978 r
= SkuIdentifier
.split('|')
1979 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1982 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1984 EdkLogger
.error("build", PARAMETER_INVALID
,
1985 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1986 % (k
, " | ".join(SkuIds
.keys())))
1987 for each
in self
.SkuIdSet
:
1989 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1991 EdkLogger
.error("build", PARAMETER_INVALID
,
1992 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1993 % (each
, " | ".join(SkuIds
.keys())))
1994 if self
.SkuUsageType
!= self
.SINGLE
:
1995 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1997 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1998 if 'COMMON' in GlobalData
.gSkuids
:
1999 GlobalData
.gSkuids
.remove('COMMON')
2000 if self
.SkuUsageType
== self
.SINGLE
:
2001 if len(GlobalData
.gSkuids
) != 1:
2002 if 'DEFAULT' in GlobalData
.gSkuids
:
2003 GlobalData
.gSkuids
.remove('DEFAULT')
2004 if GlobalData
.gSkuids
:
2005 GlobalData
.gSkuids
.sort()
2007 def GetNextSkuId(self
, skuname
):
2008 if not self
.__SkuInherit
:
2009 self
.__SkuInherit
= {}
2010 for item
in self
.SkuData
.values():
2011 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
2012 return self
.__SkuInherit
.get(skuname
, "DEFAULT")
2014 def GetSkuChain(self
, sku
):
2015 if sku
== "DEFAULT":
2020 nextsku
= self
.GetNextSkuId(nextsku
)
2021 skulist
.append(nextsku
)
2022 if nextsku
== "DEFAULT":
2026 def SkuOverrideOrder(self
):
2028 for skuname
in self
.SkuIdSet
:
2029 skuorderset
.append(self
.GetSkuChain(skuname
))
2032 for index
in range(max(len(item
) for item
in skuorderset
)):
2033 for subset
in skuorderset
:
2034 if index
> len(subset
)-1:
2036 if subset
[index
] in skuorder
:
2038 skuorder
.append(subset
[index
])
2042 def __SkuUsageType(self
):
2044 if self
.__SkuIdentifier
.upper() == "ALL":
2045 return SkuClass
.MULTIPLE
2047 if len(self
.SkuIdSet
) == 1:
2048 if self
.SkuIdSet
[0] == 'DEFAULT':
2049 return SkuClass
.DEFAULT
2051 return SkuClass
.SINGLE
2052 elif len(self
.SkuIdSet
) == 2:
2053 if 'DEFAULT' in self
.SkuIdSet
:
2054 return SkuClass
.SINGLE
2056 return SkuClass
.MULTIPLE
2058 return SkuClass
.MULTIPLE
2059 def DumpSkuIdArrary(self
):
2062 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2065 for skuname
in self
.AvailableSkuIds
:
2066 if skuname
== "COMMON":
2068 while skuname
!= "DEFAULT":
2069 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2070 skuname
= self
.GetNextSkuId(skuname
)
2071 ArrayStrList
.append("0x0")
2072 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2074 def __GetAvailableSkuIds(self
):
2075 return self
.AvailableSkuIds
2077 def __GetSystemSkuID(self
):
2078 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2079 if len(self
.SkuIdSet
) == 1:
2080 return self
.SkuIdSet
[0]
2082 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2085 def __GetAvailableSkuIdNumber(self
):
2086 return self
.SkuIdNumberSet
2087 SystemSkuId
= property(__GetSystemSkuID
)
2088 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2089 SkuUsageType
= property(__SkuUsageType
)
2090 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2093 # Pack a registry format GUID
2095 def PackRegistryFormatGuid(Guid
):
2096 return PackGUID(Guid
.split('-'))
2098 ## Get the integer value from string like "14U" or integer like 2
2100 # @param Input The object that may be either a integer value or a string
2102 # @retval Value The integer value that the input represents
2104 def GetIntegerValue(Input
):
2105 if type(Input
) in (int, long):
2108 if String
.endswith("U"):
2109 String
= String
[:-1]
2110 if String
.endswith("ULL"):
2111 String
= String
[:-3]
2112 if String
.endswith("LL"):
2113 String
= String
[:-2]
2115 if String
.startswith("0x") or String
.startswith("0X"):
2116 return int(String
, 16)
2123 # Pack a GUID (registry format) list into a buffer and return it
2126 return pack(PACK_PATTERN_GUID
,
2130 int(Guid
[3][-4:-2], 16),
2131 int(Guid
[3][-2:], 16),
2132 int(Guid
[4][-12:-10], 16),
2133 int(Guid
[4][-10:-8], 16),
2134 int(Guid
[4][-8:-6], 16),
2135 int(Guid
[4][-6:-4], 16),
2136 int(Guid
[4][-4:-2], 16),
2137 int(Guid
[4][-2:], 16)
2141 # Pack a GUID (byte) list into a buffer and return it
2143 def PackByteFormatGUID(Guid
):
2144 return pack(PACK_PATTERN_GUID
,
2160 # This acts like the main() function for the script, unless it is 'import'ed into another
2163 if __name__
== '__main__':