2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import Common
.LongFilePathOs
as os
27 from struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 from CommonDataClass
.Exceptions
import BadExpression
42 ## Regular expression used to find out place holders in string template
43 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
45 ## Dictionary used to store file time stamp for quick re-access
46 gFileTimeStampCache
= {} # {file path : file time stamp}
48 ## Dictionary used to store dependencies of files
49 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
51 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
52 """ Parse map file to get variable offset in current EFI file
53 @param mapfilepath Map file absolution path
54 @param efifilepath: EFI binary file full path
55 @param varnames iteratable container whose elements are variable names to be searched
57 @return List whos elements are tuple with variable name and raw offset
61 f
= open(mapfilepath
, 'r')
67 if len(lines
) == 0: return None
68 firstline
= lines
[0].strip()
69 if (firstline
.startswith("Archive member included ") and
70 firstline
.endswith(" file (symbol)")):
71 return _parseForGCC(lines
, efifilepath
, varnames
)
72 if firstline
.startswith("# Path:"):
73 return _parseForXcode(lines
, efifilepath
, varnames
)
74 return _parseGeneral(lines
, efifilepath
, varnames
)
76 def _parseForXcode(lines
, efifilepath
, varnames
):
81 if status
== 0 and line
== "# Symbols:":
84 if status
== 1 and len(line
) != 0:
85 for varname
in varnames
:
87 # cannot pregenerate this RegEx since it uses varname from varnames.
88 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
90 ret
.append((varname
, m
.group(1)))
93 def _parseForGCC(lines
, efifilepath
, varnames
):
94 """ Parse map file generated by GCC linker """
95 valuePattern
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
96 pcdPattern
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
100 for index
, line
in enumerate(lines
):
102 # status machine transection
103 if status
== 0 and line
== "Memory Configuration":
106 elif status
== 1 and line
== 'Linker script and memory map':
109 elif status
==2 and line
== 'START GROUP':
115 m
= valuePattern
.match(line
)
117 sections
.append(m
.groups(0))
118 for varname
in varnames
:
120 m
= re
.match("^.data.(%s)" % varname
, line
)
122 m
= re
.match(".data.(%s)$" % varname
, line
)
124 Str
= lines
[index
+ 1]
126 Str
= line
[len(".data.%s" % varname
):]
128 m
= pcdPattern
.match(Str
.strip())
130 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
134 # get section information from efi file
135 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
136 if efisecs
is None or len(efisecs
) == 0:
140 for efisec
in efisecs
:
141 for section
in sections
:
142 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
143 redirection
= int(section
[1], 16) - efisec
[1]
146 for var
in varoffset
:
147 for efisec
in efisecs
:
148 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
149 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
152 def _parseGeneral(lines
, efifilepath
, varnames
):
153 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
154 secs
= [] # key = section name
156 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
157 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
158 startRe
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
159 addressRe
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
163 if startRe
.match(line
):
166 if addressRe
.match(line
):
169 if line
.startswith("entry point at"):
172 if status
== 1 and len(line
) != 0:
173 m
= secRe
.match(line
)
174 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
175 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
176 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
177 if status
== 2 and len(line
) != 0:
178 for varname
in varnames
:
179 m
= symRe
.match(line
)
180 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
181 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
182 sec_no
= int(sec_no
, 16)
183 sym_offset
= int(sym_offset
, 16)
184 vir_addr
= int(vir_addr
, 16)
185 # cannot pregenerate this RegEx since it uses varname from varnames.
186 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
188 # fond a binary pcd entry in map file
190 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
191 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
193 if not varoffset
: return []
195 # get section information from efi file
196 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
197 if efisecs
is None or len(efisecs
) == 0:
201 for var
in varoffset
:
203 for efisec
in efisecs
:
205 if var
[1].strip() == efisec
[0].strip():
206 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
207 elif var
[4] == index
:
208 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
212 ## Routine to process duplicated INF
214 # This function is called by following two cases:
217 # Pkg/module/module.inf
218 # Pkg/module/module.inf {
220 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
223 # INF Pkg/module/module.inf
224 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
226 # This function copies Pkg/module/module.inf to
227 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
229 # @param Path Original PathClass object
230 # @param BaseName New file base name
232 # @retval return the new PathClass object
234 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
235 Filename
= os
.path
.split(Path
.File
)[1]
237 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
239 Filename
= BaseName
+ Path
.BaseName
242 # If -N is specified on command line, cache is disabled
243 # The directory has to be created
245 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
246 if not os
.path
.exists(DbDir
):
249 # A temporary INF is copied to database path which must have write permission
250 # The temporary will be removed at the end of build
251 # In case of name conflict, the file name is
252 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
254 TempFullPath
= os
.path
.join(DbDir
,
256 RtPath
= PathClass(Path
.File
, Workspace
)
258 # Modify the full path to temporary path, keep other unchanged
260 # To build same module more than once, the module path with FILE_GUID overridden has
261 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
262 # in DSC which is used as relative path by C files and other files in INF.
263 # A trick was used: all module paths are PathClass instances, after the initialization
264 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
266 # The reason for creating a temporary INF is:
267 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
268 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
269 # A different key for the same module is needed to create different output directory,
270 # retrieve overridden PCDs, library instances.
272 # The BaseName is the FILE_GUID which is also the output directory name.
275 RtPath
.Path
= TempFullPath
276 RtPath
.BaseName
= BaseName
278 # If file exists, compare contents
280 if os
.path
.exists(TempFullPath
):
281 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
282 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
285 GlobalData
.gTempInfs
.append(TempFullPath
)
286 shutil
.copy2(str(Path
), TempFullPath
)
289 ## Remove temporary created INFs whose paths were saved in gTempInfs
291 def ClearDuplicatedInf():
292 for File
in GlobalData
.gTempInfs
:
293 if os
.path
.exists(File
):
296 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
298 # @param Guid The GUID string
300 # @retval string The GUID string in C structure style
302 def GuidStringToGuidStructureString(Guid
):
303 GuidList
= Guid
.split('-')
305 for Index
in range(0, 3, 1):
306 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
307 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
308 for Index
in range(0, 12, 2):
309 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
313 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
315 # @param GuidValue The GUID value in byte array
317 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
319 def GuidStructureByteArrayToGuidString(GuidValue
):
320 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
321 guidValueList
= guidValueString
.split(",")
322 if len(guidValueList
) != 16:
324 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
326 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
327 int(guidValueList
[3], 16),
328 int(guidValueList
[2], 16),
329 int(guidValueList
[1], 16),
330 int(guidValueList
[0], 16),
331 int(guidValueList
[5], 16),
332 int(guidValueList
[4], 16),
333 int(guidValueList
[7], 16),
334 int(guidValueList
[6], 16),
335 int(guidValueList
[8], 16),
336 int(guidValueList
[9], 16),
337 int(guidValueList
[10], 16),
338 int(guidValueList
[11], 16),
339 int(guidValueList
[12], 16),
340 int(guidValueList
[13], 16),
341 int(guidValueList
[14], 16),
342 int(guidValueList
[15], 16)
347 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
349 # @param GuidValue The GUID value in C structure format
351 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
353 def GuidStructureStringToGuidString(GuidValue
):
354 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
355 guidValueList
= guidValueString
.split(",")
356 if len(guidValueList
) != 11:
358 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
360 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
361 int(guidValueList
[0], 16),
362 int(guidValueList
[1], 16),
363 int(guidValueList
[2], 16),
364 int(guidValueList
[3], 16),
365 int(guidValueList
[4], 16),
366 int(guidValueList
[5], 16),
367 int(guidValueList
[6], 16),
368 int(guidValueList
[7], 16),
369 int(guidValueList
[8], 16),
370 int(guidValueList
[9], 16),
371 int(guidValueList
[10], 16)
376 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
378 # @param GuidValue The GUID value in C structure format
380 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
382 def GuidStructureStringToGuidValueName(GuidValue
):
383 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
384 guidValueList
= guidValueString
.split(",")
385 if len(guidValueList
) != 11:
386 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
387 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
388 int(guidValueList
[0], 16),
389 int(guidValueList
[1], 16),
390 int(guidValueList
[2], 16),
391 int(guidValueList
[3], 16),
392 int(guidValueList
[4], 16),
393 int(guidValueList
[5], 16),
394 int(guidValueList
[6], 16),
395 int(guidValueList
[7], 16),
396 int(guidValueList
[8], 16),
397 int(guidValueList
[9], 16),
398 int(guidValueList
[10], 16)
401 ## Create directories
403 # @param Directory The directory name
405 def CreateDirectory(Directory
):
406 if Directory
is None or Directory
.strip() == "":
409 if not os
.access(Directory
, os
.F_OK
):
410 os
.makedirs(Directory
)
415 ## Remove directories, including files and sub-directories in it
417 # @param Directory The directory name
419 def RemoveDirectory(Directory
, Recursively
=False):
420 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
423 CurrentDirectory
= os
.getcwd()
425 for File
in os
.listdir("."):
426 if os
.path
.isdir(File
):
427 RemoveDirectory(File
, Recursively
)
430 os
.chdir(CurrentDirectory
)
433 ## Store content in file
435 # This method is used to save file only when its content is changed. This is
436 # quite useful for "make" system to decide what will be re-built and what won't.
438 # @param File The path of file
439 # @param Content The new content of the file
440 # @param IsBinaryFile The flag indicating if the file is binary file or not
442 # @retval True If the file content is changed and the file is renewed
443 # @retval False If the file content is the same
445 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
447 Content
= Content
.replace("\n", os
.linesep
)
449 if os
.path
.exists(File
):
451 if Content
== open(File
, "rb").read():
454 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
456 DirName
= os
.path
.dirname(File
)
457 if not CreateDirectory(DirName
):
458 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
461 DirName
= os
.getcwd()
462 if not os
.access(DirName
, os
.W_OK
):
463 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
466 if GlobalData
.gIsWindows
:
468 from PyUtility
import SaveFileToDisk
469 if not SaveFileToDisk(File
, Content
):
470 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
472 Fd
= open(File
, "wb")
476 Fd
= open(File
, "wb")
480 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
484 ## Make a Python object persistent on file system
486 # @param Data The object to be stored in file
487 # @param File The path of file to store the object
489 def DataDump(Data
, File
):
492 Fd
= open(File
, 'wb')
493 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
495 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
500 ## Restore a Python object from a file
502 # @param File The path of file stored the object
504 # @retval object A python object
505 # @retval None If failure in file operation
507 def DataRestore(File
):
511 Fd
= open(File
, 'rb')
512 Data
= cPickle
.load(Fd
)
514 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
521 ## Retrieve and cache the real path name in file system
523 # @param Root The root directory of path relative to
525 # @retval str The path string if the path exists
526 # @retval None If path doesn't exist
532 def __init__(self
, Root
):
534 for F
in os
.listdir(Root
):
536 self
._UPPER
_CACHE
_[F
.upper()] = F
539 def __getitem__(self
, Path
):
540 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
543 if Path
and Path
[0] == os
.path
.sep
:
545 if Path
in self
._CACHE
_:
546 return os
.path
.join(self
._Root
, Path
)
547 UpperPath
= Path
.upper()
548 if UpperPath
in self
._UPPER
_CACHE
_:
549 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
553 SepIndex
= Path
.find(os
.path
.sep
)
555 Parent
= UpperPath
[:SepIndex
]
556 if Parent
not in self
._UPPER
_CACHE
_:
558 LastSepIndex
= SepIndex
559 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
561 if LastSepIndex
== -1:
566 SepIndex
= LastSepIndex
568 Parent
= Path
[:SepIndex
]
569 ParentKey
= UpperPath
[:SepIndex
]
570 if ParentKey
not in self
._UPPER
_CACHE
_:
574 if Parent
in self
._CACHE
_:
577 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
578 for F
in os
.listdir(ParentDir
):
579 Dir
= os
.path
.join(ParentDir
, F
)
580 self
._CACHE
_.add(Dir
)
581 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
583 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
586 if Path
in self
._CACHE
_:
587 return os
.path
.join(self
._Root
, Path
)
588 elif UpperPath
in self
._UPPER
_CACHE
_:
589 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
592 def RealPath(File
, Dir
='', OverrideDir
=''):
593 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
594 NewFile
= GlobalData
.gAllFiles
[NewFile
]
595 if not NewFile
and OverrideDir
:
596 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
597 NewFile
= GlobalData
.gAllFiles
[NewFile
]
600 def RealPath2(File
, Dir
='', OverrideDir
=''):
603 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
605 if OverrideDir
[-1] == os
.path
.sep
:
606 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
608 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
609 if GlobalData
.gAllFiles
:
610 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
612 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
613 if not os
.path
.exists(NewFile
):
617 if Dir
[-1] == os
.path
.sep
:
618 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
620 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
626 ## Get GUID value from given packages
628 # @param CName The CName of the GUID
629 # @param PackageList List of packages looking-up in
630 # @param Inffile The driver file
632 # @retval GuidValue if the CName is found in any given package
633 # @retval None if the CName is not found in all given packages
635 def GuidValue(CName
, PackageList
, Inffile
= None):
636 for P
in PackageList
:
637 GuidKeys
= P
.Guids
.keys()
638 if Inffile
and P
._PrivateGuids
:
639 if not Inffile
.startswith(P
.MetaFile
.Dir
):
640 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
641 if CName
in GuidKeys
:
642 return P
.Guids
[CName
]
645 ## Get Protocol value from given packages
647 # @param CName The CName of the GUID
648 # @param PackageList List of packages looking-up in
649 # @param Inffile The driver file
651 # @retval GuidValue if the CName is found in any given package
652 # @retval None if the CName is not found in all given packages
654 def ProtocolValue(CName
, PackageList
, Inffile
= None):
655 for P
in PackageList
:
656 ProtocolKeys
= P
.Protocols
.keys()
657 if Inffile
and P
._PrivateProtocols
:
658 if not Inffile
.startswith(P
.MetaFile
.Dir
):
659 ProtocolKeys
= [x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
]
660 if CName
in ProtocolKeys
:
661 return P
.Protocols
[CName
]
664 ## Get PPI value from given packages
666 # @param CName The CName of the GUID
667 # @param PackageList List of packages looking-up in
668 # @param Inffile The driver file
670 # @retval GuidValue if the CName is found in any given package
671 # @retval None if the CName is not found in all given packages
673 def PpiValue(CName
, PackageList
, Inffile
= None):
674 for P
in PackageList
:
675 PpiKeys
= P
.Ppis
.keys()
676 if Inffile
and P
._PrivatePpis
:
677 if not Inffile
.startswith(P
.MetaFile
.Dir
):
678 PpiKeys
= [x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
]
683 ## A string template class
685 # This class implements a template for string replacement. A string template
686 # looks like following
688 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
690 # The string between ${BEGIN} and ${END} will be repeated as many times as the
691 # length of "placeholder_name", which is a list passed through a dict. The
692 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
693 # be not used and, in this case, the "placeholder_name" must not a list and it
694 # will just be replaced once.
696 class TemplateString(object):
697 _REPEAT_START_FLAG
= "BEGIN"
698 _REPEAT_END_FLAG
= "END"
700 class Section(object):
701 _LIST_TYPES
= [type([]), type(set()), type((0,))]
703 def __init__(self
, TemplateSection
, PlaceHolderList
):
704 self
._Template
= TemplateSection
705 self
._PlaceHolderList
= []
707 # Split the section into sub-sections according to the position of placeholders
709 self
._SubSectionList
= []
712 # The placeholders passed in must be in the format of
714 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
716 for PlaceHolder
, Start
, End
in PlaceHolderList
:
717 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
718 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
719 self
._PlaceHolderList
.append(PlaceHolder
)
720 SubSectionStart
= End
721 if SubSectionStart
< len(TemplateSection
):
722 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
724 self
._SubSectionList
= [TemplateSection
]
727 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
729 def Instantiate(self
, PlaceHolderValues
):
731 RepeatPlaceHolders
= {}
732 NonRepeatPlaceHolders
= {}
734 for PlaceHolder
in self
._PlaceHolderList
:
735 if PlaceHolder
not in PlaceHolderValues
:
737 Value
= PlaceHolderValues
[PlaceHolder
]
738 if type(Value
) in self
._LIST
_TYPES
:
740 RepeatTime
= len(Value
)
741 elif RepeatTime
!= len(Value
):
745 "${%s} has different repeat time from others!" % PlaceHolder
,
746 ExtraData
=str(self
._Template
)
748 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
750 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
752 if NonRepeatPlaceHolders
:
754 for S
in self
._SubSectionList
:
755 if S
not in NonRepeatPlaceHolders
:
758 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
760 StringList
= self
._SubSectionList
762 if RepeatPlaceHolders
:
764 for Index
in range(RepeatTime
):
766 if S
not in RepeatPlaceHolders
:
767 TempStringList
.append(S
)
769 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
770 StringList
= TempStringList
772 return "".join(StringList
)
775 def __init__(self
, Template
=None):
777 self
.IsBinary
= False
778 self
._Template
= Template
779 self
._TemplateSectionList
= self
._Parse
(Template
)
783 # @retval string The string replaced
788 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
790 # @retval list A list of TemplateString.Section objects
792 def _Parse(self
, Template
):
797 TemplateSectionList
= []
799 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
801 if MatchEnd
<= len(Template
):
802 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
803 TemplateSectionList
.append(TemplateSection
)
806 MatchString
= MatchObj
.group(1)
807 MatchStart
= MatchObj
.start()
808 MatchEnd
= MatchObj
.end()
810 if MatchString
== self
._REPEAT
_START
_FLAG
:
811 if MatchStart
> SectionStart
:
812 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
813 TemplateSectionList
.append(TemplateSection
)
814 SectionStart
= MatchEnd
816 elif MatchString
== self
._REPEAT
_END
_FLAG
:
817 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
818 TemplateSectionList
.append(TemplateSection
)
819 SectionStart
= MatchEnd
822 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
823 SearchFrom
= MatchEnd
824 return TemplateSectionList
826 ## Replace the string template with dictionary of placeholders and append it to previous one
828 # @param AppendString The string template to append
829 # @param Dictionary The placeholder dictionaries
831 def Append(self
, AppendString
, Dictionary
=None):
833 SectionList
= self
._Parse
(AppendString
)
834 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
836 self
.String
+= AppendString
838 ## Replace the string template with dictionary of placeholders
840 # @param Dictionary The placeholder dictionaries
842 # @retval str The string replaced with placeholder values
844 def Replace(self
, Dictionary
=None):
845 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
847 ## Progress indicator class
849 # This class makes use of thread to print progress on console.
852 # for avoiding deadloop
854 _ProgressThread
= None
855 _CheckInterval
= 0.25
859 # @param OpenMessage The string printed before progress charaters
860 # @param CloseMessage The string printed after progress charaters
861 # @param ProgressChar The charater used to indicate the progress
862 # @param Interval The interval in seconds between two progress charaters
864 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
865 self
.PromptMessage
= OpenMessage
866 self
.CodaMessage
= CloseMessage
867 self
.ProgressChar
= ProgressChar
868 self
.Interval
= Interval
869 if Progressor
._StopFlag
is None:
870 Progressor
._StopFlag
= threading
.Event()
872 ## Start to print progress charater
874 # @param OpenMessage The string printed before progress charaters
876 def Start(self
, OpenMessage
=None):
877 if OpenMessage
is not None:
878 self
.PromptMessage
= OpenMessage
879 Progressor
._StopFlag
.clear()
880 if Progressor
._ProgressThread
is None:
881 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
882 Progressor
._ProgressThread
.setDaemon(False)
883 Progressor
._ProgressThread
.start()
885 ## Stop printing progress charater
887 # @param CloseMessage The string printed after progress charaters
889 def Stop(self
, CloseMessage
=None):
890 OriginalCodaMessage
= self
.CodaMessage
891 if CloseMessage
is not None:
892 self
.CodaMessage
= CloseMessage
894 self
.CodaMessage
= OriginalCodaMessage
896 ## Thread entry method
897 def _ProgressThreadEntry(self
):
898 sys
.stdout
.write(self
.PromptMessage
+ " ")
901 while not Progressor
._StopFlag
.isSet():
903 sys
.stdout
.write(self
.ProgressChar
)
905 TimeUp
= self
.Interval
906 time
.sleep(self
._CheckInterval
)
907 TimeUp
-= self
._CheckInterval
908 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
911 ## Abort the progress display
914 if Progressor
._StopFlag
is not None:
915 Progressor
._StopFlag
.set()
916 if Progressor
._ProgressThread
is not None:
917 Progressor
._ProgressThread
.join()
918 Progressor
._ProgressThread
= None
920 ## A dict which can access its keys and/or values orderly
922 # The class implements a new kind of dict which its keys or values can be
923 # accessed in the order they are added into the dict. It guarantees the order
924 # by making use of an internal list to keep a copy of keys.
926 class sdict(IterableUserDict
):
929 IterableUserDict
.__init
__(self
)
933 def __setitem__(self
, key
, value
):
934 if key
not in self
._key
_list
:
935 self
._key
_list
.append(key
)
936 IterableUserDict
.__setitem
__(self
, key
, value
)
939 def __delitem__(self
, key
):
940 self
._key
_list
.remove(key
)
941 IterableUserDict
.__delitem
__(self
, key
)
943 ## used in "for k in dict" loop to ensure the correct order
945 return self
.iterkeys()
949 return len(self
._key
_list
)
952 def __contains__(self
, key
):
953 return key
in self
._key
_list
956 def index(self
, key
):
957 return self
._key
_list
.index(key
)
960 def insert(self
, key
, newkey
, newvalue
, order
):
961 index
= self
._key
_list
.index(key
)
962 if order
== 'BEFORE':
963 self
._key
_list
.insert(index
, newkey
)
964 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
965 elif order
== 'AFTER':
966 self
._key
_list
.insert(index
+ 1, newkey
)
967 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
970 def append(self
, sdict
):
972 if key
not in self
._key
_list
:
973 self
._key
_list
.append(key
)
974 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
976 def has_key(self
, key
):
977 return key
in self
._key
_list
982 IterableUserDict
.clear(self
)
984 ## Return a copy of keys
987 for key
in self
._key
_list
:
991 ## Return a copy of values
994 for key
in self
._key
_list
:
995 values
.append(self
[key
])
998 ## Return a copy of (key, value) list
1001 for key
in self
._key
_list
:
1002 items
.append((key
, self
[key
]))
1005 ## Iteration support
1006 def iteritems(self
):
1007 return iter(self
.items())
1009 ## Keys interation support
1011 return iter(self
.keys())
1013 ## Values interation support
1014 def itervalues(self
):
1015 return iter(self
.values())
1017 ## Return value related to a key, and remove the (key, value) from the dict
1018 def pop(self
, key
, *dv
):
1020 if key
in self
._key
_list
:
1022 self
.__delitem
__(key
)
1027 ## Return (key, value) pair, and remove the (key, value) from the dict
1029 key
= self
._key
_list
[-1]
1031 self
.__delitem
__(key
)
1034 def update(self
, dict=None, **kwargs
):
1035 if dict is not None:
1036 for k
, v
in dict.items():
1039 for k
, v
in kwargs
.items():
1042 ## Dictionary with restricted keys
1046 def __init__(self
, KeyList
):
1048 dict.__setitem
__(self
, Key
, "")
1051 def __setitem__(self
, key
, value
):
1053 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1054 ExtraData
=", ".join(dict.keys(self
)))
1055 dict.__setitem
__(self
, key
, value
)
1058 def __getitem__(self
, key
):
1061 return dict.__getitem
__(self
, key
)
1064 def __delitem__(self
, key
):
1065 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1070 self
.__setitem
__(Key
, "")
1072 ## Return value related to a key, and remove the (key, value) from the dict
1073 def pop(self
, key
, *dv
):
1074 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1076 ## Return (key, value) pair, and remove the (key, value) from the dict
1078 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1080 ## Dictionary using prioritized list as key
1083 _ListType
= type([])
1084 _TupleType
= type(())
1085 _Wildcard
= 'COMMON'
1086 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1088 def __init__(self
, _Single_
=False, _Level_
=2):
1089 self
._Level
_ = _Level_
1091 self
._Single
_ = _Single_
1094 def __getitem__(self
, key
):
1097 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1101 elif self
._Level
_ > 1:
1102 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1105 if self
._Level
_ > 1:
1106 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1108 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1109 FirstKey
= self
._Wildcard
1112 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1114 return self
._GetAllValues
(FirstKey
, RestKeys
)
1116 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1118 #print "%s-%s" % (FirstKey, self._Level_) ,
1119 if self
._Level
_ > 1:
1120 if FirstKey
== self
._Wildcard
:
1121 if FirstKey
in self
.data
:
1122 Value
= self
.data
[FirstKey
][RestKeys
]
1124 for Key
in self
.data
:
1125 Value
= self
.data
[Key
][RestKeys
]
1126 if Value
is not None: break
1128 if FirstKey
in self
.data
:
1129 Value
= self
.data
[FirstKey
][RestKeys
]
1130 if Value
is None and self
._Wildcard
in self
.data
:
1132 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1134 if FirstKey
== self
._Wildcard
:
1135 if FirstKey
in self
.data
:
1136 Value
= self
.data
[FirstKey
]
1138 for Key
in self
.data
:
1139 Value
= self
.data
[Key
]
1140 if Value
is not None: break
1142 if FirstKey
in self
.data
:
1143 Value
= self
.data
[FirstKey
]
1144 elif self
._Wildcard
in self
.data
:
1145 Value
= self
.data
[self
._Wildcard
]
1148 def _GetAllValues(self
, FirstKey
, RestKeys
):
1150 if self
._Level
_ > 1:
1151 if FirstKey
== self
._Wildcard
:
1152 for Key
in self
.data
:
1153 Value
+= self
.data
[Key
][RestKeys
]
1155 if FirstKey
in self
.data
:
1156 Value
+= self
.data
[FirstKey
][RestKeys
]
1157 if self
._Wildcard
in self
.data
:
1158 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1160 if FirstKey
== self
._Wildcard
:
1161 for Key
in self
.data
:
1162 Value
.append(self
.data
[Key
])
1164 if FirstKey
in self
.data
:
1165 Value
.append(self
.data
[FirstKey
])
1166 if self
._Wildcard
in self
.data
:
1167 Value
.append(self
.data
[self
._Wildcard
])
1171 def __setitem__(self
, key
, value
):
1174 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1179 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1182 if self
._Level
_ > 1:
1183 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1185 if FirstKey
in self
._ValidWildcardList
:
1186 FirstKey
= self
._Wildcard
1188 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1189 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1191 if self
._Level
_ > 1:
1192 self
.data
[FirstKey
][RestKeys
] = value
1194 self
.data
[FirstKey
] = value
1196 def SetGreedyMode(self
):
1197 self
._Single
_ = False
1198 if self
._Level
_ > 1:
1199 for Key
in self
.data
:
1200 self
.data
[Key
].SetGreedyMode()
1202 def SetSingleMode(self
):
1203 self
._Single
_ = True
1204 if self
._Level
_ > 1:
1205 for Key
in self
.data
:
1206 self
.data
[Key
].SetSingleMode()
1208 def GetKeys(self
, KeyIndex
=0):
1209 assert KeyIndex
>= 0
1211 return set(self
.data
.keys())
1214 for Key
in self
.data
:
1215 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1218 def IsFieldValueAnArray (Value
):
1219 Value
= Value
.strip()
1220 if Value
.startswith('GUID') and Value
.endswith(')'):
1222 if Value
.startswith('L"') and Value
.endswith('"') and len(list(Value
[2:-1])) > 1:
1224 if Value
[0] == '"' and Value
[-1] == '"' and len(list(Value
[1:-1])) > 1:
1226 if Value
[0] == '{' and Value
[-1] == '}':
1228 if Value
.startswith("L'") and Value
.endswith("'") and len(list(Value
[2:-1])) > 1:
1230 if Value
[0] == "'" and Value
[-1] == "'" and len(list(Value
[1:-1])) > 1:
1234 def AnalyzePcdExpression(Setting
):
1235 Setting
= Setting
.strip()
1236 # There might be escaped quote in a string: \", \\\" , \', \\\'
1238 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1240 InSingleQuoteStr
= False
1241 InDoubleQuoteStr
= False
1243 for Index
, ch
in enumerate(Data
):
1244 if ch
== '"' and not InSingleQuoteStr
:
1245 if Data
[Index
- 1] != '\\':
1246 InDoubleQuoteStr
= not InDoubleQuoteStr
1247 elif ch
== "'" and not InDoubleQuoteStr
:
1248 if Data
[Index
- 1] != '\\':
1249 InSingleQuoteStr
= not InSingleQuoteStr
1250 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1252 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1255 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1262 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1264 FieldList
.append(Setting
[StartPos
:].strip())
1266 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1271 def ParseDevPathValue (Value
):
1273 Value
.replace('\\', '/').replace(' ', '')
1275 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1277 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1278 out
, err
= p
.communicate()
1279 except Exception, X
:
1280 raise BadExpression("DevicePath: %s" % (str(X
)) )
1282 subprocess
._cleanup
()
1286 raise BadExpression("DevicePath: %s" % str(err
))
1287 Size
= len(out
.split())
1288 out
= ','.join(out
.split())
1289 return '{' + out
+ '}', Size
1291 def ParseFieldValue (Value
):
1292 if type(Value
) == type(0):
1293 return Value
, (Value
.bit_length() + 7) / 8
1294 if type(Value
) <> type(''):
1295 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1296 Value
= Value
.strip()
1297 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1298 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1300 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1302 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1303 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1305 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1307 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1308 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1310 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1312 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1313 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1315 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1317 if Value
.startswith('GUID') and Value
.endswith(')'):
1318 Value
= Value
.split('(', 1)[1][:-1].strip()
1319 if Value
[0] == '{' and Value
[-1] == '}':
1320 TmpValue
= GuidStructureStringToGuidString(Value
)
1321 if len(TmpValue
) == 0:
1322 raise BadExpression("Invalid GUID value string %s" % Value
)
1324 if Value
[0] == '"' and Value
[-1] == '"':
1327 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1328 except ValueError, Message
:
1329 raise BadExpression('%s' % Message
)
1330 Value
, Size
= ParseFieldValue(Value
)
1332 if Value
.startswith('L"') and Value
.endswith('"'):
1334 # translate escape character
1344 Value
= (Value
<< 16) |
ord(Char
)
1345 return Value
, (len(List
) + 1) * 2
1346 if Value
.startswith('"') and Value
.endswith('"'):
1348 # translate escape character
1357 Value
= (Value
<< 8) |
ord(Char
)
1358 return Value
, len(List
) + 1
1359 if Value
.startswith("L'") and Value
.endswith("'"):
1360 # Unicode Character Constant
1361 # translate escape character
1369 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1373 Value
= (Value
<< 16) |
ord(Char
)
1374 return Value
, len(List
) * 2
1375 if Value
.startswith("'") and Value
.endswith("'"):
1376 # Character constant
1377 # translate escape character
1384 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1388 Value
= (Value
<< 8) |
ord(Char
)
1389 return Value
, len(List
)
1390 if Value
.startswith('{') and Value
.endswith('}'):
1393 List
= [Item
.strip() for Item
in Value
.split(',')]
1398 ItemValue
, Size
= ParseFieldValue(Item
)
1400 for I
in range(Size
):
1401 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1402 return Value
, RetSize
1403 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1404 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1405 Value
= Value
.strip().strip('"')
1406 return ParseDevPathValue(Value
)
1407 if Value
.lower().startswith('0x'):
1408 Value
= int(Value
, 16)
1411 return Value
, (Value
.bit_length() + 7) / 8
1412 if Value
[0].isdigit():
1413 Value
= int(Value
, 10)
1416 return Value
, (Value
.bit_length() + 7) / 8
1417 if Value
.lower() == 'true':
1419 if Value
.lower() == 'false':
1425 # Analyze DSC PCD value, since there is no data type info in DSC
1426 # This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1427 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1428 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1429 # 3. Dynamic default:
1430 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1431 # TokenSpace.PcdCName|PcdValue
1433 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1434 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1436 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1437 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1438 # there might have "|" operator, also in string value.
1440 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1441 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1442 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1444 # ValueList: A List contain fields described above
1445 # IsValid: True if conforming EBNF, otherwise False
1446 # Index: The index where PcdValue is in ValueList
1448 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1449 FieldList
= AnalyzePcdExpression(Setting
)
1452 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1453 Value
= FieldList
[0]
1455 if len(FieldList
) > 1:
1456 if FieldList
[1].upper().startswith("0X") or FieldList
[1].isdigit():
1459 DataType
= FieldList
[1]
1461 if len(FieldList
) > 2:
1464 IsValid
= (len(FieldList
) <= 1)
1466 IsValid
= (len(FieldList
) <= 3)
1467 # Value, Size = ParseFieldValue(Value)
1470 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1474 return [str(Value
), '', str(Size
)], IsValid
, 0
1475 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1476 Value
= FieldList
[0]
1478 if len(FieldList
) > 1:
1482 if len(FieldList
) > 2:
1485 IsValid
= (len(FieldList
) <= 1)
1487 IsValid
= (len(FieldList
) <= 3)
1491 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1495 return [Value
, Type
, str(Size
)], IsValid
, 0
1496 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1497 VpdOffset
= FieldList
[0]
1499 if not DataType
== TAB_VOID
:
1500 if len(FieldList
) > 1:
1501 Value
= FieldList
[1]
1503 if len(FieldList
) > 1:
1505 if len(FieldList
) > 2:
1506 Value
= FieldList
[2]
1508 IsValid
= (len(FieldList
) <= 1)
1510 IsValid
= (len(FieldList
) <= 3)
1513 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1517 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1518 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1519 HiiString
= FieldList
[0]
1520 Guid
= Offset
= Value
= Attribute
= ''
1521 if len(FieldList
) > 1:
1523 if len(FieldList
) > 2:
1524 Offset
= FieldList
[2]
1525 if len(FieldList
) > 3:
1526 Value
= FieldList
[3]
1527 if len(FieldList
) > 4:
1528 Attribute
= FieldList
[4]
1529 IsValid
= (3 <= len(FieldList
) <= 5)
1530 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1535 # Analyze the pcd Value, Datum type and TokenNumber.
1536 # Used to avoid split issue while the value string contain "|" character
1538 # @param[in] Setting: A String contain value/datum type/token number information;
1540 # @retval ValueList: A List contain value, datum type and toke number.
1542 def AnalyzePcdData(Setting
):
1543 ValueList
= ['', '', '']
1545 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1546 PtrValue
= ValueRe
.findall(Setting
)
1548 ValueUpdateFlag
= False
1550 if len(PtrValue
) >= 1:
1551 Setting
= re
.sub(ValueRe
, '', Setting
)
1552 ValueUpdateFlag
= True
1554 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1555 ValueList
[0:len(TokenList
)] = TokenList
1558 ValueList
[0] = PtrValue
[0]
1562 ## check format of PCD value against its the datum type
1564 # For PCD value setting
1566 def CheckPcdDatum(Type
, Value
):
1567 if Type
== TAB_VOID
:
1568 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1569 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1570 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1572 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1573 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1574 elif ValueRe
.match(Value
):
1575 # Check the chars in UnicodeString or CString is printable
1576 if Value
.startswith("L"):
1580 Printset
= set(string
.printable
)
1581 Printset
.remove(TAB_PRINTCHAR_VT
)
1582 Printset
.add(TAB_PRINTCHAR_BS
)
1583 Printset
.add(TAB_PRINTCHAR_NUL
)
1584 if not set(Value
).issubset(Printset
):
1585 PrintList
= list(Printset
)
1587 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1588 elif Type
== 'BOOLEAN':
1589 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1590 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1591 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1592 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1594 Value
= long(Value
, 0)
1596 return False, "Invalid value [%s] of type [%s];"\
1597 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1599 return True, "StructurePcd"
1603 ## Split command line option string to list
1605 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1606 # in non-windows platform to launch command
1608 def SplitOption(OptionString
):
1613 for Index
in range(0, len(OptionString
)):
1614 CurrentChar
= OptionString
[Index
]
1615 if CurrentChar
in ['"', "'"]:
1616 if QuotationMark
== CurrentChar
:
1618 elif QuotationMark
== "":
1619 QuotationMark
= CurrentChar
1624 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1625 if Index
> OptionStart
:
1626 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1628 LastChar
= CurrentChar
1629 OptionList
.append(OptionString
[OptionStart
:])
1632 def CommonPath(PathList
):
1633 P1
= min(PathList
).split(os
.path
.sep
)
1634 P2
= max(PathList
).split(os
.path
.sep
)
1635 for Index
in xrange(min(len(P1
), len(P2
))):
1636 if P1
[Index
] != P2
[Index
]:
1637 return os
.path
.sep
.join(P1
[:Index
])
1638 return os
.path
.sep
.join(P1
)
1641 # Convert string to C format array
1643 def ConvertStringToByteArray(Value
):
1644 Value
= Value
.strip()
1648 if not Value
.endswith('}'):
1650 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1651 ValFields
= Value
.split(',')
1653 for Index
in range(len(ValFields
)):
1654 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1657 Value
= '{' + ','.join(ValFields
) + '}'
1661 if Value
.startswith('L"'):
1662 if not Value
.endswith('"'):
1666 elif not Value
.startswith('"') or not Value
.endswith('"'):
1669 Value
= eval(Value
) # translate escape character
1671 for Index
in range(0,len(Value
)):
1673 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1675 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1676 Value
= NewValue
+ '0}'
1679 class PathClass(object):
1680 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1681 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1683 self
.File
= str(File
)
1684 if os
.path
.isabs(self
.File
):
1688 self
.Root
= str(Root
)
1689 self
.AlterRoot
= str(AlterRoot
)
1691 # Remove any '.' and '..' in path
1693 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1694 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1695 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1696 # eliminate the side-effect of 'C:'
1697 if self
.Root
[-1] == ':':
1698 self
.Root
+= os
.path
.sep
1699 # file path should not start with path separator
1700 if self
.Root
[-1] == os
.path
.sep
:
1701 self
.File
= self
.Path
[len(self
.Root
):]
1703 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1705 self
.Path
= os
.path
.normpath(self
.File
)
1707 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1708 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1712 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1714 self
.Dir
= self
.Root
1716 self
.Dir
= self
.SubDir
1721 self
.Type
= self
.Ext
.lower()
1723 self
.IsBinary
= IsBinary
1724 self
.Target
= Target
1725 self
.TagName
= TagName
1726 self
.ToolCode
= ToolCode
1727 self
.ToolChainFamily
= ToolChainFamily
1731 ## Convert the object of this class to a string
1733 # Convert member Path of the class to a string
1735 # @retval string Formatted String
1740 ## Override __eq__ function
1742 # Check whether PathClass are the same
1744 # @retval False The two PathClass are different
1745 # @retval True The two PathClass are the same
1747 def __eq__(self
, Other
):
1748 if type(Other
) == type(self
):
1749 return self
.Path
== Other
.Path
1751 return self
.Path
== str(Other
)
1753 ## Override __cmp__ function
1755 # Customize the comparsion operation of two PathClass
1757 # @retval 0 The two PathClass are different
1758 # @retval -1 The first PathClass is less than the second PathClass
1759 # @retval 1 The first PathClass is Bigger than the second PathClass
1760 def __cmp__(self
, Other
):
1761 if type(Other
) == type(self
):
1762 OtherKey
= Other
.Path
1764 OtherKey
= str(Other
)
1767 if SelfKey
== OtherKey
:
1769 elif SelfKey
> OtherKey
:
1774 ## Override __hash__ function
1776 # Use Path as key in hash table
1778 # @retval string Key for hash table
1781 return hash(self
.Path
)
1783 def _GetFileKey(self
):
1784 if self
._Key
is None:
1785 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1788 def _GetTimeStamp(self
):
1789 return os
.stat(self
.Path
)[8]
1791 def Validate(self
, Type
='', CaseSensitive
=True):
1792 if GlobalData
.gCaseInsensitive
:
1793 CaseSensitive
= False
1794 if Type
and Type
.lower() != self
.Type
:
1795 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1797 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1798 if not RealRoot
and not RealFile
:
1799 RealFile
= self
.File
1801 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1803 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1804 if len (mws
.getPkgPath()) == 0:
1805 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1807 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1811 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1812 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1813 ErrorCode
= FILE_CASE_MISMATCH
1814 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1816 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1817 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1819 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1822 self
.File
= RealFile
1823 self
.Root
= RealRoot
1824 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1825 return ErrorCode
, ErrorInfo
1827 Key
= property(_GetFileKey
)
1828 TimeStamp
= property(_GetTimeStamp
)
1830 ## Parse PE image to get the required PE informaion.
1832 class PeImageClass():
1835 # @param File FilePath of PeImage
1837 def __init__(self
, PeFile
):
1838 self
.FileName
= PeFile
1839 self
.IsValid
= False
1842 self
.SectionAlignment
= 0
1843 self
.SectionHeaderList
= []
1846 PeObject
= open(PeFile
, 'rb')
1848 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1851 ByteArray
= array
.array('B')
1852 ByteArray
.fromfile(PeObject
, 0x3E)
1853 ByteList
= ByteArray
.tolist()
1854 # DOS signature should be 'MZ'
1855 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1856 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1859 # Read 4 byte PE Signature
1860 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1861 PeObject
.seek(PeOffset
)
1862 ByteArray
= array
.array('B')
1863 ByteArray
.fromfile(PeObject
, 4)
1864 # PE signature should be 'PE\0\0'
1865 if ByteArray
.tostring() != 'PE\0\0':
1866 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1869 # Read PE file header
1870 ByteArray
= array
.array('B')
1871 ByteArray
.fromfile(PeObject
, 0x14)
1872 ByteList
= ByteArray
.tolist()
1873 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1875 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1878 # Read PE optional header
1879 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1880 ByteArray
= array
.array('B')
1881 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1882 ByteList
= ByteArray
.tolist()
1883 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1884 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1885 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1887 # Read each Section Header
1888 for Index
in range(SecNumber
):
1889 ByteArray
= array
.array('B')
1890 ByteArray
.fromfile(PeObject
, 0x28)
1891 ByteList
= ByteArray
.tolist()
1892 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1893 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1894 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1895 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1896 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1900 def _ByteListToStr(self
, ByteList
):
1902 for index
in range(len(ByteList
)):
1903 if ByteList
[index
] == 0:
1905 String
+= chr(ByteList
[index
])
1908 def _ByteListToInt(self
, ByteList
):
1910 for index
in range(len(ByteList
) - 1, -1, -1):
1911 Value
= (Value
<< 8) |
int(ByteList
[index
])
1914 class DefaultStore():
1915 def __init__(self
,DefaultStores
):
1917 self
.DefaultStores
= DefaultStores
1918 def DefaultStoreID(self
,DefaultStoreName
):
1919 for key
,value
in self
.DefaultStores
.items():
1920 if value
== DefaultStoreName
:
1923 def GetDefaultDefault(self
):
1924 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1925 return "0",TAB_DEFAULT_STORES_DEFAULT
1927 minvalue
= min([int(value_str
) for value_str
in self
.DefaultStores
])
1928 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1929 def GetMin(self
,DefaultSIdList
):
1930 if not DefaultSIdList
:
1931 return TAB_DEFAULT_STORES_DEFAULT
1932 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1935 minid
= min(storeidset
)
1936 for sid
,name
in self
.DefaultStores
.values():
1945 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1949 for SkuName
in SkuIds
:
1950 SkuId
= SkuIds
[SkuName
][0]
1951 skuid_num
= int(SkuId
,16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1952 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1953 EdkLogger
.error("build", PARAMETER_INVALID
,
1954 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1957 self
.AvailableSkuIds
= sdict()
1959 self
.SkuIdNumberSet
= []
1960 self
.SkuData
= SkuIds
1961 self
.__SkuInherit
= {}
1962 self
.__SkuIdentifier
= SkuIdentifier
1963 if SkuIdentifier
== '' or SkuIdentifier
is None:
1964 self
.SkuIdSet
= ['DEFAULT']
1965 self
.SkuIdNumberSet
= ['0U']
1966 elif SkuIdentifier
== 'ALL':
1967 self
.SkuIdSet
= SkuIds
.keys()
1968 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1970 r
= SkuIdentifier
.split('|')
1971 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1974 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1976 EdkLogger
.error("build", PARAMETER_INVALID
,
1977 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1978 % (k
, " | ".join(SkuIds
.keys())))
1979 for each
in self
.SkuIdSet
:
1981 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1983 EdkLogger
.error("build", PARAMETER_INVALID
,
1984 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1985 % (each
, " | ".join(SkuIds
.keys())))
1986 if self
.SkuUsageType
!= self
.SINGLE
:
1987 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1989 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1990 if 'COMMON' in GlobalData
.gSkuids
:
1991 GlobalData
.gSkuids
.remove('COMMON')
1992 if self
.SkuUsageType
== self
.SINGLE
:
1993 if len(GlobalData
.gSkuids
) != 1:
1994 if 'DEFAULT' in GlobalData
.gSkuids
:
1995 GlobalData
.gSkuids
.remove('DEFAULT')
1996 if GlobalData
.gSkuids
:
1997 GlobalData
.gSkuids
.sort()
1999 def GetNextSkuId(self
, skuname
):
2000 if not self
.__SkuInherit
:
2001 self
.__SkuInherit
= {}
2002 for item
in self
.SkuData
.values():
2003 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
2004 return self
.__SkuInherit
.get(skuname
,"DEFAULT")
2006 def GetSkuChain(self
,sku
):
2007 if sku
== "DEFAULT":
2012 nextsku
= self
.GetNextSkuId(nextsku
)
2013 skulist
.append(nextsku
)
2014 if nextsku
== "DEFAULT":
2018 def SkuOverrideOrder(self
):
2020 for skuname
in self
.SkuIdSet
:
2021 skuorderset
.append(self
.GetSkuChain(skuname
))
2024 for index
in range(max([len(item
) for item
in skuorderset
])):
2025 for subset
in skuorderset
:
2026 if index
> len(subset
)-1:
2028 if subset
[index
] in skuorder
:
2030 skuorder
.append(subset
[index
])
2034 def __SkuUsageType(self
):
2036 if self
.__SkuIdentifier
.upper() == "ALL":
2037 return SkuClass
.MULTIPLE
2039 if len(self
.SkuIdSet
) == 1:
2040 if self
.SkuIdSet
[0] == 'DEFAULT':
2041 return SkuClass
.DEFAULT
2043 return SkuClass
.SINGLE
2044 elif len(self
.SkuIdSet
) == 2:
2045 if 'DEFAULT' in self
.SkuIdSet
:
2046 return SkuClass
.SINGLE
2048 return SkuClass
.MULTIPLE
2050 return SkuClass
.MULTIPLE
2051 def DumpSkuIdArrary(self
):
2054 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2057 for skuname
in self
.AvailableSkuIds
:
2058 if skuname
== "COMMON":
2060 while skuname
!= "DEFAULT":
2061 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2062 skuname
= self
.GetNextSkuId(skuname
)
2063 ArrayStrList
.append("0x0")
2064 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2066 def __GetAvailableSkuIds(self
):
2067 return self
.AvailableSkuIds
2069 def __GetSystemSkuID(self
):
2070 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2071 if len(self
.SkuIdSet
) == 1:
2072 return self
.SkuIdSet
[0]
2074 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2077 def __GetAvailableSkuIdNumber(self
):
2078 return self
.SkuIdNumberSet
2079 SystemSkuId
= property(__GetSystemSkuID
)
2080 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2081 SkuUsageType
= property(__SkuUsageType
)
2082 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2085 # Pack a registry format GUID
2087 def PackRegistryFormatGuid(Guid
):
2088 Guid
= Guid
.split('-')
2089 return pack('=LHHBBBBBBBB',
2093 int(Guid
[3][-4:-2], 16),
2094 int(Guid
[3][-2:], 16),
2095 int(Guid
[4][-12:-10], 16),
2096 int(Guid
[4][-10:-8], 16),
2097 int(Guid
[4][-8:-6], 16),
2098 int(Guid
[4][-6:-4], 16),
2099 int(Guid
[4][-4:-2], 16),
2100 int(Guid
[4][-2:], 16)
2103 ## Get the integer value from string like "14U" or integer like 2
2105 # @param Input The object that may be either a integer value or a string
2107 # @retval Value The integer value that the input represents
2109 def GetIntegerValue(Input
):
2110 if type(Input
) in (int, long):
2113 if String
.endswith("U"):
2114 String
= String
[:-1]
2115 if String
.endswith("ULL"):
2116 String
= String
[:-3]
2117 if String
.endswith("LL"):
2118 String
= String
[:-2]
2120 if String
.startswith("0x") or String
.startswith("0X"):
2121 return int(String
, 16)
2129 # This acts like the main() function for the script, unless it is 'import'ed into another
2132 if __name__
== '__main__':