2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
27 from 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 IsFieldValueAnArray (Value
):
1153 Value
= Value
.strip()
1154 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1156 if Value
.startswith('L"') and Value
.endswith('"') and len(list(Value
[2:-1])) > 1:
1158 if Value
[0] == '"' and Value
[-1] == '"' and len(list(Value
[1:-1])) > 1:
1160 if Value
[0] == '{' and Value
[-1] == '}':
1162 if Value
.startswith("L'") and Value
.endswith("'") and len(list(Value
[2:-1])) > 1:
1164 if Value
[0] == "'" and Value
[-1] == "'" and len(list(Value
[1:-1])) > 1:
1168 def AnalyzePcdExpression(Setting
):
1169 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
1170 Setting
= Setting
.replace('\\\\', RanStr
).strip()
1171 # There might be escaped quote in a string: \", \\\" , \', \\\'
1173 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1175 InSingleQuoteStr
= False
1176 InDoubleQuoteStr
= False
1178 for Index
, ch
in enumerate(Data
):
1179 if ch
== '"' and not InSingleQuoteStr
:
1180 if Data
[Index
- 1] != '\\':
1181 InDoubleQuoteStr
= not InDoubleQuoteStr
1182 elif ch
== "'" and not InDoubleQuoteStr
:
1183 if Data
[Index
- 1] != '\\':
1184 InSingleQuoteStr
= not InSingleQuoteStr
1185 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1187 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1190 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1197 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1199 FieldList
.append(Setting
[StartPos
:].strip())
1201 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1203 for i
, ch
in enumerate(FieldList
):
1205 FieldList
[i
] = ch
.replace(RanStr
,'\\\\')
1208 def ParseDevPathValue (Value
):
1210 Value
.replace('\\', '/').replace(' ', '')
1212 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1214 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1215 out
, err
= p
.communicate()
1216 except Exception as X
:
1217 raise BadExpression("DevicePath: %s" % (str(X
)) )
1219 subprocess
._cleanup
()
1223 raise BadExpression("DevicePath: %s" % str(err
))
1224 Size
= len(out
.split())
1225 out
= ','.join(out
.split())
1226 return '{' + out
+ '}', Size
1228 def ParseFieldValue (Value
):
1229 if "{CODE(" in Value
:
1230 return Value
, len(Value
.split(","))
1231 if isinstance(Value
, type(0)):
1232 return Value
, (Value
.bit_length() + 7) / 8
1233 if not isinstance(Value
, type('')):
1234 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1235 Value
= Value
.strip()
1236 if Value
.startswith(TAB_UINT8
) and Value
.endswith(')'):
1237 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1239 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1241 if Value
.startswith(TAB_UINT16
) and Value
.endswith(')'):
1242 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1244 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1246 if Value
.startswith(TAB_UINT32
) and Value
.endswith(')'):
1247 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1249 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1251 if Value
.startswith(TAB_UINT64
) and Value
.endswith(')'):
1252 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1254 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1256 if Value
.startswith(TAB_GUID
) and Value
.endswith(')'):
1257 Value
= Value
.split('(', 1)[1][:-1].strip()
1258 if Value
[0] == '{' and Value
[-1] == '}':
1259 TmpValue
= GuidStructureStringToGuidString(Value
)
1261 raise BadExpression("Invalid GUID value string %s" % Value
)
1263 if Value
[0] == '"' and Value
[-1] == '"':
1266 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1267 except ValueError as Message
:
1268 raise BadExpression(Message
)
1269 Value
, Size
= ParseFieldValue(Value
)
1271 if Value
.startswith('L"') and Value
.endswith('"'):
1273 # translate escape character
1283 Value
= (Value
<< 16) |
ord(Char
)
1284 return Value
, (len(List
) + 1) * 2
1285 if Value
.startswith('"') and Value
.endswith('"'):
1287 # translate escape character
1296 Value
= (Value
<< 8) |
ord(Char
)
1297 return Value
, len(List
) + 1
1298 if Value
.startswith("L'") and Value
.endswith("'"):
1299 # Unicode Character Constant
1300 # translate escape character
1308 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1312 Value
= (Value
<< 16) |
ord(Char
)
1313 return Value
, len(List
) * 2
1314 if Value
.startswith("'") and Value
.endswith("'"):
1315 # Character constant
1316 # translate escape character
1323 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1327 Value
= (Value
<< 8) |
ord(Char
)
1328 return Value
, len(List
)
1329 if Value
.startswith('{') and Value
.endswith('}'):
1332 List
= [Item
.strip() for Item
in Value
.split(',')]
1337 ItemValue
, Size
= ParseFieldValue(Item
)
1339 for I
in range(Size
):
1340 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1341 return Value
, RetSize
1342 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1343 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1344 Value
= Value
.strip().strip('"')
1345 return ParseDevPathValue(Value
)
1346 if Value
.lower().startswith('0x'):
1348 Value
= int(Value
, 16)
1350 raise BadExpression("invalid hex value: %s" % Value
)
1353 return Value
, (Value
.bit_length() + 7) / 8
1354 if Value
[0].isdigit():
1355 Value
= int(Value
, 10)
1358 return Value
, (Value
.bit_length() + 7) / 8
1359 if Value
.lower() == 'true':
1361 if Value
.lower() == 'false':
1367 # Analyze DSC PCD value, since there is no data type info in DSC
1368 # This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1369 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1370 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1371 # 3. Dynamic default:
1372 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1373 # TokenSpace.PcdCName|PcdValue
1375 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1376 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1378 # TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
1379 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1380 # there might have "|" operator, also in string value.
1382 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1383 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1384 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1386 # ValueList: A List contain fields described above
1387 # IsValid: True if conforming EBNF, otherwise False
1388 # Index: The index where PcdValue is in ValueList
1390 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1391 FieldList
= AnalyzePcdExpression(Setting
)
1394 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1395 Value
= FieldList
[0]
1397 if len(FieldList
) > 1 and FieldList
[1]:
1398 DataType
= FieldList
[1]
1399 if FieldList
[1] != TAB_VOID
and StructPattern
.match(FieldList
[1]) is None:
1401 if len(FieldList
) > 2:
1405 IsValid
= (len(FieldList
) <= 1)
1407 IsValid
= (len(FieldList
) <= 3)
1411 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1415 return [str(Value
), DataType
, str(Size
)], IsValid
, 0
1416 elif PcdType
== MODEL_PCD_FEATURE_FLAG
:
1417 Value
= FieldList
[0]
1419 IsValid
= (len(FieldList
) <= 1)
1420 return [Value
, DataType
, str(Size
)], IsValid
, 0
1421 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1422 VpdOffset
= FieldList
[0]
1424 if not DataType
== TAB_VOID
:
1425 if len(FieldList
) > 1:
1426 Value
= FieldList
[1]
1428 if len(FieldList
) > 1:
1430 if len(FieldList
) > 2:
1431 Value
= FieldList
[2]
1433 IsValid
= (len(FieldList
) <= 1)
1435 IsValid
= (len(FieldList
) <= 3)
1438 int(Size
, 16) if Size
.upper().startswith("0X") else int(Size
)
1442 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1443 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1444 IsValid
= (3 <= len(FieldList
) <= 5)
1445 HiiString
= FieldList
[0]
1446 Guid
= Offset
= Value
= Attribute
= ''
1447 if len(FieldList
) > 1:
1449 if len(FieldList
) > 2:
1450 Offset
= FieldList
[2]
1451 if len(FieldList
) > 3:
1452 Value
= FieldList
[3]
1453 if len(FieldList
) > 4:
1454 Attribute
= FieldList
[4]
1455 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1460 # Analyze the pcd Value, Datum type and TokenNumber.
1461 # Used to avoid split issue while the value string contain "|" character
1463 # @param[in] Setting: A String contain value/datum type/token number information;
1465 # @retval ValueList: A List contain value, datum type and toke number.
1467 def AnalyzePcdData(Setting
):
1468 ValueList
= ['', '', '']
1470 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1471 PtrValue
= ValueRe
.findall(Setting
)
1473 ValueUpdateFlag
= False
1475 if len(PtrValue
) >= 1:
1476 Setting
= re
.sub(ValueRe
, '', Setting
)
1477 ValueUpdateFlag
= True
1479 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1480 ValueList
[0:len(TokenList
)] = TokenList
1483 ValueList
[0] = PtrValue
[0]
1487 ## check format of PCD value against its the datum type
1489 # For PCD value setting
1491 def CheckPcdDatum(Type
, Value
):
1492 if Type
== TAB_VOID
:
1493 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1494 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1495 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1497 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1498 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1499 elif ValueRe
.match(Value
):
1500 # Check the chars in UnicodeString or CString is printable
1501 if Value
.startswith("L"):
1505 Printset
= set(string
.printable
)
1506 Printset
.remove(TAB_PRINTCHAR_VT
)
1507 Printset
.add(TAB_PRINTCHAR_BS
)
1508 Printset
.add(TAB_PRINTCHAR_NUL
)
1509 if not set(Value
).issubset(Printset
):
1510 PrintList
= sorted(Printset
)
1511 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1512 elif Type
== 'BOOLEAN':
1513 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1514 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1515 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1516 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1517 if Value
and int(Value
, 0) < 0:
1518 return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value
, Type
)
1520 Value
= long(Value
, 0)
1521 if Value
> MAX_VAL_TYPE
[Type
]:
1522 return False, "Too large PCD value[%s] for datum type [%s]" % (Value
, Type
)
1524 return False, "Invalid value [%s] of type [%s];"\
1525 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1527 return True, "StructurePcd"
1531 ## Split command line option string to list
1533 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1534 # in non-windows platform to launch command
1536 def SplitOption(OptionString
):
1541 for Index
in range(0, len(OptionString
)):
1542 CurrentChar
= OptionString
[Index
]
1543 if CurrentChar
in ['"', "'"]:
1544 if QuotationMark
== CurrentChar
:
1546 elif QuotationMark
== "":
1547 QuotationMark
= CurrentChar
1552 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1553 if Index
> OptionStart
:
1554 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1556 LastChar
= CurrentChar
1557 OptionList
.append(OptionString
[OptionStart
:])
1560 def CommonPath(PathList
):
1561 P1
= min(PathList
).split(os
.path
.sep
)
1562 P2
= max(PathList
).split(os
.path
.sep
)
1563 for Index
in xrange(min(len(P1
), len(P2
))):
1564 if P1
[Index
] != P2
[Index
]:
1565 return os
.path
.sep
.join(P1
[:Index
])
1566 return os
.path
.sep
.join(P1
)
1569 # Convert string to C format array
1571 def ConvertStringToByteArray(Value
):
1572 Value
= Value
.strip()
1576 if not Value
.endswith('}'):
1578 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1579 ValFields
= Value
.split(',')
1581 for Index
in range(len(ValFields
)):
1582 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1585 Value
= '{' + ','.join(ValFields
) + '}'
1589 if Value
.startswith('L"'):
1590 if not Value
.endswith('"'):
1594 elif not Value
.startswith('"') or not Value
.endswith('"'):
1597 Value
= eval(Value
) # translate escape character
1599 for Index
in range(0, len(Value
)):
1601 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1603 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1604 Value
= NewValue
+ '0}'
1607 class PathClass(object):
1608 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1609 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1611 self
.File
= str(File
)
1612 if os
.path
.isabs(self
.File
):
1616 self
.Root
= str(Root
)
1617 self
.AlterRoot
= str(AlterRoot
)
1619 # Remove any '.' and '..' in path
1621 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1622 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1623 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1624 # eliminate the side-effect of 'C:'
1625 if self
.Root
[-1] == ':':
1626 self
.Root
+= os
.path
.sep
1627 # file path should not start with path separator
1628 if self
.Root
[-1] == os
.path
.sep
:
1629 self
.File
= self
.Path
[len(self
.Root
):]
1631 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1633 self
.Path
= os
.path
.normpath(self
.File
)
1635 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1636 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1640 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1642 self
.Dir
= self
.Root
1644 self
.Dir
= self
.SubDir
1649 self
.Type
= self
.Ext
.lower()
1651 self
.IsBinary
= IsBinary
1652 self
.Target
= Target
1653 self
.TagName
= TagName
1654 self
.ToolCode
= ToolCode
1655 self
.ToolChainFamily
= ToolChainFamily
1657 ## Convert the object of this class to a string
1659 # Convert member Path of the class to a string
1661 # @retval string Formatted String
1666 ## Override __eq__ function
1668 # Check whether PathClass are the same
1670 # @retval False The two PathClass are different
1671 # @retval True The two PathClass are the same
1673 def __eq__(self
, Other
):
1674 return self
.Path
== str(Other
)
1676 ## Override __cmp__ function
1678 # Customize the comparsion operation of two PathClass
1680 # @retval 0 The two PathClass are different
1681 # @retval -1 The first PathClass is less than the second PathClass
1682 # @retval 1 The first PathClass is Bigger than the second PathClass
1683 def __cmp__(self
, Other
):
1684 OtherKey
= str(Other
)
1687 if SelfKey
== OtherKey
:
1689 elif SelfKey
> OtherKey
:
1694 ## Override __hash__ function
1696 # Use Path as key in hash table
1698 # @retval string Key for hash table
1701 return hash(self
.Path
)
1705 return self
.Path
.upper()
1708 def TimeStamp(self
):
1709 return os
.stat(self
.Path
)[8]
1711 def Validate(self
, Type
='', CaseSensitive
=True):
1712 if GlobalData
.gCaseInsensitive
:
1713 CaseSensitive
= False
1714 if Type
and Type
.lower() != self
.Type
:
1715 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1717 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1718 if not RealRoot
and not RealFile
:
1719 RealFile
= self
.File
1721 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1723 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1724 if len (mws
.getPkgPath()) == 0:
1725 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1727 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1731 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1732 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1733 ErrorCode
= FILE_CASE_MISMATCH
1734 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1736 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1737 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1739 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1742 self
.File
= RealFile
1743 self
.Root
= RealRoot
1744 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1745 return ErrorCode
, ErrorInfo
1747 ## Parse PE image to get the required PE informaion.
1749 class PeImageClass():
1752 # @param File FilePath of PeImage
1754 def __init__(self
, PeFile
):
1755 self
.FileName
= PeFile
1756 self
.IsValid
= False
1759 self
.SectionAlignment
= 0
1760 self
.SectionHeaderList
= []
1763 PeObject
= open(PeFile
, 'rb')
1765 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1768 ByteArray
= array
.array('B')
1769 ByteArray
.fromfile(PeObject
, 0x3E)
1770 ByteList
= ByteArray
.tolist()
1771 # DOS signature should be 'MZ'
1772 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1773 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1776 # Read 4 byte PE Signature
1777 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1778 PeObject
.seek(PeOffset
)
1779 ByteArray
= array
.array('B')
1780 ByteArray
.fromfile(PeObject
, 4)
1781 # PE signature should be 'PE\0\0'
1782 if ByteArray
.tostring() != 'PE\0\0':
1783 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1786 # Read PE file header
1787 ByteArray
= array
.array('B')
1788 ByteArray
.fromfile(PeObject
, 0x14)
1789 ByteList
= ByteArray
.tolist()
1790 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1792 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1795 # Read PE optional header
1796 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1797 ByteArray
= array
.array('B')
1798 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1799 ByteList
= ByteArray
.tolist()
1800 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1801 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1802 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1804 # Read each Section Header
1805 for Index
in range(SecNumber
):
1806 ByteArray
= array
.array('B')
1807 ByteArray
.fromfile(PeObject
, 0x28)
1808 ByteList
= ByteArray
.tolist()
1809 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1810 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1811 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1812 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1813 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1817 def _ByteListToStr(self
, ByteList
):
1819 for index
in range(len(ByteList
)):
1820 if ByteList
[index
] == 0:
1822 String
+= chr(ByteList
[index
])
1825 def _ByteListToInt(self
, ByteList
):
1827 for index
in range(len(ByteList
) - 1, -1, -1):
1828 Value
= (Value
<< 8) |
int(ByteList
[index
])
1831 class DefaultStore():
1832 def __init__(self
, DefaultStores
):
1834 self
.DefaultStores
= DefaultStores
1835 def DefaultStoreID(self
, DefaultStoreName
):
1836 for key
, value
in self
.DefaultStores
.items():
1837 if value
== DefaultStoreName
:
1840 def GetDefaultDefault(self
):
1841 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1842 return "0", TAB_DEFAULT_STORES_DEFAULT
1844 minvalue
= min(int(value_str
) for value_str
in self
.DefaultStores
)
1845 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1846 def GetMin(self
, DefaultSIdList
):
1847 if not DefaultSIdList
:
1848 return TAB_DEFAULT_STORES_DEFAULT
1849 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1852 minid
= min(storeidset
)
1853 for sid
, name
in self
.DefaultStores
.values():
1862 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1866 for SkuName
in SkuIds
:
1867 SkuId
= SkuIds
[SkuName
][0]
1868 skuid_num
= int(SkuId
, 16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1869 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1870 EdkLogger
.error("build", PARAMETER_INVALID
,
1871 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1874 self
.AvailableSkuIds
= sdict()
1876 self
.SkuIdNumberSet
= []
1877 self
.SkuData
= SkuIds
1878 self
._SkuInherit
= {}
1879 self
._SkuIdentifier
= SkuIdentifier
1880 if SkuIdentifier
== '' or SkuIdentifier
is None:
1881 self
.SkuIdSet
= ['DEFAULT']
1882 self
.SkuIdNumberSet
= ['0U']
1883 elif SkuIdentifier
== 'ALL':
1884 self
.SkuIdSet
= SkuIds
.keys()
1885 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1887 r
= SkuIdentifier
.split('|')
1888 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1891 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1893 EdkLogger
.error("build", PARAMETER_INVALID
,
1894 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1895 % (k
, " | ".join(SkuIds
.keys())))
1896 for each
in self
.SkuIdSet
:
1898 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1900 EdkLogger
.error("build", PARAMETER_INVALID
,
1901 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1902 % (each
, " | ".join(SkuIds
.keys())))
1903 if self
.SkuUsageType
!= SkuClass
.SINGLE
:
1904 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1906 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1907 if 'COMMON' in GlobalData
.gSkuids
:
1908 GlobalData
.gSkuids
.remove('COMMON')
1909 if self
.SkuUsageType
== self
.SINGLE
:
1910 if len(GlobalData
.gSkuids
) != 1:
1911 if 'DEFAULT' in GlobalData
.gSkuids
:
1912 GlobalData
.gSkuids
.remove('DEFAULT')
1913 if GlobalData
.gSkuids
:
1914 GlobalData
.gSkuids
.sort()
1916 def GetNextSkuId(self
, skuname
):
1917 if not self
._SkuInherit
:
1918 self
._SkuInherit
= {}
1919 for item
in self
.SkuData
.values():
1920 self
._SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1921 return self
._SkuInherit
.get(skuname
, "DEFAULT")
1923 def GetSkuChain(self
, sku
):
1924 if sku
== "DEFAULT":
1929 nextsku
= self
.GetNextSkuId(nextsku
)
1930 skulist
.append(nextsku
)
1931 if nextsku
== "DEFAULT":
1935 def SkuOverrideOrder(self
):
1937 for skuname
in self
.SkuIdSet
:
1938 skuorderset
.append(self
.GetSkuChain(skuname
))
1941 for index
in range(max(len(item
) for item
in skuorderset
)):
1942 for subset
in skuorderset
:
1943 if index
> len(subset
)-1:
1945 if subset
[index
] in skuorder
:
1947 skuorder
.append(subset
[index
])
1952 def SkuUsageType(self
):
1953 if self
._SkuIdentifier
.upper() == "ALL":
1954 return SkuClass
.MULTIPLE
1956 if len(self
.SkuIdSet
) == 1:
1957 if self
.SkuIdSet
[0] == 'DEFAULT':
1958 return SkuClass
.DEFAULT
1959 return SkuClass
.SINGLE
1960 if len(self
.SkuIdSet
) == 2 and 'DEFAULT' in self
.SkuIdSet
:
1961 return SkuClass
.SINGLE
1962 return SkuClass
.MULTIPLE
1964 def DumpSkuIdArrary(self
):
1965 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1968 for skuname
in self
.AvailableSkuIds
:
1969 if skuname
== "COMMON":
1971 while skuname
!= "DEFAULT":
1972 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
1973 skuname
= self
.GetNextSkuId(skuname
)
1974 ArrayStrList
.append("0x0")
1975 return "{{{myList}}}".format(myList
=",".join(ArrayStrList
))
1978 def AvailableSkuIdSet(self
):
1979 return self
.AvailableSkuIds
1982 def SystemSkuId(self
):
1983 if self
.SkuUsageType
== SkuClass
.SINGLE
:
1984 if len(self
.SkuIdSet
) == 1:
1985 return self
.SkuIdSet
[0]
1987 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
1992 # Pack a registry format GUID
1994 def PackRegistryFormatGuid(Guid
):
1995 return PackGUID(Guid
.split('-'))
1997 ## Get the integer value from string like "14U" or integer like 2
1999 # @param Input The object that may be either a integer value or a string
2001 # @retval Value The integer value that the input represents
2003 def GetIntegerValue(Input
):
2004 if type(Input
) in (int, long):
2007 if String
.endswith("U"):
2008 String
= String
[:-1]
2009 if String
.endswith("ULL"):
2010 String
= String
[:-3]
2011 if String
.endswith("LL"):
2012 String
= String
[:-2]
2014 if String
.startswith("0x") or String
.startswith("0X"):
2015 return int(String
, 16)
2022 # Pack a GUID (registry format) list into a buffer and return it
2025 return pack(PACK_PATTERN_GUID
,
2029 int(Guid
[3][-4:-2], 16),
2030 int(Guid
[3][-2:], 16),
2031 int(Guid
[4][-12:-10], 16),
2032 int(Guid
[4][-10:-8], 16),
2033 int(Guid
[4][-8:-6], 16),
2034 int(Guid
[4][-6:-4], 16),
2035 int(Guid
[4][-4:-2], 16),
2036 int(Guid
[4][-2:], 16)
2040 # Pack a GUID (byte) list into a buffer and return it
2042 def PackByteFormatGUID(Guid
):
2043 return pack(PACK_PATTERN_GUID
,
2057 ## DeepCopy dict/OrderedDict recusively
2059 # @param ori_dict a nested dict or ordereddict
2061 # @retval new dict or orderdict
2063 def CopyDict(ori_dict
):
2064 dict_type
= ori_dict
.__class
__
2065 if dict_type
not in (dict,OrderedDict
):
2067 new_dict
= dict_type()
2068 for key
in ori_dict
:
2069 if isinstance(ori_dict
[key
],(dict,OrderedDict
)):
2070 new_dict
[key
] = CopyDict(ori_dict
[key
])
2072 new_dict
[key
] = ori_dict
[key
]
2076 # Remove the c/c++ comments: // and /* */
2078 def RemoveCComments(ctext
):
2079 return re
.sub('//.*?\n|/\*.*?\*/', '\n', ctext
, flags
=re
.S
)
2082 # This acts like the main() function for the script, unless it is 'import'ed into another
2085 if __name__
== '__main__':