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'):
1418 Value
= int(Value
, 16)
1420 raise BadExpression("invalid hex value: %s" % Value
)
1423 return Value
, (Value
.bit_length() + 7) / 8
1424 if Value
[0].isdigit():
1425 Value
= int(Value
, 10)
1428 return Value
, (Value
.bit_length() + 7) / 8
1429 if Value
.lower() == 'true':
1431 if Value
.lower() == 'false':
1437 # Analyze DSC PCD value, since there is no data type info in DSC
1438 # This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1439 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1440 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1441 # 3. Dynamic default:
1442 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1443 # TokenSpace.PcdCName|PcdValue
1445 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1446 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1448 # TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
1449 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1450 # there might have "|" operator, also in string value.
1452 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1453 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1454 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1456 # ValueList: A List contain fields described above
1457 # IsValid: True if conforming EBNF, otherwise False
1458 # Index: The index where PcdValue is in ValueList
1460 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1461 FieldList
= AnalyzePcdExpression(Setting
)
1464 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1465 Value
= FieldList
[0]
1467 if len(FieldList
) > 1 and FieldList
[1]:
1468 DataType
= FieldList
[1]
1469 if FieldList
[1] != TAB_VOID
:
1471 if len(FieldList
) > 2:
1475 IsValid
= (len(FieldList
) <= 1)
1477 IsValid
= (len(FieldList
) <= 3)
1481 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1485 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1486 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1487 Value
= FieldList
[0]
1489 IsValid
= (len(FieldList
) <= 1)
1490 return [Value
, DataType
, str(Size
)], IsValid
, 0
1491 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1492 VpdOffset
= FieldList
[0]
1494 if not DataType
== TAB_VOID
:
1495 if len(FieldList
) > 1:
1496 Value
= FieldList
[1]
1498 if len(FieldList
) > 1:
1500 if len(FieldList
) > 2:
1501 Value
= FieldList
[2]
1503 IsValid
= (len(FieldList
) <= 1)
1505 IsValid
= (len(FieldList
) <= 3)
1508 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1512 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1513 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1514 IsValid
= (3 <= len(FieldList
) <= 5)
1515 HiiString
= FieldList
[0]
1516 Guid
= Offset
= Value
= Attribute
= ''
1517 if len(FieldList
) > 1:
1519 if len(FieldList
) > 2:
1520 Offset
= FieldList
[2]
1521 if len(FieldList
) > 3:
1522 Value
= FieldList
[3]
1525 if len(FieldList
) > 4:
1526 Attribute
= FieldList
[4]
1527 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1532 # Analyze the pcd Value, Datum type and TokenNumber.
1533 # Used to avoid split issue while the value string contain "|" character
1535 # @param[in] Setting: A String contain value/datum type/token number information;
1537 # @retval ValueList: A List contain value, datum type and toke number.
1539 def AnalyzePcdData(Setting
):
1540 ValueList
= ['', '', '']
1542 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1543 PtrValue
= ValueRe
.findall(Setting
)
1545 ValueUpdateFlag
= False
1547 if len(PtrValue
) >= 1:
1548 Setting
= re
.sub(ValueRe
, '', Setting
)
1549 ValueUpdateFlag
= True
1551 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1552 ValueList
[0:len(TokenList
)] = TokenList
1555 ValueList
[0] = PtrValue
[0]
1559 ## check format of PCD value against its the datum type
1561 # For PCD value setting
1563 def CheckPcdDatum(Type
, Value
):
1564 if Type
== TAB_VOID
:
1565 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1566 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1567 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1569 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1570 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1571 elif ValueRe
.match(Value
):
1572 # Check the chars in UnicodeString or CString is printable
1573 if Value
.startswith("L"):
1577 Printset
= set(string
.printable
)
1578 Printset
.remove(TAB_PRINTCHAR_VT
)
1579 Printset
.add(TAB_PRINTCHAR_BS
)
1580 Printset
.add(TAB_PRINTCHAR_NUL
)
1581 if not set(Value
).issubset(Printset
):
1582 PrintList
= sorted(Printset
)
1583 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1584 elif Type
== 'BOOLEAN':
1585 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1586 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1587 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1588 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1590 Value
= long(Value
, 0)
1592 return False, "Invalid value [%s] of type [%s];"\
1593 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1595 return True, "StructurePcd"
1599 ## Split command line option string to list
1601 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1602 # in non-windows platform to launch command
1604 def SplitOption(OptionString
):
1609 for Index
in range(0, len(OptionString
)):
1610 CurrentChar
= OptionString
[Index
]
1611 if CurrentChar
in ['"', "'"]:
1612 if QuotationMark
== CurrentChar
:
1614 elif QuotationMark
== "":
1615 QuotationMark
= CurrentChar
1620 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1621 if Index
> OptionStart
:
1622 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1624 LastChar
= CurrentChar
1625 OptionList
.append(OptionString
[OptionStart
:])
1628 def CommonPath(PathList
):
1629 P1
= min(PathList
).split(os
.path
.sep
)
1630 P2
= max(PathList
).split(os
.path
.sep
)
1631 for Index
in xrange(min(len(P1
), len(P2
))):
1632 if P1
[Index
] != P2
[Index
]:
1633 return os
.path
.sep
.join(P1
[:Index
])
1634 return os
.path
.sep
.join(P1
)
1637 # Convert string to C format array
1639 def ConvertStringToByteArray(Value
):
1640 Value
= Value
.strip()
1644 if not Value
.endswith('}'):
1646 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1647 ValFields
= Value
.split(',')
1649 for Index
in range(len(ValFields
)):
1650 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1653 Value
= '{' + ','.join(ValFields
) + '}'
1657 if Value
.startswith('L"'):
1658 if not Value
.endswith('"'):
1662 elif not Value
.startswith('"') or not Value
.endswith('"'):
1665 Value
= eval(Value
) # translate escape character
1667 for Index
in range(0, len(Value
)):
1669 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1671 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1672 Value
= NewValue
+ '0}'
1675 class PathClass(object):
1676 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1677 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1679 self
.File
= str(File
)
1680 if os
.path
.isabs(self
.File
):
1684 self
.Root
= str(Root
)
1685 self
.AlterRoot
= str(AlterRoot
)
1687 # Remove any '.' and '..' in path
1689 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1690 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1691 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1692 # eliminate the side-effect of 'C:'
1693 if self
.Root
[-1] == ':':
1694 self
.Root
+= os
.path
.sep
1695 # file path should not start with path separator
1696 if self
.Root
[-1] == os
.path
.sep
:
1697 self
.File
= self
.Path
[len(self
.Root
):]
1699 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1701 self
.Path
= os
.path
.normpath(self
.File
)
1703 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1704 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1708 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1710 self
.Dir
= self
.Root
1712 self
.Dir
= self
.SubDir
1717 self
.Type
= self
.Ext
.lower()
1719 self
.IsBinary
= IsBinary
1720 self
.Target
= Target
1721 self
.TagName
= TagName
1722 self
.ToolCode
= ToolCode
1723 self
.ToolChainFamily
= ToolChainFamily
1727 ## Convert the object of this class to a string
1729 # Convert member Path of the class to a string
1731 # @retval string Formatted String
1736 ## Override __eq__ function
1738 # Check whether PathClass are the same
1740 # @retval False The two PathClass are different
1741 # @retval True The two PathClass are the same
1743 def __eq__(self
, Other
):
1744 if isinstance(Other
, type(self
)):
1745 return self
.Path
== Other
.Path
1747 return self
.Path
== str(Other
)
1749 ## Override __cmp__ function
1751 # Customize the comparsion operation of two PathClass
1753 # @retval 0 The two PathClass are different
1754 # @retval -1 The first PathClass is less than the second PathClass
1755 # @retval 1 The first PathClass is Bigger than the second PathClass
1756 def __cmp__(self
, Other
):
1757 if isinstance(Other
, type(self
)):
1758 OtherKey
= Other
.Path
1760 OtherKey
= str(Other
)
1763 if SelfKey
== OtherKey
:
1765 elif SelfKey
> OtherKey
:
1770 ## Override __hash__ function
1772 # Use Path as key in hash table
1774 # @retval string Key for hash table
1777 return hash(self
.Path
)
1779 def _GetFileKey(self
):
1780 if self
._Key
is None:
1781 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1784 def _GetTimeStamp(self
):
1785 return os
.stat(self
.Path
)[8]
1787 def Validate(self
, Type
='', CaseSensitive
=True):
1788 if GlobalData
.gCaseInsensitive
:
1789 CaseSensitive
= False
1790 if Type
and Type
.lower() != self
.Type
:
1791 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1793 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1794 if not RealRoot
and not RealFile
:
1795 RealFile
= self
.File
1797 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1799 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1800 if len (mws
.getPkgPath()) == 0:
1801 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1803 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1807 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1808 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1809 ErrorCode
= FILE_CASE_MISMATCH
1810 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1812 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1813 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1815 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1818 self
.File
= RealFile
1819 self
.Root
= RealRoot
1820 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1821 return ErrorCode
, ErrorInfo
1823 Key
= property(_GetFileKey
)
1824 TimeStamp
= property(_GetTimeStamp
)
1826 ## Parse PE image to get the required PE informaion.
1828 class PeImageClass():
1831 # @param File FilePath of PeImage
1833 def __init__(self
, PeFile
):
1834 self
.FileName
= PeFile
1835 self
.IsValid
= False
1838 self
.SectionAlignment
= 0
1839 self
.SectionHeaderList
= []
1842 PeObject
= open(PeFile
, 'rb')
1844 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1847 ByteArray
= array
.array('B')
1848 ByteArray
.fromfile(PeObject
, 0x3E)
1849 ByteList
= ByteArray
.tolist()
1850 # DOS signature should be 'MZ'
1851 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1852 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1855 # Read 4 byte PE Signature
1856 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1857 PeObject
.seek(PeOffset
)
1858 ByteArray
= array
.array('B')
1859 ByteArray
.fromfile(PeObject
, 4)
1860 # PE signature should be 'PE\0\0'
1861 if ByteArray
.tostring() != 'PE\0\0':
1862 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1865 # Read PE file header
1866 ByteArray
= array
.array('B')
1867 ByteArray
.fromfile(PeObject
, 0x14)
1868 ByteList
= ByteArray
.tolist()
1869 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1871 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1874 # Read PE optional header
1875 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1876 ByteArray
= array
.array('B')
1877 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1878 ByteList
= ByteArray
.tolist()
1879 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1880 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1881 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1883 # Read each Section Header
1884 for Index
in range(SecNumber
):
1885 ByteArray
= array
.array('B')
1886 ByteArray
.fromfile(PeObject
, 0x28)
1887 ByteList
= ByteArray
.tolist()
1888 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1889 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1890 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1891 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1892 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1896 def _ByteListToStr(self
, ByteList
):
1898 for index
in range(len(ByteList
)):
1899 if ByteList
[index
] == 0:
1901 String
+= chr(ByteList
[index
])
1904 def _ByteListToInt(self
, ByteList
):
1906 for index
in range(len(ByteList
) - 1, -1, -1):
1907 Value
= (Value
<< 8) |
int(ByteList
[index
])
1910 class DefaultStore():
1911 def __init__(self
, DefaultStores
):
1913 self
.DefaultStores
= DefaultStores
1914 def DefaultStoreID(self
, DefaultStoreName
):
1915 for key
, value
in self
.DefaultStores
.items():
1916 if value
== DefaultStoreName
:
1919 def GetDefaultDefault(self
):
1920 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1921 return "0", TAB_DEFAULT_STORES_DEFAULT
1923 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1924 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1925 def GetMin(self
, DefaultSIdList
):
1926 if not DefaultSIdList
:
1927 return TAB_DEFAULT_STORES_DEFAULT
1928 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1931 minid
= min(storeidset
)
1932 for sid
, name
in self
.DefaultStores
.values():
1941 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1945 for SkuName
in SkuIds
:
1946 SkuId
= SkuIds
[SkuName
][0]
1947 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1948 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1949 EdkLogger
.error("build", PARAMETER_INVALID
,
1950 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1953 self
.AvailableSkuIds
= sdict()
1955 self
.SkuIdNumberSet
= []
1956 self
.SkuData
= SkuIds
1957 self
.__SkuInherit
= {}
1958 self
.__SkuIdentifier
= SkuIdentifier
1959 if SkuIdentifier
== '' or SkuIdentifier
is None:
1960 self
.SkuIdSet
= ['DEFAULT']
1961 self
.SkuIdNumberSet
= ['0U']
1962 elif SkuIdentifier
== 'ALL':
1963 self
.SkuIdSet
= SkuIds
.keys()
1964 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1966 r
= SkuIdentifier
.split('|')
1967 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1970 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1972 EdkLogger
.error("build", PARAMETER_INVALID
,
1973 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1974 % (k
, " | ".join(SkuIds
.keys())))
1975 for each
in self
.SkuIdSet
:
1977 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1979 EdkLogger
.error("build", PARAMETER_INVALID
,
1980 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1981 % (each
, " | ".join(SkuIds
.keys())))
1982 if self
.SkuUsageType
!= self
.SINGLE
:
1983 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1985 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1986 if 'COMMON' in GlobalData
.gSkuids
:
1987 GlobalData
.gSkuids
.remove('COMMON')
1988 if self
.SkuUsageType
== self
.SINGLE
:
1989 if len(GlobalData
.gSkuids
) != 1:
1990 if 'DEFAULT' in GlobalData
.gSkuids
:
1991 GlobalData
.gSkuids
.remove('DEFAULT')
1992 if GlobalData
.gSkuids
:
1993 GlobalData
.gSkuids
.sort()
1995 def GetNextSkuId(self
, skuname
):
1996 if not self
.__SkuInherit
:
1997 self
.__SkuInherit
= {}
1998 for item
in self
.SkuData
.values():
1999 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
2000 return self
.__SkuInherit
.get(skuname
, "DEFAULT")
2002 def GetSkuChain(self
, sku
):
2003 if sku
== "DEFAULT":
2008 nextsku
= self
.GetNextSkuId(nextsku
)
2009 skulist
.append(nextsku
)
2010 if nextsku
== "DEFAULT":
2014 def SkuOverrideOrder(self
):
2016 for skuname
in self
.SkuIdSet
:
2017 skuorderset
.append(self
.GetSkuChain(skuname
))
2020 for index
in range(max(len(item
) for item
in skuorderset
)):
2021 for subset
in skuorderset
:
2022 if index
> len(subset
)-1:
2024 if subset
[index
] in skuorder
:
2026 skuorder
.append(subset
[index
])
2030 def __SkuUsageType(self
):
2032 if self
.__SkuIdentifier
.upper() == "ALL":
2033 return SkuClass
.MULTIPLE
2035 if len(self
.SkuIdSet
) == 1:
2036 if self
.SkuIdSet
[0] == 'DEFAULT':
2037 return SkuClass
.DEFAULT
2039 return SkuClass
.SINGLE
2040 elif len(self
.SkuIdSet
) == 2:
2041 if 'DEFAULT' in self
.SkuIdSet
:
2042 return SkuClass
.SINGLE
2044 return SkuClass
.MULTIPLE
2046 return SkuClass
.MULTIPLE
2047 def DumpSkuIdArrary(self
):
2050 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2053 for skuname
in self
.AvailableSkuIds
:
2054 if skuname
== "COMMON":
2056 while skuname
!= "DEFAULT":
2057 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2058 skuname
= self
.GetNextSkuId(skuname
)
2059 ArrayStrList
.append("0x0")
2060 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2062 def __GetAvailableSkuIds(self
):
2063 return self
.AvailableSkuIds
2065 def __GetSystemSkuID(self
):
2066 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2067 if len(self
.SkuIdSet
) == 1:
2068 return self
.SkuIdSet
[0]
2070 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2073 def __GetAvailableSkuIdNumber(self
):
2074 return self
.SkuIdNumberSet
2075 SystemSkuId
= property(__GetSystemSkuID
)
2076 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2077 SkuUsageType
= property(__SkuUsageType
)
2078 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2081 # Pack a registry format GUID
2083 def PackRegistryFormatGuid(Guid
):
2084 return PackGUID(Guid
.split('-'))
2086 ## Get the integer value from string like "14U" or integer like 2
2088 # @param Input The object that may be either a integer value or a string
2090 # @retval Value The integer value that the input represents
2092 def GetIntegerValue(Input
):
2093 if type(Input
) in (int, long):
2096 if String
.endswith("U"):
2097 String
= String
[:-1]
2098 if String
.endswith("ULL"):
2099 String
= String
[:-3]
2100 if String
.endswith("LL"):
2101 String
= String
[:-2]
2103 if String
.startswith("0x") or String
.startswith("0X"):
2104 return int(String
, 16)
2111 # Pack a GUID (registry format) list into a buffer and return it
2114 return pack(PACK_PATTERN_GUID
,
2118 int(Guid
[3][-4:-2], 16),
2119 int(Guid
[3][-2:], 16),
2120 int(Guid
[4][-12:-10], 16),
2121 int(Guid
[4][-10:-8], 16),
2122 int(Guid
[4][-8:-6], 16),
2123 int(Guid
[4][-6:-4], 16),
2124 int(Guid
[4][-4:-2], 16),
2125 int(Guid
[4][-2:], 16)
2129 # Pack a GUID (byte) list into a buffer and return it
2131 def PackByteFormatGUID(Guid
):
2132 return pack(PACK_PATTERN_GUID
,
2148 # This acts like the main() function for the script, unless it is 'import'ed into another
2151 if __name__
== '__main__':