2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2019, 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 random
import sample
28 from struct
import pack
29 from UserDict
import IterableUserDict
30 from UserList
import UserList
32 from Common
import EdkLogger
as EdkLogger
33 from Common
import GlobalData
as GlobalData
34 from .DataType
import *
35 from .BuildToolError
import *
36 from CommonDataClass
.DataClass
import *
37 from .Parsing
import GetSplitValueList
38 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
39 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
41 from CommonDataClass
.Exceptions
import BadExpression
42 from Common
.caching
import cached_property
44 from collections
import OrderedDict
45 ## Regular expression used to find out place holders in string template
46 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
48 ## regular expressions for map file processing
49 startPatternGeneral
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
50 addressPatternGeneral
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
51 valuePatternGcc
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
52 pcdPatternGcc
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
53 secReGeneral
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
55 StructPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
57 ## Dictionary used to store file time stamp for quick re-access
58 gFileTimeStampCache
= {} # {file path : file time stamp}
60 ## Dictionary used to store dependencies of files
61 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
64 # If a module is built more than once with different PCDs or library classes
65 # a temporary INF file with same content is created, the temporary file is removed
70 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
71 """ Parse map file to get variable offset in current EFI file
72 @param mapfilepath Map file absolution path
73 @param efifilepath: EFI binary file full path
74 @param varnames iteratable container whose elements are variable names to be searched
76 @return List whos elements are tuple with variable name and raw offset
80 f
= open(mapfilepath
, 'r')
86 if len(lines
) == 0: return None
87 firstline
= lines
[0].strip()
88 if (firstline
.startswith("Archive member included ") and
89 firstline
.endswith(" file (symbol)")):
90 return _parseForGCC(lines
, efifilepath
, varnames
)
91 if firstline
.startswith("# Path:"):
92 return _parseForXcode(lines
, efifilepath
, varnames
)
93 return _parseGeneral(lines
, efifilepath
, varnames
)
95 def _parseForXcode(lines
, efifilepath
, varnames
):
100 if status
== 0 and line
== "# Symbols:":
103 if status
== 1 and len(line
) != 0:
104 for varname
in varnames
:
106 # cannot pregenerate this RegEx since it uses varname from varnames.
107 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
109 ret
.append((varname
, m
.group(1)))
112 def _parseForGCC(lines
, efifilepath
, varnames
):
113 """ Parse map file generated by GCC linker """
117 for index
, line
in enumerate(lines
):
119 # status machine transection
120 if status
== 0 and line
== "Memory Configuration":
123 elif status
== 1 and line
== 'Linker script and memory map':
126 elif status
==2 and line
== 'START GROUP':
132 m
= valuePatternGcc
.match(line
)
134 sections
.append(m
.groups(0))
135 for varname
in varnames
:
137 m
= re
.match("^.data.(%s)" % varname
, line
)
139 m
= re
.match(".data.(%s)$" % varname
, line
)
141 Str
= lines
[index
+ 1]
143 Str
= line
[len(".data.%s" % varname
):]
145 m
= pcdPatternGcc
.match(Str
.strip())
147 varoffset
.append((varname
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
151 # get section information from efi file
152 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
153 if efisecs
is None or len(efisecs
) == 0:
157 for efisec
in efisecs
:
158 for section
in sections
:
159 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
160 redirection
= int(section
[1], 16) - efisec
[1]
163 for var
in varoffset
:
164 for efisec
in efisecs
:
165 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
166 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
169 def _parseGeneral(lines
, efifilepath
, varnames
):
170 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
171 secs
= [] # key = section name
173 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
177 if startPatternGeneral
.match(line
):
180 if addressPatternGeneral
.match(line
):
183 if line
.startswith("entry point at"):
186 if status
== 1 and len(line
) != 0:
187 m
= secReGeneral
.match(line
)
188 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
189 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
190 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
191 if status
== 2 and len(line
) != 0:
192 for varname
in varnames
:
193 m
= symRe
.match(line
)
194 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
195 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
196 sec_no
= int(sec_no
, 16)
197 sym_offset
= int(sym_offset
, 16)
198 vir_addr
= int(vir_addr
, 16)
199 # cannot pregenerate this RegEx since it uses varname from varnames.
200 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
202 # fond a binary pcd entry in map file
204 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
205 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
207 if not varoffset
: return []
209 # get section information from efi file
210 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
211 if efisecs
is None or len(efisecs
) == 0:
215 for var
in varoffset
:
217 for efisec
in efisecs
:
219 if var
[1].strip() == efisec
[0].strip():
220 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
221 elif var
[4] == index
:
222 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
226 ## Routine to process duplicated INF
228 # This function is called by following two cases:
231 # Pkg/module/module.inf
232 # Pkg/module/module.inf {
234 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
237 # INF Pkg/module/module.inf
238 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
240 # This function copies Pkg/module/module.inf to
241 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
243 # @param Path Original PathClass object
244 # @param BaseName New file base name
246 # @retval return the new PathClass object
248 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
249 Filename
= os
.path
.split(Path
.File
)[1]
251 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
253 Filename
= BaseName
+ Path
.BaseName
256 # If -N is specified on command line, cache is disabled
257 # The directory has to be created
259 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
260 if not os
.path
.exists(DbDir
):
263 # A temporary INF is copied to database path which must have write permission
264 # The temporary will be removed at the end of build
265 # In case of name conflict, the file name is
266 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
268 TempFullPath
= os
.path
.join(DbDir
,
270 RtPath
= PathClass(Path
.File
, Workspace
)
272 # Modify the full path to temporary path, keep other unchanged
274 # To build same module more than once, the module path with FILE_GUID overridden has
275 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
276 # in DSC which is used as relative path by C files and other files in INF.
277 # A trick was used: all module paths are PathClass instances, after the initialization
278 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
280 # The reason for creating a temporary INF is:
281 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
282 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
283 # A different key for the same module is needed to create different output directory,
284 # retrieve overridden PCDs, library instances.
286 # The BaseName is the FILE_GUID which is also the output directory name.
289 RtPath
.Path
= TempFullPath
290 RtPath
.BaseName
= BaseName
292 # If file exists, compare contents
294 if os
.path
.exists(TempFullPath
):
295 with
open(str(Path
), 'rb') as f1
, open(TempFullPath
, 'rb') as f2
:
296 if f1
.read() == f2
.read():
298 _TempInfs
.append(TempFullPath
)
299 shutil
.copy2(str(Path
), TempFullPath
)
302 ## Remove temporary created INFs whose paths were saved in _TempInfs
304 def ClearDuplicatedInf():
306 File
= _TempInfs
.pop()
307 if os
.path
.exists(File
):
310 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
312 # @param Guid The GUID string
314 # @retval string The GUID string in C structure style
316 def GuidStringToGuidStructureString(Guid
):
317 GuidList
= Guid
.split('-')
319 for Index
in range(0, 3, 1):
320 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
321 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
322 for Index
in range(0, 12, 2):
323 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
327 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
329 # @param GuidValue The GUID value in byte array
331 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
333 def GuidStructureByteArrayToGuidString(GuidValue
):
334 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
335 guidValueList
= guidValueString
.split(",")
336 if len(guidValueList
) != 16:
338 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
340 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
341 int(guidValueList
[3], 16),
342 int(guidValueList
[2], 16),
343 int(guidValueList
[1], 16),
344 int(guidValueList
[0], 16),
345 int(guidValueList
[5], 16),
346 int(guidValueList
[4], 16),
347 int(guidValueList
[7], 16),
348 int(guidValueList
[6], 16),
349 int(guidValueList
[8], 16),
350 int(guidValueList
[9], 16),
351 int(guidValueList
[10], 16),
352 int(guidValueList
[11], 16),
353 int(guidValueList
[12], 16),
354 int(guidValueList
[13], 16),
355 int(guidValueList
[14], 16),
356 int(guidValueList
[15], 16)
361 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
363 # @param GuidValue The GUID value in C structure format
365 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
367 def GuidStructureStringToGuidString(GuidValue
):
368 if not GlobalData
.gGuidCFormatPattern
.match(GuidValue
):
370 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
371 guidValueList
= guidValueString
.split(",")
372 if len(guidValueList
) != 11:
374 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
376 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
377 int(guidValueList
[0], 16),
378 int(guidValueList
[1], 16),
379 int(guidValueList
[2], 16),
380 int(guidValueList
[3], 16),
381 int(guidValueList
[4], 16),
382 int(guidValueList
[5], 16),
383 int(guidValueList
[6], 16),
384 int(guidValueList
[7], 16),
385 int(guidValueList
[8], 16),
386 int(guidValueList
[9], 16),
387 int(guidValueList
[10], 16)
392 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
394 # @param GuidValue The GUID value in C structure format
396 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
398 def GuidStructureStringToGuidValueName(GuidValue
):
399 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
400 guidValueList
= guidValueString
.split(",")
401 if len(guidValueList
) != 11:
402 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
403 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
404 int(guidValueList
[0], 16),
405 int(guidValueList
[1], 16),
406 int(guidValueList
[2], 16),
407 int(guidValueList
[3], 16),
408 int(guidValueList
[4], 16),
409 int(guidValueList
[5], 16),
410 int(guidValueList
[6], 16),
411 int(guidValueList
[7], 16),
412 int(guidValueList
[8], 16),
413 int(guidValueList
[9], 16),
414 int(guidValueList
[10], 16)
417 ## Create directories
419 # @param Directory The directory name
421 def CreateDirectory(Directory
):
422 if Directory
is None or Directory
.strip() == "":
425 if not os
.access(Directory
, os
.F_OK
):
426 os
.makedirs(Directory
)
431 ## Remove directories, including files and sub-directories in it
433 # @param Directory The directory name
435 def RemoveDirectory(Directory
, Recursively
=False):
436 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
439 CurrentDirectory
= os
.getcwd()
441 for File
in os
.listdir("."):
442 if os
.path
.isdir(File
):
443 RemoveDirectory(File
, Recursively
)
446 os
.chdir(CurrentDirectory
)
449 ## Store content in file
451 # This method is used to save file only when its content is changed. This is
452 # quite useful for "make" system to decide what will be re-built and what won't.
454 # @param File The path of file
455 # @param Content The new content of the file
456 # @param IsBinaryFile The flag indicating if the file is binary file or not
458 # @retval True If the file content is changed and the file is renewed
459 # @retval False If the file content is the same
461 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
463 Content
= Content
.replace("\n", os
.linesep
)
465 if os
.path
.exists(File
):
467 if Content
== open(File
, "rb").read():
470 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
472 DirName
= os
.path
.dirname(File
)
473 if not CreateDirectory(DirName
):
474 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
477 DirName
= os
.getcwd()
478 if not os
.access(DirName
, os
.W_OK
):
479 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
482 Fd
= open(File
, "wb")
486 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
490 ## Retrieve and cache the real path name in file system
492 # @param Root The root directory of path relative to
494 # @retval str The path string if the path exists
495 # @retval None If path doesn't exist
501 def __init__(self
, Root
):
503 for F
in os
.listdir(Root
):
505 self
._UPPER
_CACHE
_[F
.upper()] = F
508 def __getitem__(self
, Path
):
509 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
512 if Path
and Path
[0] == os
.path
.sep
:
514 if Path
in self
._CACHE
_:
515 return os
.path
.join(self
._Root
, Path
)
516 UpperPath
= Path
.upper()
517 if UpperPath
in self
._UPPER
_CACHE
_:
518 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
522 SepIndex
= Path
.find(os
.path
.sep
)
524 Parent
= UpperPath
[:SepIndex
]
525 if Parent
not in self
._UPPER
_CACHE
_:
527 LastSepIndex
= SepIndex
528 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
530 if LastSepIndex
== -1:
535 SepIndex
= LastSepIndex
537 Parent
= Path
[:SepIndex
]
538 ParentKey
= UpperPath
[:SepIndex
]
539 if ParentKey
not in self
._UPPER
_CACHE
_:
543 if Parent
in self
._CACHE
_:
546 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
547 for F
in os
.listdir(ParentDir
):
548 Dir
= os
.path
.join(ParentDir
, F
)
549 self
._CACHE
_.add(Dir
)
550 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
552 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
555 if Path
in self
._CACHE
_:
556 return os
.path
.join(self
._Root
, Path
)
557 elif UpperPath
in self
._UPPER
_CACHE
_:
558 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
561 def RealPath(File
, Dir
='', OverrideDir
=''):
562 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
563 NewFile
= GlobalData
.gAllFiles
[NewFile
]
564 if not NewFile
and OverrideDir
:
565 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
566 NewFile
= GlobalData
.gAllFiles
[NewFile
]
569 def RealPath2(File
, Dir
='', OverrideDir
=''):
572 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
574 if OverrideDir
[-1] == os
.path
.sep
:
575 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
577 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
578 if GlobalData
.gAllFiles
:
579 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
581 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
582 if not os
.path
.exists(NewFile
):
586 if Dir
[-1] == os
.path
.sep
:
587 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
589 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
595 ## Get GUID value from given packages
597 # @param CName The CName of the GUID
598 # @param PackageList List of packages looking-up in
599 # @param Inffile The driver file
601 # @retval GuidValue if the CName is found in any given package
602 # @retval None if the CName is not found in all given packages
604 def GuidValue(CName
, PackageList
, Inffile
= None):
605 for P
in PackageList
:
606 GuidKeys
= P
.Guids
.keys()
607 if Inffile
and P
._PrivateGuids
:
608 if not Inffile
.startswith(P
.MetaFile
.Dir
):
609 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
610 if CName
in GuidKeys
:
611 return P
.Guids
[CName
]
614 ## A string template class
616 # This class implements a template for string replacement. A string template
617 # looks like following
619 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
621 # The string between ${BEGIN} and ${END} will be repeated as many times as the
622 # length of "placeholder_name", which is a list passed through a dict. The
623 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
624 # be not used and, in this case, the "placeholder_name" must not a list and it
625 # will just be replaced once.
627 class TemplateString(object):
628 _REPEAT_START_FLAG
= "BEGIN"
629 _REPEAT_END_FLAG
= "END"
631 class Section(object):
632 _LIST_TYPES
= [type([]), type(set()), type((0,))]
634 def __init__(self
, TemplateSection
, PlaceHolderList
):
635 self
._Template
= TemplateSection
636 self
._PlaceHolderList
= []
638 # Split the section into sub-sections according to the position of placeholders
640 self
._SubSectionList
= []
643 # The placeholders passed in must be in the format of
645 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
647 for PlaceHolder
, Start
, End
in PlaceHolderList
:
648 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
649 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
650 self
._PlaceHolderList
.append(PlaceHolder
)
651 SubSectionStart
= End
652 if SubSectionStart
< len(TemplateSection
):
653 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
655 self
._SubSectionList
= [TemplateSection
]
658 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
660 def Instantiate(self
, PlaceHolderValues
):
662 RepeatPlaceHolders
= {}
663 NonRepeatPlaceHolders
= {}
665 for PlaceHolder
in self
._PlaceHolderList
:
666 if PlaceHolder
not in PlaceHolderValues
:
668 Value
= PlaceHolderValues
[PlaceHolder
]
669 if type(Value
) in self
._LIST
_TYPES
:
671 RepeatTime
= len(Value
)
672 elif RepeatTime
!= len(Value
):
676 "${%s} has different repeat time from others!" % PlaceHolder
,
677 ExtraData
=str(self
._Template
)
679 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
681 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
683 if NonRepeatPlaceHolders
:
685 for S
in self
._SubSectionList
:
686 if S
not in NonRepeatPlaceHolders
:
689 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
691 StringList
= self
._SubSectionList
693 if RepeatPlaceHolders
:
695 for Index
in range(RepeatTime
):
697 if S
not in RepeatPlaceHolders
:
698 TempStringList
.append(S
)
700 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
701 StringList
= TempStringList
703 return "".join(StringList
)
706 def __init__(self
, Template
=None):
708 self
.IsBinary
= False
709 self
._Template
= Template
710 self
._TemplateSectionList
= self
._Parse
(Template
)
714 # @retval string The string replaced
717 return "".join(self
.String
)
719 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
721 # @retval list A list of TemplateString.Section objects
723 def _Parse(self
, Template
):
728 TemplateSectionList
= []
730 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
732 if MatchEnd
<= len(Template
):
733 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
734 TemplateSectionList
.append(TemplateSection
)
737 MatchString
= MatchObj
.group(1)
738 MatchStart
= MatchObj
.start()
739 MatchEnd
= MatchObj
.end()
741 if MatchString
== self
._REPEAT
_START
_FLAG
:
742 if MatchStart
> SectionStart
:
743 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
744 TemplateSectionList
.append(TemplateSection
)
745 SectionStart
= MatchEnd
747 elif MatchString
== self
._REPEAT
_END
_FLAG
:
748 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
749 TemplateSectionList
.append(TemplateSection
)
750 SectionStart
= MatchEnd
753 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
754 SearchFrom
= MatchEnd
755 return TemplateSectionList
757 ## Replace the string template with dictionary of placeholders and append it to previous one
759 # @param AppendString The string template to append
760 # @param Dictionary The placeholder dictionaries
762 def Append(self
, AppendString
, Dictionary
=None):
764 SectionList
= self
._Parse
(AppendString
)
765 self
.String
.append( "".join(S
.Instantiate(Dictionary
) for S
in SectionList
))
767 if isinstance(AppendString
,list):
768 self
.String
.extend(AppendString
)
770 self
.String
.append(AppendString
)
772 ## Replace the string template with dictionary of placeholders
774 # @param Dictionary The placeholder dictionaries
776 # @retval str The string replaced with placeholder values
778 def Replace(self
, Dictionary
=None):
779 return "".join(S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
)
781 ## Progress indicator class
783 # This class makes use of thread to print progress on console.
786 # for avoiding deadloop
788 _ProgressThread
= None
789 _CheckInterval
= 0.25
793 # @param OpenMessage The string printed before progress charaters
794 # @param CloseMessage The string printed after progress charaters
795 # @param ProgressChar The charater used to indicate the progress
796 # @param Interval The interval in seconds between two progress charaters
798 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
799 self
.PromptMessage
= OpenMessage
800 self
.CodaMessage
= CloseMessage
801 self
.ProgressChar
= ProgressChar
802 self
.Interval
= Interval
803 if Progressor
._StopFlag
is None:
804 Progressor
._StopFlag
= threading
.Event()
806 ## Start to print progress charater
808 # @param OpenMessage The string printed before progress charaters
810 def Start(self
, OpenMessage
=None):
811 if OpenMessage
is not None:
812 self
.PromptMessage
= OpenMessage
813 Progressor
._StopFlag
.clear()
814 if Progressor
._ProgressThread
is None:
815 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
816 Progressor
._ProgressThread
.setDaemon(False)
817 Progressor
._ProgressThread
.start()
819 ## Stop printing progress charater
821 # @param CloseMessage The string printed after progress charaters
823 def Stop(self
, CloseMessage
=None):
824 OriginalCodaMessage
= self
.CodaMessage
825 if CloseMessage
is not None:
826 self
.CodaMessage
= CloseMessage
828 self
.CodaMessage
= OriginalCodaMessage
830 ## Thread entry method
831 def _ProgressThreadEntry(self
):
832 sys
.stdout
.write(self
.PromptMessage
+ " ")
835 while not Progressor
._StopFlag
.isSet():
837 sys
.stdout
.write(self
.ProgressChar
)
839 TimeUp
= self
.Interval
840 time
.sleep(self
._CheckInterval
)
841 TimeUp
-= self
._CheckInterval
842 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
845 ## Abort the progress display
848 if Progressor
._StopFlag
is not None:
849 Progressor
._StopFlag
.set()
850 if Progressor
._ProgressThread
is not None:
851 Progressor
._ProgressThread
.join()
852 Progressor
._ProgressThread
= None
854 ## A dict which can access its keys and/or values orderly
856 # The class implements a new kind of dict which its keys or values can be
857 # accessed in the order they are added into the dict. It guarantees the order
858 # by making use of an internal list to keep a copy of keys.
860 class sdict(IterableUserDict
):
863 IterableUserDict
.__init
__(self
)
867 def __setitem__(self
, key
, value
):
868 if key
not in self
._key
_list
:
869 self
._key
_list
.append(key
)
870 IterableUserDict
.__setitem
__(self
, key
, value
)
873 def __delitem__(self
, key
):
874 self
._key
_list
.remove(key
)
875 IterableUserDict
.__delitem
__(self
, key
)
877 ## used in "for k in dict" loop to ensure the correct order
879 return self
.iterkeys()
883 return len(self
._key
_list
)
886 def __contains__(self
, key
):
887 return key
in self
._key
_list
890 def index(self
, key
):
891 return self
._key
_list
.index(key
)
894 def insert(self
, key
, newkey
, newvalue
, order
):
895 index
= self
._key
_list
.index(key
)
896 if order
== 'BEFORE':
897 self
._key
_list
.insert(index
, newkey
)
898 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
899 elif order
== 'AFTER':
900 self
._key
_list
.insert(index
+ 1, newkey
)
901 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
904 def append(self
, sdict
):
906 if key
not in self
._key
_list
:
907 self
._key
_list
.append(key
)
908 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
910 def has_key(self
, key
):
911 return key
in self
._key
_list
916 IterableUserDict
.clear(self
)
918 ## Return a copy of keys
921 for key
in self
._key
_list
:
925 ## Return a copy of values
928 for key
in self
._key
_list
:
929 values
.append(self
[key
])
932 ## Return a copy of (key, value) list
935 for key
in self
._key
_list
:
936 items
.append((key
, self
[key
]))
941 return iter(self
.items())
943 ## Keys interation support
945 return iter(self
.keys())
947 ## Values interation support
948 def itervalues(self
):
949 return iter(self
.values())
951 ## Return value related to a key, and remove the (key, value) from the dict
952 def pop(self
, key
, *dv
):
954 if key
in self
._key
_list
:
956 self
.__delitem
__(key
)
961 ## Return (key, value) pair, and remove the (key, value) from the dict
963 key
= self
._key
_list
[-1]
965 self
.__delitem
__(key
)
968 def update(self
, dict=None, **kwargs
):
970 for k
, v
in dict.items():
973 for k
, v
in kwargs
.items():
976 ## Dictionary with restricted keys
980 def __init__(self
, KeyList
):
982 dict.__setitem
__(self
, Key
, "")
985 def __setitem__(self
, key
, value
):
987 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
988 ExtraData
=", ".join(dict.keys(self
)))
989 dict.__setitem
__(self
, key
, value
)
992 def __getitem__(self
, key
):
995 return dict.__getitem
__(self
, key
)
998 def __delitem__(self
, key
):
999 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1004 self
.__setitem
__(Key
, "")
1006 ## Return value related to a key, and remove the (key, value) from the dict
1007 def pop(self
, key
, *dv
):
1008 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1010 ## Return (key, value) pair, and remove the (key, value) from the dict
1012 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1014 ## Dictionary using prioritized list as key
1017 _ListType
= type([])
1018 _TupleType
= type(())
1019 _Wildcard
= 'COMMON'
1020 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', TAB_STAR
, 'PLATFORM']
1022 def __init__(self
, _Single_
=False, _Level_
=2):
1023 self
._Level
_ = _Level_
1025 self
._Single
_ = _Single_
1028 def __getitem__(self
, key
):
1031 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1035 elif self
._Level
_ > 1:
1036 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1039 if self
._Level
_ > 1:
1040 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1042 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1043 FirstKey
= self
._Wildcard
1046 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1048 return self
._GetAllValues
(FirstKey
, RestKeys
)
1050 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1052 #print "%s-%s" % (FirstKey, self._Level_) ,
1053 if self
._Level
_ > 1:
1054 if FirstKey
== self
._Wildcard
:
1055 if FirstKey
in self
.data
:
1056 Value
= self
.data
[FirstKey
][RestKeys
]
1058 for Key
in self
.data
:
1059 Value
= self
.data
[Key
][RestKeys
]
1060 if Value
is not None: break
1062 if FirstKey
in self
.data
:
1063 Value
= self
.data
[FirstKey
][RestKeys
]
1064 if Value
is None and self
._Wildcard
in self
.data
:
1066 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1068 if FirstKey
== self
._Wildcard
:
1069 if FirstKey
in self
.data
:
1070 Value
= self
.data
[FirstKey
]
1072 for Key
in self
.data
:
1073 Value
= self
.data
[Key
]
1074 if Value
is not None: break
1076 if FirstKey
in self
.data
:
1077 Value
= self
.data
[FirstKey
]
1078 elif self
._Wildcard
in self
.data
:
1079 Value
= self
.data
[self
._Wildcard
]
1082 def _GetAllValues(self
, FirstKey
, RestKeys
):
1084 if self
._Level
_ > 1:
1085 if FirstKey
== self
._Wildcard
:
1086 for Key
in self
.data
:
1087 Value
+= self
.data
[Key
][RestKeys
]
1089 if FirstKey
in self
.data
:
1090 Value
+= self
.data
[FirstKey
][RestKeys
]
1091 if self
._Wildcard
in self
.data
:
1092 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1094 if FirstKey
== self
._Wildcard
:
1095 for Key
in self
.data
:
1096 Value
.append(self
.data
[Key
])
1098 if FirstKey
in self
.data
:
1099 Value
.append(self
.data
[FirstKey
])
1100 if self
._Wildcard
in self
.data
:
1101 Value
.append(self
.data
[self
._Wildcard
])
1105 def __setitem__(self
, key
, value
):
1108 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1113 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1116 if self
._Level
_ > 1:
1117 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1119 if FirstKey
in self
._ValidWildcardList
:
1120 FirstKey
= self
._Wildcard
1122 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1123 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1125 if self
._Level
_ > 1:
1126 self
.data
[FirstKey
][RestKeys
] = value
1128 self
.data
[FirstKey
] = value
1130 def SetGreedyMode(self
):
1131 self
._Single
_ = False
1132 if self
._Level
_ > 1:
1133 for Key
in self
.data
:
1134 self
.data
[Key
].SetGreedyMode()
1136 def SetSingleMode(self
):
1137 self
._Single
_ = True
1138 if self
._Level
_ > 1:
1139 for Key
in self
.data
:
1140 self
.data
[Key
].SetSingleMode()
1142 def GetKeys(self
, KeyIndex
=0):
1143 assert KeyIndex
>= 0
1145 return set(self
.data
.keys())
1148 for Key
in self
.data
:
1149 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1152 def AnalyzePcdExpression(Setting
):
1153 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
1154 Setting
= Setting
.replace('\\\\', RanStr
).strip()
1155 # There might be escaped quote in a string: \", \\\" , \', \\\'
1157 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1159 InSingleQuoteStr
= False
1160 InDoubleQuoteStr
= False
1162 for Index
, ch
in enumerate(Data
):
1163 if ch
== '"' and not InSingleQuoteStr
:
1164 if Data
[Index
- 1] != '\\':
1165 InDoubleQuoteStr
= not InDoubleQuoteStr
1166 elif ch
== "'" and not InDoubleQuoteStr
:
1167 if Data
[Index
- 1] != '\\':
1168 InSingleQuoteStr
= not InSingleQuoteStr
1169 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1171 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1174 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1181 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1183 FieldList
.append(Setting
[StartPos
:].strip())
1185 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1187 for i
, ch
in enumerate(FieldList
):
1189 FieldList
[i
] = ch
.replace(RanStr
,'\\\\')
1192 def ParseDevPathValue (Value
):
1194 Value
.replace('\\', '/').replace(' ', '')
1196 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1198 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1199 out
, err
= p
.communicate()
1200 except Exception as X
:
1201 raise BadExpression("DevicePath: %s" % (str(X
)) )
1203 subprocess
._cleanup
()
1207 raise BadExpression("DevicePath: %s" % str(err
))
1208 Size
= len(out
.split())
1209 out
= ','.join(out
.split())
1210 return '{' + out
+ '}', Size
1212 def ParseFieldValue (Value
):
1213 if "{CODE(" in Value
:
1214 return Value
, len(Value
.split(","))
1215 if isinstance(Value
, type(0)):
1216 return Value
, (Value
.bit_length() + 7) / 8
1217 if not isinstance(Value
, type('')):
1218 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1219 Value
= Value
.strip()
1220 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1221 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1223 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1225 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1226 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1228 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1230 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1231 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1233 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1235 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1236 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1238 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1240 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1241 Value
= Value
.split('(', 1)[1][:-1].strip()
1242 if Value
[0] == '{' and Value
[-1] == '}':
1243 TmpValue
= GuidStructureStringToGuidString(Value
)
1245 raise BadExpression("Invalid GUID value string %s" % Value
)
1247 if Value
[0] == '"' and Value
[-1] == '"':
1250 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1251 except ValueError as Message
:
1252 raise BadExpression(Message
)
1253 Value
, Size
= ParseFieldValue(Value
)
1255 if Value
.startswith('L"') and Value
.endswith('"'):
1257 # translate escape character
1267 Value
= (Value
<< 16) |
ord(Char
)
1268 return Value
, (len(List
) + 1) * 2
1269 if Value
.startswith('"') and Value
.endswith('"'):
1271 # translate escape character
1280 Value
= (Value
<< 8) |
ord(Char
)
1281 return Value
, len(List
) + 1
1282 if Value
.startswith("L'") and Value
.endswith("'"):
1283 # Unicode Character Constant
1284 # translate escape character
1292 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1296 Value
= (Value
<< 16) |
ord(Char
)
1297 return Value
, len(List
) * 2
1298 if Value
.startswith("'") and Value
.endswith("'"):
1299 # Character constant
1300 # translate escape character
1307 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1311 Value
= (Value
<< 8) |
ord(Char
)
1312 return Value
, len(List
)
1313 if Value
.startswith('{') and Value
.endswith('}'):
1316 List
= [Item
.strip() for Item
in Value
.split(',')]
1321 ItemValue
, Size
= ParseFieldValue(Item
)
1323 for I
in range(Size
):
1324 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1325 return Value
, RetSize
1326 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1327 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1328 Value
= Value
.strip().strip('"')
1329 return ParseDevPathValue(Value
)
1330 if Value
.lower().startswith('0x'):
1332 Value
= int(Value
, 16)
1334 raise BadExpression("invalid hex value: %s" % Value
)
1337 return Value
, (Value
.bit_length() + 7) / 8
1338 if Value
[0].isdigit():
1339 Value
= int(Value
, 10)
1342 return Value
, (Value
.bit_length() + 7) / 8
1343 if Value
.lower() == 'true':
1345 if Value
.lower() == 'false':
1351 # Analyze DSC PCD value, since there is no data type info in DSC
1352 # This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1353 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1354 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1355 # 3. Dynamic default:
1356 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1357 # TokenSpace.PcdCName|PcdValue
1359 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1360 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1362 # TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
1363 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1364 # there might have "|" operator, also in string value.
1366 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1367 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1368 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1370 # ValueList: A List contain fields described above
1371 # IsValid: True if conforming EBNF, otherwise False
1372 # Index: The index where PcdValue is in ValueList
1374 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1375 FieldList
= AnalyzePcdExpression(Setting
)
1378 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1379 Value
= FieldList
[0]
1381 if len(FieldList
) > 1 and FieldList
[1]:
1382 DataType
= FieldList
[1]
1383 if FieldList
[1] != TAB_VOID
and StructPattern
.match(FieldList
[1]) is None:
1385 if len(FieldList
) > 2:
1389 IsValid
= (len(FieldList
) <= 1)
1391 IsValid
= (len(FieldList
) <= 3)
1395 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1399 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1400 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1401 Value
= FieldList
[0]
1403 IsValid
= (len(FieldList
) <= 1)
1404 return [Value
, DataType
, str(Size
)], IsValid
, 0
1405 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1406 VpdOffset
= FieldList
[0]
1408 if not DataType
== TAB_VOID
:
1409 if len(FieldList
) > 1:
1410 Value
= FieldList
[1]
1412 if len(FieldList
) > 1:
1414 if len(FieldList
) > 2:
1415 Value
= FieldList
[2]
1417 IsValid
= (len(FieldList
) <= 1)
1419 IsValid
= (len(FieldList
) <= 3)
1422 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1426 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1427 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1428 IsValid
= (3 <= len(FieldList
) <= 5)
1429 HiiString
= FieldList
[0]
1430 Guid
= Offset
= Value
= Attribute
= ''
1431 if len(FieldList
) > 1:
1433 if len(FieldList
) > 2:
1434 Offset
= FieldList
[2]
1435 if len(FieldList
) > 3:
1436 Value
= FieldList
[3]
1437 if len(FieldList
) > 4:
1438 Attribute
= FieldList
[4]
1439 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1444 # Analyze the pcd Value, Datum type and TokenNumber.
1445 # Used to avoid split issue while the value string contain "|" character
1447 # @param[in] Setting: A String contain value/datum type/token number information;
1449 # @retval ValueList: A List contain value, datum type and toke number.
1451 def AnalyzePcdData(Setting
):
1452 ValueList
= ['', '', '']
1454 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1455 PtrValue
= ValueRe
.findall(Setting
)
1457 ValueUpdateFlag
= False
1459 if len(PtrValue
) >= 1:
1460 Setting
= re
.sub(ValueRe
, '', Setting
)
1461 ValueUpdateFlag
= True
1463 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1464 ValueList
[0:len(TokenList
)] = TokenList
1467 ValueList
[0] = PtrValue
[0]
1471 ## check format of PCD value against its the datum type
1473 # For PCD value setting
1475 def CheckPcdDatum(Type
, Value
):
1476 if Type
== TAB_VOID
:
1477 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1478 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1479 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1481 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1482 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1483 elif ValueRe
.match(Value
):
1484 # Check the chars in UnicodeString or CString is printable
1485 if Value
.startswith("L"):
1489 Printset
= set(string
.printable
)
1490 Printset
.remove(TAB_PRINTCHAR_VT
)
1491 Printset
.add(TAB_PRINTCHAR_BS
)
1492 Printset
.add(TAB_PRINTCHAR_NUL
)
1493 if not set(Value
).issubset(Printset
):
1494 PrintList
= sorted(Printset
)
1495 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1496 elif Type
== 'BOOLEAN':
1497 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1498 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1499 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1500 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1501 if Value
and int(Value
, 0) < 0:
1502 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value
, Type
)
1504 Value
= long(Value
, 0)
1505 if Value
> MAX_VAL_TYPE
[Type
]:
1506 return False, "Too large PCD value[%s] for datum type [%s]" % (Value
, Type
)
1508 return False, "Invalid value [%s] of type [%s];"\
1509 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1511 return True, "StructurePcd"
1515 ## Split command line option string to list
1517 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1518 # in non-windows platform to launch command
1520 def SplitOption(OptionString
):
1525 for Index
in range(0, len(OptionString
)):
1526 CurrentChar
= OptionString
[Index
]
1527 if CurrentChar
in ['"', "'"]:
1528 if QuotationMark
== CurrentChar
:
1530 elif QuotationMark
== "":
1531 QuotationMark
= CurrentChar
1536 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1537 if Index
> OptionStart
:
1538 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1540 LastChar
= CurrentChar
1541 OptionList
.append(OptionString
[OptionStart
:])
1544 def CommonPath(PathList
):
1545 P1
= min(PathList
).split(os
.path
.sep
)
1546 P2
= max(PathList
).split(os
.path
.sep
)
1547 for Index
in xrange(min(len(P1
), len(P2
))):
1548 if P1
[Index
] != P2
[Index
]:
1549 return os
.path
.sep
.join(P1
[:Index
])
1550 return os
.path
.sep
.join(P1
)
1553 # Convert string to C format array
1555 def ConvertStringToByteArray(Value
):
1556 Value
= Value
.strip()
1560 if not Value
.endswith('}'):
1562 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1563 ValFields
= Value
.split(',')
1565 for Index
in range(len(ValFields
)):
1566 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1569 Value
= '{' + ','.join(ValFields
) + '}'
1573 if Value
.startswith('L"'):
1574 if not Value
.endswith('"'):
1578 elif not Value
.startswith('"') or not Value
.endswith('"'):
1581 Value
= eval(Value
) # translate escape character
1583 for Index
in range(0, len(Value
)):
1585 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1587 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1588 Value
= NewValue
+ '0}'
1591 class PathClass(object):
1592 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1593 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1595 self
.File
= str(File
)
1596 if os
.path
.isabs(self
.File
):
1600 self
.Root
= str(Root
)
1601 self
.AlterRoot
= str(AlterRoot
)
1603 # Remove any '.' and '..' in path
1605 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1606 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1607 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1608 # eliminate the side-effect of 'C:'
1609 if self
.Root
[-1] == ':':
1610 self
.Root
+= os
.path
.sep
1611 # file path should not start with path separator
1612 if self
.Root
[-1] == os
.path
.sep
:
1613 self
.File
= self
.Path
[len(self
.Root
):]
1615 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1617 self
.Path
= os
.path
.normpath(self
.File
)
1619 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1620 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1624 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1626 self
.Dir
= self
.Root
1628 self
.Dir
= self
.SubDir
1633 self
.Type
= self
.Ext
.lower()
1635 self
.IsBinary
= IsBinary
1636 self
.Target
= Target
1637 self
.TagName
= TagName
1638 self
.ToolCode
= ToolCode
1639 self
.ToolChainFamily
= ToolChainFamily
1641 ## Convert the object of this class to a string
1643 # Convert member Path of the class to a string
1645 # @retval string Formatted String
1650 ## Override __eq__ function
1652 # Check whether PathClass are the same
1654 # @retval False The two PathClass are different
1655 # @retval True The two PathClass are the same
1657 def __eq__(self
, Other
):
1658 return self
.Path
== str(Other
)
1660 ## Override __cmp__ function
1662 # Customize the comparsion operation of two PathClass
1664 # @retval 0 The two PathClass are different
1665 # @retval -1 The first PathClass is less than the second PathClass
1666 # @retval 1 The first PathClass is Bigger than the second PathClass
1667 def __cmp__(self
, Other
):
1668 OtherKey
= str(Other
)
1671 if SelfKey
== OtherKey
:
1673 elif SelfKey
> OtherKey
:
1678 ## Override __hash__ function
1680 # Use Path as key in hash table
1682 # @retval string Key for hash table
1685 return hash(self
.Path
)
1689 return self
.Path
.upper()
1692 def TimeStamp(self
):
1693 return os
.stat(self
.Path
)[8]
1695 def Validate(self
, Type
='', CaseSensitive
=True):
1696 if GlobalData
.gCaseInsensitive
:
1697 CaseSensitive
= False
1698 if Type
and Type
.lower() != self
.Type
:
1699 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1701 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1702 if not RealRoot
and not RealFile
:
1703 RealFile
= self
.File
1705 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1707 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1708 if len (mws
.getPkgPath()) == 0:
1709 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1711 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1715 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1716 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1717 ErrorCode
= FILE_CASE_MISMATCH
1718 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1720 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1721 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1723 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1726 self
.File
= RealFile
1727 self
.Root
= RealRoot
1728 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1729 return ErrorCode
, ErrorInfo
1731 ## Parse PE image to get the required PE informaion.
1733 class PeImageClass():
1736 # @param File FilePath of PeImage
1738 def __init__(self
, PeFile
):
1739 self
.FileName
= PeFile
1740 self
.IsValid
= False
1743 self
.SectionAlignment
= 0
1744 self
.SectionHeaderList
= []
1747 PeObject
= open(PeFile
, 'rb')
1749 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1752 ByteArray
= array
.array('B')
1753 ByteArray
.fromfile(PeObject
, 0x3E)
1754 ByteList
= ByteArray
.tolist()
1755 # DOS signature should be 'MZ'
1756 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1757 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1760 # Read 4 byte PE Signature
1761 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1762 PeObject
.seek(PeOffset
)
1763 ByteArray
= array
.array('B')
1764 ByteArray
.fromfile(PeObject
, 4)
1765 # PE signature should be 'PE\0\0'
1766 if ByteArray
.tostring() != 'PE\0\0':
1767 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1770 # Read PE file header
1771 ByteArray
= array
.array('B')
1772 ByteArray
.fromfile(PeObject
, 0x14)
1773 ByteList
= ByteArray
.tolist()
1774 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1776 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1779 # Read PE optional header
1780 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1781 ByteArray
= array
.array('B')
1782 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1783 ByteList
= ByteArray
.tolist()
1784 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1785 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1786 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1788 # Read each Section Header
1789 for Index
in range(SecNumber
):
1790 ByteArray
= array
.array('B')
1791 ByteArray
.fromfile(PeObject
, 0x28)
1792 ByteList
= ByteArray
.tolist()
1793 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1794 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1795 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1796 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1797 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1801 def _ByteListToStr(self
, ByteList
):
1803 for index
in range(len(ByteList
)):
1804 if ByteList
[index
] == 0:
1806 String
+= chr(ByteList
[index
])
1809 def _ByteListToInt(self
, ByteList
):
1811 for index
in range(len(ByteList
) - 1, -1, -1):
1812 Value
= (Value
<< 8) |
int(ByteList
[index
])
1815 class DefaultStore():
1816 def __init__(self
, DefaultStores
):
1818 self
.DefaultStores
= DefaultStores
1819 def DefaultStoreID(self
, DefaultStoreName
):
1820 for key
, value
in self
.DefaultStores
.items():
1821 if value
== DefaultStoreName
:
1824 def GetDefaultDefault(self
):
1825 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1826 return "0", TAB_DEFAULT_STORES_DEFAULT
1828 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1829 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1830 def GetMin(self
, DefaultSIdList
):
1831 if not DefaultSIdList
:
1832 return TAB_DEFAULT_STORES_DEFAULT
1833 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1836 minid
= min(storeidset
)
1837 for sid
, name
in self
.DefaultStores
.values():
1846 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1850 for SkuName
in SkuIds
:
1851 SkuId
= SkuIds
[SkuName
][0]
1852 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1853 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1854 EdkLogger
.error("build", PARAMETER_INVALID
,
1855 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1858 self
.AvailableSkuIds
= sdict()
1860 self
.SkuIdNumberSet
= []
1861 self
.SkuData
= SkuIds
1862 self
._SkuInherit
= {}
1863 self
._SkuIdentifier
= SkuIdentifier
1864 if SkuIdentifier
== '' or SkuIdentifier
is None:
1865 self
.SkuIdSet
= ['DEFAULT']
1866 self
.SkuIdNumberSet
= ['0U']
1867 elif SkuIdentifier
== 'ALL':
1868 self
.SkuIdSet
= SkuIds
.keys()
1869 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1871 r
= SkuIdentifier
.split('|')
1872 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1875 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1877 EdkLogger
.error("build", PARAMETER_INVALID
,
1878 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1879 % (k
, " | ".join(SkuIds
.keys())))
1880 for each
in self
.SkuIdSet
:
1882 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1884 EdkLogger
.error("build", PARAMETER_INVALID
,
1885 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1886 % (each
, " | ".join(SkuIds
.keys())))
1887 if self
.SkuUsageType
!= SkuClass
.SINGLE
:
1888 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1890 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1891 if 'COMMON' in GlobalData
.gSkuids
:
1892 GlobalData
.gSkuids
.remove('COMMON')
1893 if self
.SkuUsageType
== self
.SINGLE
:
1894 if len(GlobalData
.gSkuids
) != 1:
1895 if 'DEFAULT' in GlobalData
.gSkuids
:
1896 GlobalData
.gSkuids
.remove('DEFAULT')
1897 if GlobalData
.gSkuids
:
1898 GlobalData
.gSkuids
.sort()
1900 def GetNextSkuId(self
, skuname
):
1901 if not self
._SkuInherit
:
1902 self
._SkuInherit
= {}
1903 for item
in self
.SkuData
.values():
1904 self
._SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1905 return self
._SkuInherit
.get(skuname
, "DEFAULT")
1907 def GetSkuChain(self
, sku
):
1908 if sku
== "DEFAULT":
1913 nextsku
= self
.GetNextSkuId(nextsku
)
1914 skulist
.append(nextsku
)
1915 if nextsku
== "DEFAULT":
1919 def SkuOverrideOrder(self
):
1921 for skuname
in self
.SkuIdSet
:
1922 skuorderset
.append(self
.GetSkuChain(skuname
))
1925 for index
in range(max(len(item
) for item
in skuorderset
)):
1926 for subset
in skuorderset
:
1927 if index
> len(subset
)-1:
1929 if subset
[index
] in skuorder
:
1931 skuorder
.append(subset
[index
])
1936 def SkuUsageType(self
):
1937 if self
._SkuIdentifier
.upper() == "ALL":
1938 return SkuClass
.MULTIPLE
1940 if len(self
.SkuIdSet
) == 1:
1941 if self
.SkuIdSet
[0] == 'DEFAULT':
1942 return SkuClass
.DEFAULT
1943 return SkuClass
.SINGLE
1944 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
:
1945 return SkuClass
.SINGLE
1946 return SkuClass
.MULTIPLE
1948 def DumpSkuIdArrary(self
):
1949 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1952 for skuname
in self
.AvailableSkuIds
:
1953 if skuname
== "COMMON":
1955 while skuname
!= "DEFAULT":
1956 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
1957 skuname
= self
.GetNextSkuId(skuname
)
1958 ArrayStrList
.append("0x0")
1959 return "{{{myList}}}".format(myList
=",".join(ArrayStrList
))
1962 def AvailableSkuIdSet(self
):
1963 return self
.AvailableSkuIds
1966 def SystemSkuId(self
):
1967 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1968 if len(self
.SkuIdSet
) == 1:
1969 return self
.SkuIdSet
[0]
1971 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
1976 # Pack a registry format GUID
1978 def PackRegistryFormatGuid(Guid
):
1979 return PackGUID(Guid
.split('-'))
1981 ## Get the integer value from string like "14U" or integer like 2
1983 # @param Input The object that may be either a integer value or a string
1985 # @retval Value The integer value that the input represents
1987 def GetIntegerValue(Input
):
1988 if type(Input
) in (int, long):
1991 if String
.endswith("U"):
1992 String
= String
[:-1]
1993 if String
.endswith("ULL"):
1994 String
= String
[:-3]
1995 if String
.endswith("LL"):
1996 String
= String
[:-2]
1998 if String
.startswith("0x") or String
.startswith("0X"):
1999 return int(String
, 16)
2006 # Pack a GUID (registry format) list into a buffer and return it
2009 return pack(PACK_PATTERN_GUID
,
2013 int(Guid
[3][-4:-2], 16),
2014 int(Guid
[3][-2:], 16),
2015 int(Guid
[4][-12:-10], 16),
2016 int(Guid
[4][-10:-8], 16),
2017 int(Guid
[4][-8:-6], 16),
2018 int(Guid
[4][-6:-4], 16),
2019 int(Guid
[4][-4:-2], 16),
2020 int(Guid
[4][-2:], 16)
2024 # Pack a GUID (byte) list into a buffer and return it
2026 def PackByteFormatGUID(Guid
):
2027 return pack(PACK_PATTERN_GUID
,
2041 ## DeepCopy dict/OrderedDict recusively
2043 # @param ori_dict a nested dict or ordereddict
2045 # @retval new dict or orderdict
2047 def CopyDict(ori_dict
):
2048 dict_type
= ori_dict
.__class
__
2049 if dict_type
not in (dict,OrderedDict
):
2051 new_dict
= dict_type()
2052 for key
in ori_dict
:
2053 if isinstance(ori_dict
[key
],(dict,OrderedDict
)):
2054 new_dict
[key
] = CopyDict(ori_dict
[key
])
2056 new_dict
[key
] = ori_dict
[key
]
2060 # Remove the c/c++ comments: // and /* */
2062 def RemoveCComments(ctext
):
2063 return re
.sub('//.*?\n|/\*.*?\*/', '\n', ctext
, flags
=re
.S
)
2066 # This acts like the main() function for the script, unless it is 'import'ed into another
2069 if __name__
== '__main__':