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
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 pickle
.dump(Data
, Fd
, pickle
.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
= pickle
.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 function 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[|VOID*[|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|VariableGuid|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_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1462 Value
= FieldList
[0]
1464 if len(FieldList
) > 1 and FieldList
[1]:
1465 DataType
= FieldList
[1]
1466 if FieldList
[1] != TAB_VOID
:
1468 if len(FieldList
) > 2:
1472 IsValid
= (len(FieldList
) <= 1)
1474 IsValid
= (len(FieldList
) <= 3)
1478 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1482 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1483 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1484 Value
= FieldList
[0]
1486 IsValid
= (len(FieldList
) <= 1)
1487 return [Value
, DataType
, str(Size
)], IsValid
, 0
1488 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1489 VpdOffset
= FieldList
[0]
1491 if not DataType
== TAB_VOID
:
1492 if len(FieldList
) > 1:
1493 Value
= FieldList
[1]
1495 if len(FieldList
) > 1:
1497 if len(FieldList
) > 2:
1498 Value
= FieldList
[2]
1500 IsValid
= (len(FieldList
) <= 1)
1502 IsValid
= (len(FieldList
) <= 3)
1505 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1509 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1510 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1511 IsValid
= (3 <= len(FieldList
) <= 5)
1512 HiiString
= FieldList
[0]
1513 Guid
= Offset
= Value
= Attribute
= ''
1514 if len(FieldList
) > 1:
1516 if len(FieldList
) > 2:
1517 Offset
= FieldList
[2]
1518 if len(FieldList
) > 3:
1519 Value
= FieldList
[3]
1522 if len(FieldList
) > 4:
1523 Attribute
= FieldList
[4]
1524 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1529 # Analyze the pcd Value, Datum type and TokenNumber.
1530 # Used to avoid split issue while the value string contain "|" character
1532 # @param[in] Setting: A String contain value/datum type/token number information;
1534 # @retval ValueList: A List contain value, datum type and toke number.
1536 def AnalyzePcdData(Setting
):
1537 ValueList
= ['', '', '']
1539 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1540 PtrValue
= ValueRe
.findall(Setting
)
1542 ValueUpdateFlag
= False
1544 if len(PtrValue
) >= 1:
1545 Setting
= re
.sub(ValueRe
, '', Setting
)
1546 ValueUpdateFlag
= True
1548 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1549 ValueList
[0:len(TokenList
)] = TokenList
1552 ValueList
[0] = PtrValue
[0]
1556 ## check format of PCD value against its the datum type
1558 # For PCD value setting
1560 def CheckPcdDatum(Type
, Value
):
1561 if Type
== TAB_VOID
:
1562 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1563 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1564 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1566 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1567 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1568 elif ValueRe
.match(Value
):
1569 # Check the chars in UnicodeString or CString is printable
1570 if Value
.startswith("L"):
1574 Printset
= set(string
.printable
)
1575 Printset
.remove(TAB_PRINTCHAR_VT
)
1576 Printset
.add(TAB_PRINTCHAR_BS
)
1577 Printset
.add(TAB_PRINTCHAR_NUL
)
1578 if not set(Value
).issubset(Printset
):
1579 PrintList
= sorted(Printset
)
1580 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1581 elif Type
== 'BOOLEAN':
1582 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1583 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1584 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1585 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1587 Value
= long(Value
, 0)
1589 return False, "Invalid value [%s] of type [%s];"\
1590 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1592 return True, "StructurePcd"
1596 ## Split command line option string to list
1598 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1599 # in non-windows platform to launch command
1601 def SplitOption(OptionString
):
1606 for Index
in range(0, len(OptionString
)):
1607 CurrentChar
= OptionString
[Index
]
1608 if CurrentChar
in ['"', "'"]:
1609 if QuotationMark
== CurrentChar
:
1611 elif QuotationMark
== "":
1612 QuotationMark
= CurrentChar
1617 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1618 if Index
> OptionStart
:
1619 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1621 LastChar
= CurrentChar
1622 OptionList
.append(OptionString
[OptionStart
:])
1625 def CommonPath(PathList
):
1626 P1
= min(PathList
).split(os
.path
.sep
)
1627 P2
= max(PathList
).split(os
.path
.sep
)
1628 for Index
in xrange(min(len(P1
), len(P2
))):
1629 if P1
[Index
] != P2
[Index
]:
1630 return os
.path
.sep
.join(P1
[:Index
])
1631 return os
.path
.sep
.join(P1
)
1634 # Convert string to C format array
1636 def ConvertStringToByteArray(Value
):
1637 Value
= Value
.strip()
1641 if not Value
.endswith('}'):
1643 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1644 ValFields
= Value
.split(',')
1646 for Index
in range(len(ValFields
)):
1647 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1650 Value
= '{' + ','.join(ValFields
) + '}'
1654 if Value
.startswith('L"'):
1655 if not Value
.endswith('"'):
1659 elif not Value
.startswith('"') or not Value
.endswith('"'):
1662 Value
= eval(Value
) # translate escape character
1664 for Index
in range(0, len(Value
)):
1666 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1668 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1669 Value
= NewValue
+ '0}'
1672 class PathClass(object):
1673 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1674 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1676 self
.File
= str(File
)
1677 if os
.path
.isabs(self
.File
):
1681 self
.Root
= str(Root
)
1682 self
.AlterRoot
= str(AlterRoot
)
1684 # Remove any '.' and '..' in path
1686 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1687 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1688 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1689 # eliminate the side-effect of 'C:'
1690 if self
.Root
[-1] == ':':
1691 self
.Root
+= os
.path
.sep
1692 # file path should not start with path separator
1693 if self
.Root
[-1] == os
.path
.sep
:
1694 self
.File
= self
.Path
[len(self
.Root
):]
1696 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1698 self
.Path
= os
.path
.normpath(self
.File
)
1700 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1701 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1705 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1707 self
.Dir
= self
.Root
1709 self
.Dir
= self
.SubDir
1714 self
.Type
= self
.Ext
.lower()
1716 self
.IsBinary
= IsBinary
1717 self
.Target
= Target
1718 self
.TagName
= TagName
1719 self
.ToolCode
= ToolCode
1720 self
.ToolChainFamily
= ToolChainFamily
1724 ## Convert the object of this class to a string
1726 # Convert member Path of the class to a string
1728 # @retval string Formatted String
1733 ## Override __eq__ function
1735 # Check whether PathClass are the same
1737 # @retval False The two PathClass are different
1738 # @retval True The two PathClass are the same
1740 def __eq__(self
, Other
):
1741 if isinstance(Other
, type(self
)):
1742 return self
.Path
== Other
.Path
1744 return self
.Path
== str(Other
)
1746 ## Override __cmp__ function
1748 # Customize the comparsion operation of two PathClass
1750 # @retval 0 The two PathClass are different
1751 # @retval -1 The first PathClass is less than the second PathClass
1752 # @retval 1 The first PathClass is Bigger than the second PathClass
1753 def __cmp__(self
, Other
):
1754 if isinstance(Other
, type(self
)):
1755 OtherKey
= Other
.Path
1757 OtherKey
= str(Other
)
1760 if SelfKey
== OtherKey
:
1762 elif SelfKey
> OtherKey
:
1767 ## Override __hash__ function
1769 # Use Path as key in hash table
1771 # @retval string Key for hash table
1774 return hash(self
.Path
)
1776 def _GetFileKey(self
):
1777 if self
._Key
is None:
1778 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1781 def _GetTimeStamp(self
):
1782 return os
.stat(self
.Path
)[8]
1784 def Validate(self
, Type
='', CaseSensitive
=True):
1785 if GlobalData
.gCaseInsensitive
:
1786 CaseSensitive
= False
1787 if Type
and Type
.lower() != self
.Type
:
1788 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1790 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1791 if not RealRoot
and not RealFile
:
1792 RealFile
= self
.File
1794 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1796 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1797 if len (mws
.getPkgPath()) == 0:
1798 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1800 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1804 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1805 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1806 ErrorCode
= FILE_CASE_MISMATCH
1807 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1809 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1810 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1812 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1815 self
.File
= RealFile
1816 self
.Root
= RealRoot
1817 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1818 return ErrorCode
, ErrorInfo
1820 Key
= property(_GetFileKey
)
1821 TimeStamp
= property(_GetTimeStamp
)
1823 ## Parse PE image to get the required PE informaion.
1825 class PeImageClass():
1828 # @param File FilePath of PeImage
1830 def __init__(self
, PeFile
):
1831 self
.FileName
= PeFile
1832 self
.IsValid
= False
1835 self
.SectionAlignment
= 0
1836 self
.SectionHeaderList
= []
1839 PeObject
= open(PeFile
, 'rb')
1841 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1844 ByteArray
= array
.array('B')
1845 ByteArray
.fromfile(PeObject
, 0x3E)
1846 ByteList
= ByteArray
.tolist()
1847 # DOS signature should be 'MZ'
1848 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1849 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1852 # Read 4 byte PE Signature
1853 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1854 PeObject
.seek(PeOffset
)
1855 ByteArray
= array
.array('B')
1856 ByteArray
.fromfile(PeObject
, 4)
1857 # PE signature should be 'PE\0\0'
1858 if ByteArray
.tostring() != 'PE\0\0':
1859 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1862 # Read PE file header
1863 ByteArray
= array
.array('B')
1864 ByteArray
.fromfile(PeObject
, 0x14)
1865 ByteList
= ByteArray
.tolist()
1866 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1868 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1871 # Read PE optional header
1872 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1873 ByteArray
= array
.array('B')
1874 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1875 ByteList
= ByteArray
.tolist()
1876 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1877 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1878 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1880 # Read each Section Header
1881 for Index
in range(SecNumber
):
1882 ByteArray
= array
.array('B')
1883 ByteArray
.fromfile(PeObject
, 0x28)
1884 ByteList
= ByteArray
.tolist()
1885 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1886 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1887 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1888 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1889 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1893 def _ByteListToStr(self
, ByteList
):
1895 for index
in range(len(ByteList
)):
1896 if ByteList
[index
] == 0:
1898 String
+= chr(ByteList
[index
])
1901 def _ByteListToInt(self
, ByteList
):
1903 for index
in range(len(ByteList
) - 1, -1, -1):
1904 Value
= (Value
<< 8) |
int(ByteList
[index
])
1907 class DefaultStore():
1908 def __init__(self
, DefaultStores
):
1910 self
.DefaultStores
= DefaultStores
1911 def DefaultStoreID(self
, DefaultStoreName
):
1912 for key
, value
in self
.DefaultStores
.items():
1913 if value
== DefaultStoreName
:
1916 def GetDefaultDefault(self
):
1917 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1918 return "0", TAB_DEFAULT_STORES_DEFAULT
1920 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1921 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1922 def GetMin(self
, DefaultSIdList
):
1923 if not DefaultSIdList
:
1924 return TAB_DEFAULT_STORES_DEFAULT
1925 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1928 minid
= min(storeidset
)
1929 for sid
, name
in self
.DefaultStores
.values():
1938 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1942 for SkuName
in SkuIds
:
1943 SkuId
= SkuIds
[SkuName
][0]
1944 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1945 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1946 EdkLogger
.error("build", PARAMETER_INVALID
,
1947 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1950 self
.AvailableSkuIds
= sdict()
1952 self
.SkuIdNumberSet
= []
1953 self
.SkuData
= SkuIds
1954 self
.__SkuInherit
= {}
1955 self
.__SkuIdentifier
= SkuIdentifier
1956 if SkuIdentifier
== '' or SkuIdentifier
is None:
1957 self
.SkuIdSet
= ['DEFAULT']
1958 self
.SkuIdNumberSet
= ['0U']
1959 elif SkuIdentifier
== 'ALL':
1960 self
.SkuIdSet
= SkuIds
.keys()
1961 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1963 r
= SkuIdentifier
.split('|')
1964 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1967 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1969 EdkLogger
.error("build", PARAMETER_INVALID
,
1970 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1971 % (k
, " | ".join(SkuIds
.keys())))
1972 for each
in self
.SkuIdSet
:
1974 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1976 EdkLogger
.error("build", PARAMETER_INVALID
,
1977 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1978 % (each
, " | ".join(SkuIds
.keys())))
1979 if self
.SkuUsageType
!= self
.SINGLE
:
1980 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1982 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1983 if 'COMMON' in GlobalData
.gSkuids
:
1984 GlobalData
.gSkuids
.remove('COMMON')
1985 if self
.SkuUsageType
== self
.SINGLE
:
1986 if len(GlobalData
.gSkuids
) != 1:
1987 if 'DEFAULT' in GlobalData
.gSkuids
:
1988 GlobalData
.gSkuids
.remove('DEFAULT')
1989 if GlobalData
.gSkuids
:
1990 GlobalData
.gSkuids
.sort()
1992 def GetNextSkuId(self
, skuname
):
1993 if not self
.__SkuInherit
:
1994 self
.__SkuInherit
= {}
1995 for item
in self
.SkuData
.values():
1996 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1997 return self
.__SkuInherit
.get(skuname
, "DEFAULT")
1999 def GetSkuChain(self
, sku
):
2000 if sku
== "DEFAULT":
2005 nextsku
= self
.GetNextSkuId(nextsku
)
2006 skulist
.append(nextsku
)
2007 if nextsku
== "DEFAULT":
2011 def SkuOverrideOrder(self
):
2013 for skuname
in self
.SkuIdSet
:
2014 skuorderset
.append(self
.GetSkuChain(skuname
))
2017 for index
in range(max(len(item
) for item
in skuorderset
)):
2018 for subset
in skuorderset
:
2019 if index
> len(subset
)-1:
2021 if subset
[index
] in skuorder
:
2023 skuorder
.append(subset
[index
])
2027 def __SkuUsageType(self
):
2029 if self
.__SkuIdentifier
.upper() == "ALL":
2030 return SkuClass
.MULTIPLE
2032 if len(self
.SkuIdSet
) == 1:
2033 if self
.SkuIdSet
[0] == 'DEFAULT':
2034 return SkuClass
.DEFAULT
2036 return SkuClass
.SINGLE
2037 elif len(self
.SkuIdSet
) == 2:
2038 if 'DEFAULT' in self
.SkuIdSet
:
2039 return SkuClass
.SINGLE
2041 return SkuClass
.MULTIPLE
2043 return SkuClass
.MULTIPLE
2044 def DumpSkuIdArrary(self
):
2047 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2050 for skuname
in self
.AvailableSkuIds
:
2051 if skuname
== "COMMON":
2053 while skuname
!= "DEFAULT":
2054 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2055 skuname
= self
.GetNextSkuId(skuname
)
2056 ArrayStrList
.append("0x0")
2057 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2059 def __GetAvailableSkuIds(self
):
2060 return self
.AvailableSkuIds
2062 def __GetSystemSkuID(self
):
2063 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2064 if len(self
.SkuIdSet
) == 1:
2065 return self
.SkuIdSet
[0]
2067 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2070 def __GetAvailableSkuIdNumber(self
):
2071 return self
.SkuIdNumberSet
2072 SystemSkuId
= property(__GetSystemSkuID
)
2073 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2074 SkuUsageType
= property(__SkuUsageType
)
2075 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2078 # Pack a registry format GUID
2080 def PackRegistryFormatGuid(Guid
):
2081 return PackGUID(Guid
.split('-'))
2083 ## Get the integer value from string like "14U" or integer like 2
2085 # @param Input The object that may be either a integer value or a string
2087 # @retval Value The integer value that the input represents
2089 def GetIntegerValue(Input
):
2090 if type(Input
) in (int, long):
2093 if String
.endswith("U"):
2094 String
= String
[:-1]
2095 if String
.endswith("ULL"):
2096 String
= String
[:-3]
2097 if String
.endswith("LL"):
2098 String
= String
[:-2]
2100 if String
.startswith("0x") or String
.startswith("0X"):
2101 return int(String
, 16)
2108 # Pack a GUID (registry format) list into a buffer and return it
2111 return pack(PACK_PATTERN_GUID
,
2115 int(Guid
[3][-4:-2], 16),
2116 int(Guid
[3][-2:], 16),
2117 int(Guid
[4][-12:-10], 16),
2118 int(Guid
[4][-10:-8], 16),
2119 int(Guid
[4][-8:-6], 16),
2120 int(Guid
[4][-6:-4], 16),
2121 int(Guid
[4][-4:-2], 16),
2122 int(Guid
[4][-2:], 16)
2126 # Pack a GUID (byte) list into a buffer and return it
2128 def PackByteFormatGUID(Guid
):
2129 return pack(PACK_PATTERN_GUID
,
2145 # This acts like the main() function for the script, unless it is 'import'ed into another
2148 if __name__
== '__main__':