2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import Common
.LongFilePathOs
as os
27 from struct
import pack
28 from UserDict
import IterableUserDict
29 from UserList
import UserList
31 from Common
import EdkLogger
as EdkLogger
32 from Common
import GlobalData
as GlobalData
33 from DataType
import *
34 from BuildToolError
import *
35 from CommonDataClass
.DataClass
import *
36 from Parsing
import GetSplitValueList
37 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
38 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
40 from CommonDataClass
.Exceptions
import BadExpression
42 ## Regular expression used to find out place holders in string template
43 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE | re
.UNICODE
)
45 ## Dictionary used to store file time stamp for quick re-access
46 gFileTimeStampCache
= {} # {file path : file time stamp}
48 ## Dictionary used to store dependencies of files
49 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
51 def GetVariableOffset(mapfilepath
, efifilepath
, varnames
):
52 """ Parse map file to get variable offset in current EFI file
53 @param mapfilepath Map file absolution path
54 @param efifilepath: EFI binary file full path
55 @param varnames iteratable container whose elements are variable names to be searched
57 @return List whos elements are tuple with variable name and raw offset
61 f
= open(mapfilepath
, 'r')
67 if len(lines
) == 0: return None
68 firstline
= lines
[0].strip()
69 if (firstline
.startswith("Archive member included ") and
70 firstline
.endswith(" file (symbol)")):
71 return _parseForGCC(lines
, efifilepath
, varnames
)
72 if firstline
.startswith("# Path:"):
73 return _parseForXcode(lines
, efifilepath
, varnames
)
74 return _parseGeneral(lines
, efifilepath
, varnames
)
76 def _parseForXcode(lines
, efifilepath
, varnames
):
81 if status
== 0 and line
== "# Symbols:":
84 if status
== 1 and len(line
) != 0:
85 for varname
in varnames
:
87 m
= re
.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname
, line
)
89 ret
.append((varname
, m
.group(1)))
92 def _parseForGCC(lines
, efifilepath
, varnames
):
93 """ Parse map file generated by GCC linker """
97 for index
, line
in enumerate(lines
):
99 # status machine transection
100 if status
== 0 and line
== "Memory Configuration":
103 elif status
== 1 and line
== 'Linker script and memory map':
106 elif status
==2 and line
== 'START GROUP':
112 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
114 sections
.append(m
.groups(0))
115 for varname
in varnames
:
117 m
= re
.match("^.data.(%s)" % varname
, line
)
119 m
= re
.match(".data.(%s)$" % varname
, line
)
121 Str
= lines
[index
+ 1]
123 Str
= line
[len(".data.%s" % varname
):]
125 m
= re
.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str
.strip())
127 varoffset
.append((varname
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
131 # get section information from efi file
132 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
133 if efisecs
is None or len(efisecs
) == 0:
137 for efisec
in efisecs
:
138 for section
in sections
:
139 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
140 redirection
= int(section
[1], 16) - efisec
[1]
143 for var
in varoffset
:
144 for efisec
in efisecs
:
145 if var
[1] >= efisec
[1] and var
[1] < efisec
[1]+efisec
[3]:
146 ret
.append((var
[0], hex(efisec
[2] + var
[1] - efisec
[1] - redirection
)))
149 def _parseGeneral(lines
, efifilepath
, varnames
):
150 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
151 secs
= [] # key = section name
153 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
154 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re
.UNICODE
)
158 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
161 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
164 if re
.match("^entry point at", line
):
167 if status
== 1 and len(line
) != 0:
168 m
= secRe
.match(line
)
169 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
170 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
171 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
172 if status
== 2 and len(line
) != 0:
173 for varname
in varnames
:
174 m
= symRe
.match(line
)
175 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
176 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
177 sec_no
= int(sec_no
, 16)
178 sym_offset
= int(sym_offset
, 16)
179 vir_addr
= int(vir_addr
, 16)
180 m2
= re
.match('^[_]*(%s)' % varname
, sym_name
)
182 # fond a binary pcd entry in map file
184 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
185 varoffset
.append([varname
, sec
[3], sym_offset
, vir_addr
, sec_no
])
187 if not varoffset
: return []
189 # get section information from efi file
190 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
191 if efisecs
is None or len(efisecs
) == 0:
195 for var
in varoffset
:
197 for efisec
in efisecs
:
199 if var
[1].strip() == efisec
[0].strip():
200 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
201 elif var
[4] == index
:
202 ret
.append((var
[0], hex(efisec
[2] + var
[2])))
206 ## Routine to process duplicated INF
208 # This function is called by following two cases:
211 # Pkg/module/module.inf
212 # Pkg/module/module.inf {
214 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
217 # INF Pkg/module/module.inf
218 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
220 # This function copies Pkg/module/module.inf to
221 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
223 # @param Path Original PathClass object
224 # @param BaseName New file base name
226 # @retval return the new PathClass object
228 def ProcessDuplicatedInf(Path
, BaseName
, Workspace
):
229 Filename
= os
.path
.split(Path
.File
)[1]
231 Filename
= BaseName
+ Path
.BaseName
+ Filename
[Filename
.rfind('.'):]
233 Filename
= BaseName
+ Path
.BaseName
236 # If -N is specified on command line, cache is disabled
237 # The directory has to be created
239 DbDir
= os
.path
.split(GlobalData
.gDatabasePath
)[0]
240 if not os
.path
.exists(DbDir
):
243 # A temporary INF is copied to database path which must have write permission
244 # The temporary will be removed at the end of build
245 # In case of name conflict, the file name is
246 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
248 TempFullPath
= os
.path
.join(DbDir
,
250 RtPath
= PathClass(Path
.File
, Workspace
)
252 # Modify the full path to temporary path, keep other unchanged
254 # To build same module more than once, the module path with FILE_GUID overridden has
255 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
256 # in DSC which is used as relative path by C files and other files in INF.
257 # A trick was used: all module paths are PathClass instances, after the initialization
258 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
260 # The reason for creating a temporary INF is:
261 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
262 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
263 # A different key for the same module is needed to create different output directory,
264 # retrieve overridden PCDs, library instances.
266 # The BaseName is the FILE_GUID which is also the output directory name.
269 RtPath
.Path
= TempFullPath
270 RtPath
.BaseName
= BaseName
272 # If file exists, compare contents
274 if os
.path
.exists(TempFullPath
):
275 with
open(str(Path
), 'rb') as f1
: Src
= f1
.read()
276 with
open(TempFullPath
, 'rb') as f2
: Dst
= f2
.read()
279 GlobalData
.gTempInfs
.append(TempFullPath
)
280 shutil
.copy2(str(Path
), TempFullPath
)
283 ## Remove temporary created INFs whose paths were saved in gTempInfs
285 def ClearDuplicatedInf():
286 for File
in GlobalData
.gTempInfs
:
287 if os
.path
.exists(File
):
290 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
292 # @param Guid The GUID string
294 # @retval string The GUID string in C structure style
296 def GuidStringToGuidStructureString(Guid
):
297 GuidList
= Guid
.split('-')
299 for Index
in range(0, 3, 1):
300 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
301 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
302 for Index
in range(0, 12, 2):
303 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
307 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
309 # @param GuidValue The GUID value in byte array
311 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
313 def GuidStructureByteArrayToGuidString(GuidValue
):
314 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
315 guidValueList
= guidValueString
.split(",")
316 if len(guidValueList
) != 16:
318 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
320 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
321 int(guidValueList
[3], 16),
322 int(guidValueList
[2], 16),
323 int(guidValueList
[1], 16),
324 int(guidValueList
[0], 16),
325 int(guidValueList
[5], 16),
326 int(guidValueList
[4], 16),
327 int(guidValueList
[7], 16),
328 int(guidValueList
[6], 16),
329 int(guidValueList
[8], 16),
330 int(guidValueList
[9], 16),
331 int(guidValueList
[10], 16),
332 int(guidValueList
[11], 16),
333 int(guidValueList
[12], 16),
334 int(guidValueList
[13], 16),
335 int(guidValueList
[14], 16),
336 int(guidValueList
[15], 16)
341 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
343 # @param GuidValue The GUID value in C structure format
345 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
347 def GuidStructureStringToGuidString(GuidValue
):
348 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
349 guidValueList
= guidValueString
.split(",")
350 if len(guidValueList
) != 11:
352 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
354 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
355 int(guidValueList
[0], 16),
356 int(guidValueList
[1], 16),
357 int(guidValueList
[2], 16),
358 int(guidValueList
[3], 16),
359 int(guidValueList
[4], 16),
360 int(guidValueList
[5], 16),
361 int(guidValueList
[6], 16),
362 int(guidValueList
[7], 16),
363 int(guidValueList
[8], 16),
364 int(guidValueList
[9], 16),
365 int(guidValueList
[10], 16)
370 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
372 # @param GuidValue The GUID value in C structure format
374 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
376 def GuidStructureStringToGuidValueName(GuidValue
):
377 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
378 guidValueList
= guidValueString
.split(",")
379 if len(guidValueList
) != 11:
380 EdkLogger
.error(None, FORMAT_INVALID
, "Invalid GUID value string [%s]" % GuidValue
)
381 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
382 int(guidValueList
[0], 16),
383 int(guidValueList
[1], 16),
384 int(guidValueList
[2], 16),
385 int(guidValueList
[3], 16),
386 int(guidValueList
[4], 16),
387 int(guidValueList
[5], 16),
388 int(guidValueList
[6], 16),
389 int(guidValueList
[7], 16),
390 int(guidValueList
[8], 16),
391 int(guidValueList
[9], 16),
392 int(guidValueList
[10], 16)
395 ## Create directories
397 # @param Directory The directory name
399 def CreateDirectory(Directory
):
400 if Directory
is None or Directory
.strip() == "":
403 if not os
.access(Directory
, os
.F_OK
):
404 os
.makedirs(Directory
)
409 ## Remove directories, including files and sub-directories in it
411 # @param Directory The directory name
413 def RemoveDirectory(Directory
, Recursively
=False):
414 if Directory
is None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
417 CurrentDirectory
= os
.getcwd()
419 for File
in os
.listdir("."):
420 if os
.path
.isdir(File
):
421 RemoveDirectory(File
, Recursively
)
424 os
.chdir(CurrentDirectory
)
427 ## Store content in file
429 # This method is used to save file only when its content is changed. This is
430 # quite useful for "make" system to decide what will be re-built and what won't.
432 # @param File The path of file
433 # @param Content The new content of the file
434 # @param IsBinaryFile The flag indicating if the file is binary file or not
436 # @retval True If the file content is changed and the file is renewed
437 # @retval False If the file content is the same
439 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
441 Content
= Content
.replace("\n", os
.linesep
)
443 if os
.path
.exists(File
):
445 if Content
== open(File
, "rb").read():
448 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
450 DirName
= os
.path
.dirname(File
)
451 if not CreateDirectory(DirName
):
452 EdkLogger
.error(None, FILE_CREATE_FAILURE
, "Could not create directory %s" % DirName
)
455 DirName
= os
.getcwd()
456 if not os
.access(DirName
, os
.W_OK
):
457 EdkLogger
.error(None, PERMISSION_FAILURE
, "Do not have write permission on directory %s" % DirName
)
460 if GlobalData
.gIsWindows
:
462 from PyUtility
import SaveFileToDisk
463 if not SaveFileToDisk(File
, Content
):
464 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
466 Fd
= open(File
, "wb")
470 Fd
= open(File
, "wb")
474 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
='IOError %s' % X
)
478 ## Make a Python object persistent on file system
480 # @param Data The object to be stored in file
481 # @param File The path of file to store the object
483 def DataDump(Data
, File
):
486 Fd
= open(File
, 'wb')
487 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
489 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
494 ## Restore a Python object from a file
496 # @param File The path of file stored the object
498 # @retval object A python object
499 # @retval None If failure in file operation
501 def DataRestore(File
):
505 Fd
= open(File
, 'rb')
506 Data
= cPickle
.load(Fd
)
508 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
515 ## Retrieve and cache the real path name in file system
517 # @param Root The root directory of path relative to
519 # @retval str The path string if the path exists
520 # @retval None If path doesn't exist
526 def __init__(self
, Root
):
528 for F
in os
.listdir(Root
):
530 self
._UPPER
_CACHE
_[F
.upper()] = F
533 def __getitem__(self
, Path
):
534 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
537 if Path
and Path
[0] == os
.path
.sep
:
539 if Path
in self
._CACHE
_:
540 return os
.path
.join(self
._Root
, Path
)
541 UpperPath
= Path
.upper()
542 if UpperPath
in self
._UPPER
_CACHE
_:
543 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
547 SepIndex
= Path
.find(os
.path
.sep
)
549 Parent
= UpperPath
[:SepIndex
]
550 if Parent
not in self
._UPPER
_CACHE
_:
552 LastSepIndex
= SepIndex
553 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
555 if LastSepIndex
== -1:
560 SepIndex
= LastSepIndex
562 Parent
= Path
[:SepIndex
]
563 ParentKey
= UpperPath
[:SepIndex
]
564 if ParentKey
not in self
._UPPER
_CACHE
_:
568 if Parent
in self
._CACHE
_:
571 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
572 for F
in os
.listdir(ParentDir
):
573 Dir
= os
.path
.join(ParentDir
, F
)
574 self
._CACHE
_.add(Dir
)
575 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
577 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
580 if Path
in self
._CACHE
_:
581 return os
.path
.join(self
._Root
, Path
)
582 elif UpperPath
in self
._UPPER
_CACHE
_:
583 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
586 def RealPath(File
, Dir
='', OverrideDir
=''):
587 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
588 NewFile
= GlobalData
.gAllFiles
[NewFile
]
589 if not NewFile
and OverrideDir
:
590 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
591 NewFile
= GlobalData
.gAllFiles
[NewFile
]
594 def RealPath2(File
, Dir
='', OverrideDir
=''):
597 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
599 if OverrideDir
[-1] == os
.path
.sep
:
600 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
602 return NewFile
[len(OverrideDir
) + 1:], NewFile
[0:len(OverrideDir
)]
603 if GlobalData
.gAllFiles
:
604 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
606 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
607 if not os
.path
.exists(NewFile
):
611 if Dir
[-1] == os
.path
.sep
:
612 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
614 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
620 ## Get GUID value from given packages
622 # @param CName The CName of the GUID
623 # @param PackageList List of packages looking-up in
624 # @param Inffile The driver file
626 # @retval GuidValue if the CName is found in any given package
627 # @retval None if the CName is not found in all given packages
629 def GuidValue(CName
, PackageList
, Inffile
= None):
630 for P
in PackageList
:
631 GuidKeys
= P
.Guids
.keys()
632 if Inffile
and P
._PrivateGuids
:
633 if not Inffile
.startswith(P
.MetaFile
.Dir
):
634 GuidKeys
= [x
for x
in P
.Guids
if x
not in P
._PrivateGuids
]
635 if CName
in GuidKeys
:
636 return P
.Guids
[CName
]
639 ## Get Protocol value from given packages
641 # @param CName The CName of the GUID
642 # @param PackageList List of packages looking-up in
643 # @param Inffile The driver file
645 # @retval GuidValue if the CName is found in any given package
646 # @retval None if the CName is not found in all given packages
648 def ProtocolValue(CName
, PackageList
, Inffile
= None):
649 for P
in PackageList
:
650 ProtocolKeys
= P
.Protocols
.keys()
651 if Inffile
and P
._PrivateProtocols
:
652 if not Inffile
.startswith(P
.MetaFile
.Dir
):
653 ProtocolKeys
= [x
for x
in P
.Protocols
if x
not in P
._PrivateProtocols
]
654 if CName
in ProtocolKeys
:
655 return P
.Protocols
[CName
]
658 ## Get PPI value from given packages
660 # @param CName The CName of the GUID
661 # @param PackageList List of packages looking-up in
662 # @param Inffile The driver file
664 # @retval GuidValue if the CName is found in any given package
665 # @retval None if the CName is not found in all given packages
667 def PpiValue(CName
, PackageList
, Inffile
= None):
668 for P
in PackageList
:
669 PpiKeys
= P
.Ppis
.keys()
670 if Inffile
and P
._PrivatePpis
:
671 if not Inffile
.startswith(P
.MetaFile
.Dir
):
672 PpiKeys
= [x
for x
in P
.Ppis
if x
not in P
._PrivatePpis
]
677 ## A string template class
679 # This class implements a template for string replacement. A string template
680 # looks like following
682 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
684 # The string between ${BEGIN} and ${END} will be repeated as many times as the
685 # length of "placeholder_name", which is a list passed through a dict. The
686 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
687 # be not used and, in this case, the "placeholder_name" must not a list and it
688 # will just be replaced once.
690 class TemplateString(object):
691 _REPEAT_START_FLAG
= "BEGIN"
692 _REPEAT_END_FLAG
= "END"
694 class Section(object):
695 _LIST_TYPES
= [type([]), type(set()), type((0,))]
697 def __init__(self
, TemplateSection
, PlaceHolderList
):
698 self
._Template
= TemplateSection
699 self
._PlaceHolderList
= []
701 # Split the section into sub-sections according to the position of placeholders
703 self
._SubSectionList
= []
706 # The placeholders passed in must be in the format of
708 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
710 for PlaceHolder
, Start
, End
in PlaceHolderList
:
711 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
712 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
713 self
._PlaceHolderList
.append(PlaceHolder
)
714 SubSectionStart
= End
715 if SubSectionStart
< len(TemplateSection
):
716 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
718 self
._SubSectionList
= [TemplateSection
]
721 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
723 def Instantiate(self
, PlaceHolderValues
):
725 RepeatPlaceHolders
= {}
726 NonRepeatPlaceHolders
= {}
728 for PlaceHolder
in self
._PlaceHolderList
:
729 if PlaceHolder
not in PlaceHolderValues
:
731 Value
= PlaceHolderValues
[PlaceHolder
]
732 if type(Value
) in self
._LIST
_TYPES
:
734 RepeatTime
= len(Value
)
735 elif RepeatTime
!= len(Value
):
739 "${%s} has different repeat time from others!" % PlaceHolder
,
740 ExtraData
=str(self
._Template
)
742 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
744 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
746 if NonRepeatPlaceHolders
:
748 for S
in self
._SubSectionList
:
749 if S
not in NonRepeatPlaceHolders
:
752 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
754 StringList
= self
._SubSectionList
756 if RepeatPlaceHolders
:
758 for Index
in range(RepeatTime
):
760 if S
not in RepeatPlaceHolders
:
761 TempStringList
.append(S
)
763 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
764 StringList
= TempStringList
766 return "".join(StringList
)
769 def __init__(self
, Template
=None):
771 self
.IsBinary
= False
772 self
._Template
= Template
773 self
._TemplateSectionList
= self
._Parse
(Template
)
777 # @retval string The string replaced
782 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
784 # @retval list A list of TemplateString.Section objects
786 def _Parse(self
, Template
):
791 TemplateSectionList
= []
793 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
795 if MatchEnd
<= len(Template
):
796 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
797 TemplateSectionList
.append(TemplateSection
)
800 MatchString
= MatchObj
.group(1)
801 MatchStart
= MatchObj
.start()
802 MatchEnd
= MatchObj
.end()
804 if MatchString
== self
._REPEAT
_START
_FLAG
:
805 if MatchStart
> SectionStart
:
806 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
807 TemplateSectionList
.append(TemplateSection
)
808 SectionStart
= MatchEnd
810 elif MatchString
== self
._REPEAT
_END
_FLAG
:
811 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
812 TemplateSectionList
.append(TemplateSection
)
813 SectionStart
= MatchEnd
816 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
817 SearchFrom
= MatchEnd
818 return TemplateSectionList
820 ## Replace the string template with dictionary of placeholders and append it to previous one
822 # @param AppendString The string template to append
823 # @param Dictionary The placeholder dictionaries
825 def Append(self
, AppendString
, Dictionary
=None):
827 SectionList
= self
._Parse
(AppendString
)
828 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
830 self
.String
+= AppendString
832 ## Replace the string template with dictionary of placeholders
834 # @param Dictionary The placeholder dictionaries
836 # @retval str The string replaced with placeholder values
838 def Replace(self
, Dictionary
=None):
839 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
841 ## Progress indicator class
843 # This class makes use of thread to print progress on console.
846 # for avoiding deadloop
848 _ProgressThread
= None
849 _CheckInterval
= 0.25
853 # @param OpenMessage The string printed before progress charaters
854 # @param CloseMessage The string printed after progress charaters
855 # @param ProgressChar The charater used to indicate the progress
856 # @param Interval The interval in seconds between two progress charaters
858 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
859 self
.PromptMessage
= OpenMessage
860 self
.CodaMessage
= CloseMessage
861 self
.ProgressChar
= ProgressChar
862 self
.Interval
= Interval
863 if Progressor
._StopFlag
is None:
864 Progressor
._StopFlag
= threading
.Event()
866 ## Start to print progress charater
868 # @param OpenMessage The string printed before progress charaters
870 def Start(self
, OpenMessage
=None):
871 if OpenMessage
is not None:
872 self
.PromptMessage
= OpenMessage
873 Progressor
._StopFlag
.clear()
874 if Progressor
._ProgressThread
is None:
875 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
876 Progressor
._ProgressThread
.setDaemon(False)
877 Progressor
._ProgressThread
.start()
879 ## Stop printing progress charater
881 # @param CloseMessage The string printed after progress charaters
883 def Stop(self
, CloseMessage
=None):
884 OriginalCodaMessage
= self
.CodaMessage
885 if CloseMessage
is not None:
886 self
.CodaMessage
= CloseMessage
888 self
.CodaMessage
= OriginalCodaMessage
890 ## Thread entry method
891 def _ProgressThreadEntry(self
):
892 sys
.stdout
.write(self
.PromptMessage
+ " ")
895 while not Progressor
._StopFlag
.isSet():
897 sys
.stdout
.write(self
.ProgressChar
)
899 TimeUp
= self
.Interval
900 time
.sleep(self
._CheckInterval
)
901 TimeUp
-= self
._CheckInterval
902 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
905 ## Abort the progress display
908 if Progressor
._StopFlag
is not None:
909 Progressor
._StopFlag
.set()
910 if Progressor
._ProgressThread
is not None:
911 Progressor
._ProgressThread
.join()
912 Progressor
._ProgressThread
= None
914 ## A dict which can access its keys and/or values orderly
916 # The class implements a new kind of dict which its keys or values can be
917 # accessed in the order they are added into the dict. It guarantees the order
918 # by making use of an internal list to keep a copy of keys.
920 class sdict(IterableUserDict
):
923 IterableUserDict
.__init
__(self
)
927 def __setitem__(self
, key
, value
):
928 if key
not in self
._key
_list
:
929 self
._key
_list
.append(key
)
930 IterableUserDict
.__setitem
__(self
, key
, value
)
933 def __delitem__(self
, key
):
934 self
._key
_list
.remove(key
)
935 IterableUserDict
.__delitem
__(self
, key
)
937 ## used in "for k in dict" loop to ensure the correct order
939 return self
.iterkeys()
943 return len(self
._key
_list
)
946 def __contains__(self
, key
):
947 return key
in self
._key
_list
950 def index(self
, key
):
951 return self
._key
_list
.index(key
)
954 def insert(self
, key
, newkey
, newvalue
, order
):
955 index
= self
._key
_list
.index(key
)
956 if order
== 'BEFORE':
957 self
._key
_list
.insert(index
, newkey
)
958 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
959 elif order
== 'AFTER':
960 self
._key
_list
.insert(index
+ 1, newkey
)
961 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
964 def append(self
, sdict
):
966 if key
not in self
._key
_list
:
967 self
._key
_list
.append(key
)
968 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
970 def has_key(self
, key
):
971 return key
in self
._key
_list
976 IterableUserDict
.clear(self
)
978 ## Return a copy of keys
981 for key
in self
._key
_list
:
985 ## Return a copy of values
988 for key
in self
._key
_list
:
989 values
.append(self
[key
])
992 ## Return a copy of (key, value) list
995 for key
in self
._key
_list
:
996 items
.append((key
, self
[key
]))
1000 def iteritems(self
):
1001 return iter(self
.items())
1003 ## Keys interation support
1005 return iter(self
.keys())
1007 ## Values interation support
1008 def itervalues(self
):
1009 return iter(self
.values())
1011 ## Return value related to a key, and remove the (key, value) from the dict
1012 def pop(self
, key
, *dv
):
1014 if key
in self
._key
_list
:
1016 self
.__delitem
__(key
)
1021 ## Return (key, value) pair, and remove the (key, value) from the dict
1023 key
= self
._key
_list
[-1]
1025 self
.__delitem
__(key
)
1028 def update(self
, dict=None, **kwargs
):
1029 if dict is not None:
1030 for k
, v
in dict.items():
1033 for k
, v
in kwargs
.items():
1036 ## Dictionary with restricted keys
1040 def __init__(self
, KeyList
):
1042 dict.__setitem
__(self
, Key
, "")
1045 def __setitem__(self
, key
, value
):
1047 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
1048 ExtraData
=", ".join(dict.keys(self
)))
1049 dict.__setitem
__(self
, key
, value
)
1052 def __getitem__(self
, key
):
1055 return dict.__getitem
__(self
, key
)
1058 def __delitem__(self
, key
):
1059 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
1064 self
.__setitem
__(Key
, "")
1066 ## Return value related to a key, and remove the (key, value) from the dict
1067 def pop(self
, key
, *dv
):
1068 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
1070 ## Return (key, value) pair, and remove the (key, value) from the dict
1072 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1074 ## Dictionary using prioritized list as key
1077 _ListType
= type([])
1078 _TupleType
= type(())
1079 _Wildcard
= 'COMMON'
1080 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1082 def __init__(self
, _Single_
=False, _Level_
=2):
1083 self
._Level
_ = _Level_
1085 self
._Single
_ = _Single_
1088 def __getitem__(self
, key
):
1091 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1095 elif self
._Level
_ > 1:
1096 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1099 if self
._Level
_ > 1:
1100 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1102 if FirstKey
is None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1103 FirstKey
= self
._Wildcard
1106 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1108 return self
._GetAllValues
(FirstKey
, RestKeys
)
1110 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1112 #print "%s-%s" % (FirstKey, self._Level_) ,
1113 if self
._Level
_ > 1:
1114 if FirstKey
== self
._Wildcard
:
1115 if FirstKey
in self
.data
:
1116 Value
= self
.data
[FirstKey
][RestKeys
]
1118 for Key
in self
.data
:
1119 Value
= self
.data
[Key
][RestKeys
]
1120 if Value
is not None: break
1122 if FirstKey
in self
.data
:
1123 Value
= self
.data
[FirstKey
][RestKeys
]
1124 if Value
is None and self
._Wildcard
in self
.data
:
1126 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1128 if FirstKey
== self
._Wildcard
:
1129 if FirstKey
in self
.data
:
1130 Value
= self
.data
[FirstKey
]
1132 for Key
in self
.data
:
1133 Value
= self
.data
[Key
]
1134 if Value
is not None: break
1136 if FirstKey
in self
.data
:
1137 Value
= self
.data
[FirstKey
]
1138 elif self
._Wildcard
in self
.data
:
1139 Value
= self
.data
[self
._Wildcard
]
1142 def _GetAllValues(self
, FirstKey
, RestKeys
):
1144 if self
._Level
_ > 1:
1145 if FirstKey
== self
._Wildcard
:
1146 for Key
in self
.data
:
1147 Value
+= self
.data
[Key
][RestKeys
]
1149 if FirstKey
in self
.data
:
1150 Value
+= self
.data
[FirstKey
][RestKeys
]
1151 if self
._Wildcard
in self
.data
:
1152 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1154 if FirstKey
== self
._Wildcard
:
1155 for Key
in self
.data
:
1156 Value
.append(self
.data
[Key
])
1158 if FirstKey
in self
.data
:
1159 Value
.append(self
.data
[FirstKey
])
1160 if self
._Wildcard
in self
.data
:
1161 Value
.append(self
.data
[self
._Wildcard
])
1165 def __setitem__(self
, key
, value
):
1168 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1173 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1176 if self
._Level
_ > 1:
1177 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_ - 1)]
1179 if FirstKey
in self
._ValidWildcardList
:
1180 FirstKey
= self
._Wildcard
1182 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1183 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1185 if self
._Level
_ > 1:
1186 self
.data
[FirstKey
][RestKeys
] = value
1188 self
.data
[FirstKey
] = value
1190 def SetGreedyMode(self
):
1191 self
._Single
_ = False
1192 if self
._Level
_ > 1:
1193 for Key
in self
.data
:
1194 self
.data
[Key
].SetGreedyMode()
1196 def SetSingleMode(self
):
1197 self
._Single
_ = True
1198 if self
._Level
_ > 1:
1199 for Key
in self
.data
:
1200 self
.data
[Key
].SetSingleMode()
1202 def GetKeys(self
, KeyIndex
=0):
1203 assert KeyIndex
>= 0
1205 return set(self
.data
.keys())
1208 for Key
in self
.data
:
1209 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1212 def IsFieldValueAnArray (Value
):
1213 Value
= Value
.strip()
1214 if Value
.startswith('GUID') and Value
.endswith(')'):
1216 if Value
.startswith('L"') and Value
.endswith('"') and len(list(Value
[2:-1])) > 1:
1218 if Value
[0] == '"' and Value
[-1] == '"' and len(list(Value
[1:-1])) > 1:
1220 if Value
[0] == '{' and Value
[-1] == '}':
1222 if Value
.startswith("L'") and Value
.endswith("'") and len(list(Value
[2:-1])) > 1:
1224 if Value
[0] == "'" and Value
[-1] == "'" and len(list(Value
[1:-1])) > 1:
1228 def AnalyzePcdExpression(Setting
):
1229 Setting
= Setting
.strip()
1230 # There might be escaped quote in a string: \", \\\" , \', \\\'
1232 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1234 InSingleQuoteStr
= False
1235 InDoubleQuoteStr
= False
1237 for Index
, ch
in enumerate(Data
):
1238 if ch
== '"' and not InSingleQuoteStr
:
1239 if Data
[Index
- 1] != '\\':
1240 InDoubleQuoteStr
= not InDoubleQuoteStr
1241 elif ch
== "'" and not InDoubleQuoteStr
:
1242 if Data
[Index
- 1] != '\\':
1243 InSingleQuoteStr
= not InSingleQuoteStr
1244 elif ch
== '(' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1246 elif ch
== ')' and not (InSingleQuoteStr
or InDoubleQuoteStr
):
1249 if (Pair
> 0 or InSingleQuoteStr
or InDoubleQuoteStr
) and ch
== TAB_VALUE_SPLIT
:
1256 Pos
= NewStr
.find(TAB_VALUE_SPLIT
, StartPos
)
1258 FieldList
.append(Setting
[StartPos
:].strip())
1260 FieldList
.append(Setting
[StartPos
:Pos
].strip())
1265 def ParseDevPathValue (Value
):
1267 Value
.replace('\\', '/').replace(' ', '')
1269 Cmd
= 'DevicePath ' + '"' + Value
+ '"'
1271 p
= subprocess
.Popen(Cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, shell
=True)
1272 out
, err
= p
.communicate()
1273 except Exception, X
:
1274 raise BadExpression("DevicePath: %s" % (str(X
)) )
1276 subprocess
._cleanup
()
1280 raise BadExpression("DevicePath: %s" % str(err
))
1281 Size
= len(out
.split())
1282 out
= ','.join(out
.split())
1283 return '{' + out
+ '}', Size
1285 def ParseFieldValue (Value
):
1286 if type(Value
) == type(0):
1287 return Value
, (Value
.bit_length() + 7) / 8
1288 if type(Value
) <> type(''):
1289 raise BadExpression('Type %s is %s' %(Value
, type(Value
)))
1290 Value
= Value
.strip()
1291 if Value
.startswith('UINT8') and Value
.endswith(')'):
1292 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1294 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1296 if Value
.startswith('UINT16') and Value
.endswith(')'):
1297 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1299 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1301 if Value
.startswith('UINT32') and Value
.endswith(')'):
1302 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1304 raise BadExpression('Value (%s) Size larger than %d' %(Value
, Size
))
1306 if Value
.startswith('UINT64') and Value
.endswith(')'):
1307 Value
, Size
= ParseFieldValue(Value
.split('(', 1)[1][:-1])
1309 raise BadExpression('Value (%s) Size larger than %d' % (Value
, Size
))
1311 if Value
.startswith('GUID') and Value
.endswith(')'):
1312 Value
= Value
.split('(', 1)[1][:-1].strip()
1313 if Value
[0] == '{' and Value
[-1] == '}':
1314 TmpValue
= GuidStructureStringToGuidString(Value
)
1315 if len(TmpValue
) == 0:
1316 raise BadExpression("Invalid GUID value string %s" % Value
)
1318 if Value
[0] == '"' and Value
[-1] == '"':
1321 Value
= "'" + uuid
.UUID(Value
).get_bytes_le() + "'"
1322 except ValueError, Message
:
1323 raise BadExpression('%s' % Message
)
1324 Value
, Size
= ParseFieldValue(Value
)
1326 if Value
.startswith('L"') and Value
.endswith('"'):
1328 # translate escape character
1338 Value
= (Value
<< 16) |
ord(Char
)
1339 return Value
, (len(List
) + 1) * 2
1340 if Value
.startswith('"') and Value
.endswith('"'):
1342 # translate escape character
1351 Value
= (Value
<< 8) |
ord(Char
)
1352 return Value
, len(List
) + 1
1353 if Value
.startswith("L'") and Value
.endswith("'"):
1354 # Unicode Character Constant
1355 # translate escape character
1363 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1367 Value
= (Value
<< 16) |
ord(Char
)
1368 return Value
, len(List
) * 2
1369 if Value
.startswith("'") and Value
.endswith("'"):
1370 # Character constant
1371 # translate escape character
1378 raise BadExpression('Length %s is %s' % (Value
, len(List
)))
1382 Value
= (Value
<< 8) |
ord(Char
)
1383 return Value
, len(List
)
1384 if Value
.startswith('{') and Value
.endswith('}'):
1387 List
= [Item
.strip() for Item
in Value
.split(',')]
1392 ItemValue
, Size
= ParseFieldValue(Item
)
1394 for I
in range(Size
):
1395 Value
= (Value
<< 8) |
((ItemValue
>> 8 * I
) & 0xff)
1396 return Value
, RetSize
1397 if Value
.startswith('DEVICE_PATH(') and Value
.endswith(')'):
1398 Value
= Value
.replace("DEVICE_PATH(", '').rstrip(')')
1399 Value
= Value
.strip().strip('"')
1400 return ParseDevPathValue(Value
)
1401 if Value
.lower().startswith('0x'):
1402 Value
= int(Value
, 16)
1405 return Value
, (Value
.bit_length() + 7) / 8
1406 if Value
[0].isdigit():
1407 Value
= int(Value
, 10)
1410 return Value
, (Value
.bit_length() + 7) / 8
1411 if Value
.lower() == 'true':
1413 if Value
.lower() == 'false':
1419 # Analyze DSC PCD value, since there is no data type info in DSC
1420 # This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
1421 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1422 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1423 # 3. Dynamic default:
1424 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1425 # TokenSpace.PcdCName|PcdValue
1427 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1428 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1430 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1431 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1432 # there might have "|" operator, also in string value.
1434 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1435 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1436 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1438 # ValueList: A List contain fields described above
1439 # IsValid: True if conforming EBNF, otherwise False
1440 # Index: The index where PcdValue is in ValueList
1442 def AnalyzeDscPcd(Setting
, PcdType
, DataType
=''):
1443 FieldList
= AnalyzePcdExpression(Setting
)
1446 if PcdType
in (MODEL_PCD_FIXED_AT_BUILD
, MODEL_PCD_PATCHABLE_IN_MODULE
, MODEL_PCD_FEATURE_FLAG
):
1447 Value
= FieldList
[0]
1449 if len(FieldList
) > 1:
1450 if FieldList
[1].upper().startswith("0X") or FieldList
[1].isdigit():
1453 DataType
= FieldList
[1]
1455 if len(FieldList
) > 2:
1458 IsValid
= (len(FieldList
) <= 1)
1460 IsValid
= (len(FieldList
) <= 3)
1461 # Value, Size = ParseFieldValue(Value)
1464 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1468 return [str(Value
), '', str(Size
)], IsValid
, 0
1469 elif PcdType
in (MODEL_PCD_DYNAMIC_DEFAULT
, MODEL_PCD_DYNAMIC_EX_DEFAULT
):
1470 Value
= FieldList
[0]
1472 if len(FieldList
) > 1:
1476 if len(FieldList
) > 2:
1479 IsValid
= (len(FieldList
) <= 1)
1481 IsValid
= (len(FieldList
) <= 3)
1485 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1489 return [Value
, Type
, str(Size
)], IsValid
, 0
1490 elif PcdType
in (MODEL_PCD_DYNAMIC_VPD
, MODEL_PCD_DYNAMIC_EX_VPD
):
1491 VpdOffset
= FieldList
[0]
1493 if not DataType
== 'VOID*':
1494 if len(FieldList
) > 1:
1495 Value
= FieldList
[1]
1497 if len(FieldList
) > 1:
1499 if len(FieldList
) > 2:
1500 Value
= FieldList
[2]
1502 IsValid
= (len(FieldList
) <= 1)
1504 IsValid
= (len(FieldList
) <= 3)
1507 int(Size
,16) if Size
.upper().startswith("0X") else int(Size
)
1511 return [VpdOffset
, str(Size
), Value
], IsValid
, 2
1512 elif PcdType
in (MODEL_PCD_DYNAMIC_HII
, MODEL_PCD_DYNAMIC_EX_HII
):
1513 HiiString
= FieldList
[0]
1514 Guid
= Offset
= Value
= Attribute
= ''
1515 if len(FieldList
) > 1:
1517 if len(FieldList
) > 2:
1518 Offset
= FieldList
[2]
1519 if len(FieldList
) > 3:
1520 Value
= FieldList
[3]
1521 if len(FieldList
) > 4:
1522 Attribute
= FieldList
[4]
1523 IsValid
= (3 <= len(FieldList
) <= 5)
1524 return [HiiString
, Guid
, Offset
, Value
, Attribute
], IsValid
, 3
1529 # Analyze the pcd Value, Datum type and TokenNumber.
1530 # Used to avoid split issue while the value string contain "|" character
1532 # @param[in] Setting: A String contain value/datum type/token number information;
1534 # @retval ValueList: A List contain value, datum type and toke number.
1536 def AnalyzePcdData(Setting
):
1537 ValueList
= ['', '', '']
1539 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1540 PtrValue
= ValueRe
.findall(Setting
)
1542 ValueUpdateFlag
= False
1544 if len(PtrValue
) >= 1:
1545 Setting
= re
.sub(ValueRe
, '', Setting
)
1546 ValueUpdateFlag
= True
1548 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1549 ValueList
[0:len(TokenList
)] = TokenList
1552 ValueList
[0] = PtrValue
[0]
1556 ## check format of PCD value against its the datum type
1558 # For PCD value setting
1560 def CheckPcdDatum(Type
, Value
):
1562 ValueRe
= re
.compile(r
'\s*L?\".*\"\s*$')
1563 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1564 or (Value
.startswith('{') and Value
.endswith('}')) or (Value
.startswith("L'") or Value
.startswith("'") and Value
.endswith("'"))
1566 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1567 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value
, Type
)
1568 elif ValueRe
.match(Value
):
1569 # Check the chars in UnicodeString or CString is printable
1570 if Value
.startswith("L"):
1574 Printset
= set(string
.printable
)
1575 Printset
.remove(TAB_PRINTCHAR_VT
)
1576 Printset
.add(TAB_PRINTCHAR_BS
)
1577 Printset
.add(TAB_PRINTCHAR_NUL
)
1578 if not set(Value
).issubset(Printset
):
1579 PrintList
= list(Printset
)
1581 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type
, PrintList
)
1582 elif Type
== 'BOOLEAN':
1583 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1584 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1585 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1586 elif Type
in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
]:
1588 Value
= long(Value
, 0)
1590 return False, "Invalid value [%s] of type [%s];"\
1591 " must be a hexadecimal, decimal or octal in C language format." % (Value
, Type
)
1593 return True, "StructurePcd"
1597 ## Split command line option string to list
1599 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1600 # in non-windows platform to launch command
1602 def SplitOption(OptionString
):
1607 for Index
in range(0, len(OptionString
)):
1608 CurrentChar
= OptionString
[Index
]
1609 if CurrentChar
in ['"', "'"]:
1610 if QuotationMark
== CurrentChar
:
1612 elif QuotationMark
== "":
1613 QuotationMark
= CurrentChar
1618 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1619 if Index
> OptionStart
:
1620 OptionList
.append(OptionString
[OptionStart
:Index
- 1])
1622 LastChar
= CurrentChar
1623 OptionList
.append(OptionString
[OptionStart
:])
1626 def CommonPath(PathList
):
1627 P1
= min(PathList
).split(os
.path
.sep
)
1628 P2
= max(PathList
).split(os
.path
.sep
)
1629 for Index
in xrange(min(len(P1
), len(P2
))):
1630 if P1
[Index
] != P2
[Index
]:
1631 return os
.path
.sep
.join(P1
[:Index
])
1632 return os
.path
.sep
.join(P1
)
1635 # Convert string to C format array
1637 def ConvertStringToByteArray(Value
):
1638 Value
= Value
.strip()
1642 if not Value
.endswith('}'):
1644 Value
= Value
.replace(' ', '').replace('{', '').replace('}', '')
1645 ValFields
= Value
.split(',')
1647 for Index
in range(len(ValFields
)):
1648 ValFields
[Index
] = str(int(ValFields
[Index
], 0))
1651 Value
= '{' + ','.join(ValFields
) + '}'
1655 if Value
.startswith('L"'):
1656 if not Value
.endswith('"'):
1660 elif not Value
.startswith('"') or not Value
.endswith('"'):
1663 Value
= eval(Value
) # translate escape character
1665 for Index
in range(0,len(Value
)):
1667 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x10000) + ','
1669 NewValue
= NewValue
+ str(ord(Value
[Index
]) % 0x100) + ','
1670 Value
= NewValue
+ '0}'
1673 class PathClass(object):
1674 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1675 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1677 self
.File
= str(File
)
1678 if os
.path
.isabs(self
.File
):
1682 self
.Root
= str(Root
)
1683 self
.AlterRoot
= str(AlterRoot
)
1685 # Remove any '.' and '..' in path
1687 self
.Root
= mws
.getWs(self
.Root
, self
.File
)
1688 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1689 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1690 # eliminate the side-effect of 'C:'
1691 if self
.Root
[-1] == ':':
1692 self
.Root
+= os
.path
.sep
1693 # file path should not start with path separator
1694 if self
.Root
[-1] == os
.path
.sep
:
1695 self
.File
= self
.Path
[len(self
.Root
):]
1697 self
.File
= self
.Path
[len(self
.Root
) + 1:]
1699 self
.Path
= os
.path
.normpath(self
.File
)
1701 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1702 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1706 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1708 self
.Dir
= self
.Root
1710 self
.Dir
= self
.SubDir
1715 self
.Type
= self
.Ext
.lower()
1717 self
.IsBinary
= IsBinary
1718 self
.Target
= Target
1719 self
.TagName
= TagName
1720 self
.ToolCode
= ToolCode
1721 self
.ToolChainFamily
= ToolChainFamily
1725 ## Convert the object of this class to a string
1727 # Convert member Path of the class to a string
1729 # @retval string Formatted String
1734 ## Override __eq__ function
1736 # Check whether PathClass are the same
1738 # @retval False The two PathClass are different
1739 # @retval True The two PathClass are the same
1741 def __eq__(self
, Other
):
1742 if type(Other
) == type(self
):
1743 return self
.Path
== Other
.Path
1745 return self
.Path
== str(Other
)
1747 ## Override __cmp__ function
1749 # Customize the comparsion operation of two PathClass
1751 # @retval 0 The two PathClass are different
1752 # @retval -1 The first PathClass is less than the second PathClass
1753 # @retval 1 The first PathClass is Bigger than the second PathClass
1754 def __cmp__(self
, Other
):
1755 if type(Other
) == type(self
):
1756 OtherKey
= Other
.Path
1758 OtherKey
= str(Other
)
1761 if SelfKey
== OtherKey
:
1763 elif SelfKey
> OtherKey
:
1768 ## Override __hash__ function
1770 # Use Path as key in hash table
1772 # @retval string Key for hash table
1775 return hash(self
.Path
)
1777 def _GetFileKey(self
):
1778 if self
._Key
is None:
1779 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1782 def _GetTimeStamp(self
):
1783 return os
.stat(self
.Path
)[8]
1785 def Validate(self
, Type
='', CaseSensitive
=True):
1786 if GlobalData
.gCaseInsensitive
:
1787 CaseSensitive
= False
1788 if Type
and Type
.lower() != self
.Type
:
1789 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1791 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1792 if not RealRoot
and not RealFile
:
1793 RealFile
= self
.File
1795 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1797 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1798 if len (mws
.getPkgPath()) == 0:
1799 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1801 return FILE_NOT_FOUND
, "%s is not found in packages path:\n\t%s" % (self
.File
, '\n\t'.join(mws
.getPkgPath()))
1805 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1806 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1807 ErrorCode
= FILE_CASE_MISMATCH
1808 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1810 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1811 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1813 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1816 self
.File
= RealFile
1817 self
.Root
= RealRoot
1818 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1819 return ErrorCode
, ErrorInfo
1821 Key
= property(_GetFileKey
)
1822 TimeStamp
= property(_GetTimeStamp
)
1824 ## Parse PE image to get the required PE informaion.
1826 class PeImageClass():
1829 # @param File FilePath of PeImage
1831 def __init__(self
, PeFile
):
1832 self
.FileName
= PeFile
1833 self
.IsValid
= False
1836 self
.SectionAlignment
= 0
1837 self
.SectionHeaderList
= []
1840 PeObject
= open(PeFile
, 'rb')
1842 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1845 ByteArray
= array
.array('B')
1846 ByteArray
.fromfile(PeObject
, 0x3E)
1847 ByteList
= ByteArray
.tolist()
1848 # DOS signature should be 'MZ'
1849 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1850 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1853 # Read 4 byte PE Signature
1854 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1855 PeObject
.seek(PeOffset
)
1856 ByteArray
= array
.array('B')
1857 ByteArray
.fromfile(PeObject
, 4)
1858 # PE signature should be 'PE\0\0'
1859 if ByteArray
.tostring() != 'PE\0\0':
1860 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1863 # Read PE file header
1864 ByteArray
= array
.array('B')
1865 ByteArray
.fromfile(PeObject
, 0x14)
1866 ByteList
= ByteArray
.tolist()
1867 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1869 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1872 # Read PE optional header
1873 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1874 ByteArray
= array
.array('B')
1875 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1876 ByteList
= ByteArray
.tolist()
1877 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1878 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1879 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1881 # Read each Section Header
1882 for Index
in range(SecNumber
):
1883 ByteArray
= array
.array('B')
1884 ByteArray
.fromfile(PeObject
, 0x28)
1885 ByteList
= ByteArray
.tolist()
1886 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1887 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1888 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1889 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1890 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1894 def _ByteListToStr(self
, ByteList
):
1896 for index
in range(len(ByteList
)):
1897 if ByteList
[index
] == 0:
1899 String
+= chr(ByteList
[index
])
1902 def _ByteListToInt(self
, ByteList
):
1904 for index
in range(len(ByteList
) - 1, -1, -1):
1905 Value
= (Value
<< 8) |
int(ByteList
[index
])
1908 class DefaultStore():
1909 def __init__(self
,DefaultStores
):
1911 self
.DefaultStores
= DefaultStores
1912 def DefaultStoreID(self
,DefaultStoreName
):
1913 for key
,value
in self
.DefaultStores
.items():
1914 if value
== DefaultStoreName
:
1917 def GetDefaultDefault(self
):
1918 if not self
.DefaultStores
or "0" in self
.DefaultStores
:
1919 return "0",TAB_DEFAULT_STORES_DEFAULT
1921 minvalue
= min([int(value_str
) for value_str
in self
.DefaultStores
.keys()])
1922 return (str(minvalue
), self
.DefaultStores
[str(minvalue
)])
1923 def GetMin(self
,DefaultSIdList
):
1924 if not DefaultSIdList
:
1925 return TAB_DEFAULT_STORES_DEFAULT
1926 storeidset
= {storeid
for storeid
, storename
in self
.DefaultStores
.values() if storename
in DefaultSIdList
}
1929 minid
= min(storeidset
)
1930 for sid
,name
in self
.DefaultStores
.values():
1939 def __init__(self
,SkuIdentifier
='', SkuIds
=None):
1943 for SkuName
in SkuIds
:
1944 SkuId
= SkuIds
[SkuName
][0]
1945 skuid_num
= int(SkuId
,16) if SkuId
.upper().startswith("0X") else int(SkuId
)
1946 if skuid_num
> 0xFFFFFFFFFFFFFFFF:
1947 EdkLogger
.error("build", PARAMETER_INVALID
,
1948 ExtraData
= "SKU-ID [%s] value %s exceeds the max value of UINT64"
1951 self
.AvailableSkuIds
= sdict()
1953 self
.SkuIdNumberSet
= []
1954 self
.SkuData
= SkuIds
1955 self
.__SkuInherit
= {}
1956 self
.__SkuIdentifier
= SkuIdentifier
1957 if SkuIdentifier
== '' or SkuIdentifier
is None:
1958 self
.SkuIdSet
= ['DEFAULT']
1959 self
.SkuIdNumberSet
= ['0U']
1960 elif SkuIdentifier
== 'ALL':
1961 self
.SkuIdSet
= SkuIds
.keys()
1962 self
.SkuIdNumberSet
= [num
[0].strip() + 'U' for num
in SkuIds
.values()]
1964 r
= SkuIdentifier
.split('|')
1965 self
.SkuIdSet
=[(r
[k
].strip()).upper() for k
in range(len(r
))]
1968 self
.SkuIdNumberSet
= [SkuIds
[k
][0].strip() + 'U' for k
in self
.SkuIdSet
]
1970 EdkLogger
.error("build", PARAMETER_INVALID
,
1971 ExtraData
= "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1972 % (k
, " | ".join(SkuIds
.keys())))
1973 for each
in self
.SkuIdSet
:
1975 self
.AvailableSkuIds
[each
] = SkuIds
[each
][0]
1977 EdkLogger
.error("build", PARAMETER_INVALID
,
1978 ExtraData
="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
1979 % (each
, " | ".join(SkuIds
.keys())))
1980 if self
.SkuUsageType
!= self
.SINGLE
:
1981 self
.AvailableSkuIds
.update({'DEFAULT':0, 'COMMON':0})
1983 GlobalData
.gSkuids
= (self
.SkuIdSet
)
1984 if 'COMMON' in GlobalData
.gSkuids
:
1985 GlobalData
.gSkuids
.remove('COMMON')
1986 if self
.SkuUsageType
== self
.SINGLE
:
1987 if len(GlobalData
.gSkuids
) != 1:
1988 if 'DEFAULT' in GlobalData
.gSkuids
:
1989 GlobalData
.gSkuids
.remove('DEFAULT')
1990 if GlobalData
.gSkuids
:
1991 GlobalData
.gSkuids
.sort()
1993 def GetNextSkuId(self
, skuname
):
1994 if not self
.__SkuInherit
:
1995 self
.__SkuInherit
= {}
1996 for item
in self
.SkuData
.values():
1997 self
.__SkuInherit
[item
[1]]=item
[2] if item
[2] else "DEFAULT"
1998 return self
.__SkuInherit
.get(skuname
,"DEFAULT")
2000 def GetSkuChain(self
,sku
):
2001 if sku
== "DEFAULT":
2006 nextsku
= self
.GetNextSkuId(nextsku
)
2007 skulist
.append(nextsku
)
2008 if nextsku
== "DEFAULT":
2012 def SkuOverrideOrder(self
):
2014 for skuname
in self
.SkuIdSet
:
2015 skuorderset
.append(self
.GetSkuChain(skuname
))
2018 for index
in range(max([len(item
) for item
in skuorderset
])):
2019 for subset
in skuorderset
:
2020 if index
> len(subset
)-1:
2022 if subset
[index
] in skuorder
:
2024 skuorder
.append(subset
[index
])
2028 def __SkuUsageType(self
):
2030 if self
.__SkuIdentifier
.upper() == "ALL":
2031 return SkuClass
.MULTIPLE
2033 if len(self
.SkuIdSet
) == 1:
2034 if self
.SkuIdSet
[0] == 'DEFAULT':
2035 return SkuClass
.DEFAULT
2037 return SkuClass
.SINGLE
2038 elif len(self
.SkuIdSet
) == 2:
2039 if 'DEFAULT' in self
.SkuIdSet
:
2040 return SkuClass
.SINGLE
2042 return SkuClass
.MULTIPLE
2044 return SkuClass
.MULTIPLE
2045 def DumpSkuIdArrary(self
):
2048 if self
.SkuUsageType
== SkuClass
.SINGLE
:
2051 for skuname
in self
.AvailableSkuIds
:
2052 if skuname
== "COMMON":
2054 while skuname
!= "DEFAULT":
2055 ArrayStrList
.append(hex(int(self
.AvailableSkuIds
[skuname
])))
2056 skuname
= self
.GetNextSkuId(skuname
)
2057 ArrayStrList
.append("0x0")
2058 ArrayStr
= "{" + ",".join(ArrayStrList
) + "}"
2060 def __GetAvailableSkuIds(self
):
2061 return self
.AvailableSkuIds
2063 def __GetSystemSkuID(self
):
2064 if self
.__SkuUsageType
() == SkuClass
.SINGLE
:
2065 if len(self
.SkuIdSet
) == 1:
2066 return self
.SkuIdSet
[0]
2068 return self
.SkuIdSet
[0] if self
.SkuIdSet
[0] != 'DEFAULT' else self
.SkuIdSet
[1]
2071 def __GetAvailableSkuIdNumber(self
):
2072 return self
.SkuIdNumberSet
2073 SystemSkuId
= property(__GetSystemSkuID
)
2074 AvailableSkuIdSet
= property(__GetAvailableSkuIds
)
2075 SkuUsageType
= property(__SkuUsageType
)
2076 AvailableSkuIdNumSet
= property(__GetAvailableSkuIdNumber
)
2079 # Pack a registry format GUID
2081 def PackRegistryFormatGuid(Guid
):
2082 Guid
= Guid
.split('-')
2083 return pack('=LHHBBBBBBBB',
2087 int(Guid
[3][-4:-2], 16),
2088 int(Guid
[3][-2:], 16),
2089 int(Guid
[4][-12:-10], 16),
2090 int(Guid
[4][-10:-8], 16),
2091 int(Guid
[4][-8:-6], 16),
2092 int(Guid
[4][-6:-4], 16),
2093 int(Guid
[4][-4:-2], 16),
2094 int(Guid
[4][-2:], 16)
2097 ## Get the integer value from string like "14U" or integer like 2
2099 # @param Input The object that may be either a integer value or a string
2101 # @retval Value The integer value that the input represents
2103 def GetIntegerValue(Input
):
2104 if type(Input
) in (int, long):
2107 if String
.endswith("U"):
2108 String
= String
[:-1]
2109 if String
.endswith("ULL"):
2110 String
= String
[:-3]
2111 if String
.endswith("LL"):
2112 String
= String
[:-2]
2114 if String
.startswith("0x") or String
.startswith("0X"):
2115 return int(String
, 16)
2123 # This acts like the main() function for the script, unless it is 'import'ed into another
2126 if __name__
== '__main__':