]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
2a5125d72da8c08f943bb0ac4fbdc113f49ba043
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
1 ## @file
2 # Common routines used by all tools
3 #
4 # Copyright (c) 2007 - 2017, 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
9 #
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.
12 #
13
14 ##
15 # Import Modules
16 #
17 import Common.LongFilePathOs as os
18 import sys
19 import string
20 import thread
21 import threading
22 import time
23 import re
24 import cPickle
25 import array
26 import shutil
27 from struct import pack
28 from UserDict import IterableUserDict
29 from UserList import UserList
30
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
39
40 ## Regular expression used to find out place holders in string template
41 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)
42
43 ## Dictionary used to store file time stamp for quick re-access
44 gFileTimeStampCache = {} # {file path : file time stamp}
45
46 ## Dictionary used to store dependencies of files
47 gDependencyDatabase = {} # arch : {file path : [dependent files list]}
48
49 def GetVariableOffset(mapfilepath, efifilepath, varnames):
50 """ Parse map file to get variable offset in current EFI file
51 @param mapfilepath Map file absolution path
52 @param efifilepath: EFI binary file full path
53 @param varnames iteratable container whose elements are variable names to be searched
54
55 @return List whos elements are tuple with variable name and raw offset
56 """
57 lines = []
58 try:
59 f = open(mapfilepath, 'r')
60 lines = f.readlines()
61 f.close()
62 except:
63 return None
64
65 if len(lines) == 0: return None
66 firstline = lines[0].strip()
67 if (firstline.startswith("Archive member included ") and
68 firstline.endswith(" file (symbol)")):
69 return _parseForGCC(lines, efifilepath, varnames)
70 if firstline.startswith("# Path:"):
71 return _parseForXcode(lines, efifilepath, varnames)
72 return _parseGeneral(lines, efifilepath, varnames)
73
74 def _parseForXcode(lines, efifilepath, varnames):
75 status = 0
76 ret = []
77 for index, line in enumerate(lines):
78 line = line.strip()
79 if status == 0 and line == "# Symbols:":
80 status = 1
81 continue
82 if status == 1 and len(line) != 0:
83 for varname in varnames:
84 if varname in line:
85 m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)
86 if m != None:
87 ret.append((varname, m.group(1)))
88 return ret
89
90 def _parseForGCC(lines, efifilepath, varnames):
91 """ Parse map file generated by GCC linker """
92 status = 0
93 sections = []
94 varoffset = []
95 for index, line in enumerate(lines):
96 line = line.strip()
97 # status machine transection
98 if status == 0 and line == "Memory Configuration":
99 status = 1
100 continue
101 elif status == 1 and line == 'Linker script and memory map':
102 status = 2
103 continue
104 elif status ==2 and line == 'START GROUP':
105 status = 3
106 continue
107
108 # status handler
109 if status == 3:
110 m = re.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line)
111 if m != None:
112 sections.append(m.groups(0))
113 for varname in varnames:
114 Str = ''
115 m = re.match("^.data.(%s)" % varname, line)
116 if m != None:
117 m = re.match(".data.(%s)$" % varname, line)
118 if m != None:
119 Str = lines[index + 1]
120 else:
121 Str = line[len(".data.%s" % varname):]
122 if Str:
123 m = re.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str.strip())
124 if m != None:
125 varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0]))
126
127 if not varoffset:
128 return []
129 # get section information from efi file
130 efisecs = PeImageClass(efifilepath).SectionHeaderList
131 if efisecs == None or len(efisecs) == 0:
132 return []
133 #redirection
134 redirection = 0
135 for efisec in efisecs:
136 for section in sections:
137 if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':
138 redirection = int(section[1], 16) - efisec[1]
139
140 ret = []
141 for var in varoffset:
142 for efisec in efisecs:
143 if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:
144 ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))
145 return ret
146
147 def _parseGeneral(lines, efifilepath, varnames):
148 status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
149 secs = [] # key = section name
150 varoffset = []
151 secRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)
152 symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re.UNICODE)
153
154 for line in lines:
155 line = line.strip()
156 if re.match("^Start[' ']+Length[' ']+Name[' ']+Class", line):
157 status = 1
158 continue
159 if re.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line):
160 status = 2
161 continue
162 if re.match("^entry point at", line):
163 status = 3
164 continue
165 if status == 1 and len(line) != 0:
166 m = secRe.match(line)
167 assert m != None, "Fail to parse the section in map file , line is %s" % line
168 sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)
169 secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])
170 if status == 2 and len(line) != 0:
171 for varname in varnames:
172 m = symRe.match(line)
173 assert m != None, "Fail to parse the symbol in map file, line is %s" % line
174 sec_no, sym_offset, sym_name, vir_addr = m.groups(0)
175 sec_no = int(sec_no, 16)
176 sym_offset = int(sym_offset, 16)
177 vir_addr = int(vir_addr, 16)
178 m2 = re.match('^[_]*(%s)' % varname, sym_name)
179 if m2 != None:
180 # fond a binary pcd entry in map file
181 for sec in secs:
182 if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):
183 varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])
184
185 if not varoffset: return []
186
187 # get section information from efi file
188 efisecs = PeImageClass(efifilepath).SectionHeaderList
189 if efisecs == None or len(efisecs) == 0:
190 return []
191
192 ret = []
193 for var in varoffset:
194 index = 0
195 for efisec in efisecs:
196 index = index + 1
197 if var[1].strip() == efisec[0].strip():
198 ret.append((var[0], hex(efisec[2] + var[2])))
199 elif var[4] == index:
200 ret.append((var[0], hex(efisec[2] + var[2])))
201
202 return ret
203
204 ## Routine to process duplicated INF
205 #
206 # This function is called by following two cases:
207 # Case 1 in DSC:
208 # [components.arch]
209 # Pkg/module/module.inf
210 # Pkg/module/module.inf {
211 # <Defines>
212 # FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
213 # }
214 # Case 2 in FDF:
215 # INF Pkg/module/module.inf
216 # INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
217 #
218 # This function copies Pkg/module/module.inf to
219 # Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
220 #
221 # @param Path Original PathClass object
222 # @param BaseName New file base name
223 #
224 # @retval return the new PathClass object
225 #
226 def ProcessDuplicatedInf(Path, BaseName, Workspace):
227 Filename = os.path.split(Path.File)[1]
228 if '.' in Filename:
229 Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]
230 else:
231 Filename = BaseName + Path.BaseName
232
233 #
234 # If -N is specified on command line, cache is disabled
235 # The directory has to be created
236 #
237 DbDir = os.path.split(GlobalData.gDatabasePath)[0]
238 if not os.path.exists(DbDir):
239 os.makedirs(DbDir)
240 #
241 # A temporary INF is copied to database path which must have write permission
242 # The temporary will be removed at the end of build
243 # In case of name conflict, the file name is
244 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
245 #
246 TempFullPath = os.path.join(DbDir,
247 Filename)
248 RtPath = PathClass(Path.File, Workspace)
249 #
250 # Modify the full path to temporary path, keep other unchanged
251 #
252 # To build same module more than once, the module path with FILE_GUID overridden has
253 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
254 # in DSC which is used as relative path by C files and other files in INF.
255 # A trick was used: all module paths are PathClass instances, after the initialization
256 # of PathClass, the PathClass.Path is overridden by the temporary INF path.
257 #
258 # The reason for creating a temporary INF is:
259 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
260 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
261 # A different key for the same module is needed to create different output directory,
262 # retrieve overridden PCDs, library instances.
263 #
264 # The BaseName is the FILE_GUID which is also the output directory name.
265 #
266 #
267 RtPath.Path = TempFullPath
268 RtPath.BaseName = BaseName
269 #
270 # If file exists, compare contents
271 #
272 if os.path.exists(TempFullPath):
273 with open(str(Path), 'rb') as f1: Src = f1.read()
274 with open(TempFullPath, 'rb') as f2: Dst = f2.read()
275 if Src == Dst:
276 return RtPath
277 GlobalData.gTempInfs.append(TempFullPath)
278 shutil.copy2(str(Path), TempFullPath)
279 return RtPath
280
281 ## Remove temporary created INFs whose paths were saved in gTempInfs
282 #
283 def ClearDuplicatedInf():
284 for File in GlobalData.gTempInfs:
285 if os.path.exists(File):
286 os.remove(File)
287
288 ## callback routine for processing variable option
289 #
290 # This function can be used to process variable number of option values. The
291 # typical usage of it is specify architecure list on command line.
292 # (e.g. <tool> -a IA32 X64 IPF)
293 #
294 # @param Option Standard callback function parameter
295 # @param OptionString Standard callback function parameter
296 # @param Value Standard callback function parameter
297 # @param Parser Standard callback function parameter
298 #
299 # @retval
300 #
301 def ProcessVariableArgument(Option, OptionString, Value, Parser):
302 assert Value is None
303 Value = []
304 RawArgs = Parser.rargs
305 while RawArgs:
306 Arg = RawArgs[0]
307 if (Arg[:2] == "--" and len(Arg) > 2) or \
308 (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"):
309 break
310 Value.append(Arg)
311 del RawArgs[0]
312 setattr(Parser.values, Option.dest, Value)
313
314 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
315 #
316 # @param Guid The GUID string
317 #
318 # @retval string The GUID string in C structure style
319 #
320 def GuidStringToGuidStructureString(Guid):
321 GuidList = Guid.split('-')
322 Result = '{'
323 for Index in range(0, 3, 1):
324 Result = Result + '0x' + GuidList[Index] + ', '
325 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
326 for Index in range(0, 12, 2):
327 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
328 Result += '}}'
329 return Result
330
331 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
332 #
333 # @param GuidValue The GUID value in byte array
334 #
335 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
336 #
337 def GuidStructureByteArrayToGuidString(GuidValue):
338 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
339 guidValueList = guidValueString.split(",")
340 if len(guidValueList) != 16:
341 return ''
342 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
343 try:
344 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
345 int(guidValueList[3], 16),
346 int(guidValueList[2], 16),
347 int(guidValueList[1], 16),
348 int(guidValueList[0], 16),
349 int(guidValueList[5], 16),
350 int(guidValueList[4], 16),
351 int(guidValueList[7], 16),
352 int(guidValueList[6], 16),
353 int(guidValueList[8], 16),
354 int(guidValueList[9], 16),
355 int(guidValueList[10], 16),
356 int(guidValueList[11], 16),
357 int(guidValueList[12], 16),
358 int(guidValueList[13], 16),
359 int(guidValueList[14], 16),
360 int(guidValueList[15], 16)
361 )
362 except:
363 return ''
364
365 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
366 #
367 # @param GuidValue The GUID value in C structure format
368 #
369 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
370 #
371 def GuidStructureStringToGuidString(GuidValue):
372 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
373 guidValueList = guidValueString.split(",")
374 if len(guidValueList) != 11:
375 return ''
376 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
377 try:
378 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
379 int(guidValueList[0], 16),
380 int(guidValueList[1], 16),
381 int(guidValueList[2], 16),
382 int(guidValueList[3], 16),
383 int(guidValueList[4], 16),
384 int(guidValueList[5], 16),
385 int(guidValueList[6], 16),
386 int(guidValueList[7], 16),
387 int(guidValueList[8], 16),
388 int(guidValueList[9], 16),
389 int(guidValueList[10], 16)
390 )
391 except:
392 return ''
393
394 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
395 #
396 # @param GuidValue The GUID value in C structure format
397 #
398 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
399 #
400 def GuidStructureStringToGuidValueName(GuidValue):
401 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
402 guidValueList = guidValueString.split(",")
403 if len(guidValueList) != 11:
404 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)
405 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
406 int(guidValueList[0], 16),
407 int(guidValueList[1], 16),
408 int(guidValueList[2], 16),
409 int(guidValueList[3], 16),
410 int(guidValueList[4], 16),
411 int(guidValueList[5], 16),
412 int(guidValueList[6], 16),
413 int(guidValueList[7], 16),
414 int(guidValueList[8], 16),
415 int(guidValueList[9], 16),
416 int(guidValueList[10], 16)
417 )
418
419 ## Create directories
420 #
421 # @param Directory The directory name
422 #
423 def CreateDirectory(Directory):
424 if Directory == None or Directory.strip() == "":
425 return True
426 try:
427 if not os.access(Directory, os.F_OK):
428 os.makedirs(Directory)
429 except:
430 return False
431 return True
432
433 ## Remove directories, including files and sub-directories in it
434 #
435 # @param Directory The directory name
436 #
437 def RemoveDirectory(Directory, Recursively=False):
438 if Directory == None or Directory.strip() == "" or not os.path.exists(Directory):
439 return
440 if Recursively:
441 CurrentDirectory = os.getcwd()
442 os.chdir(Directory)
443 for File in os.listdir("."):
444 if os.path.isdir(File):
445 RemoveDirectory(File, Recursively)
446 else:
447 os.remove(File)
448 os.chdir(CurrentDirectory)
449 os.rmdir(Directory)
450
451 ## Check if given file is changed or not
452 #
453 # This method is used to check if a file is changed or not between two build
454 # actions. It makes use a cache to store files timestamp.
455 #
456 # @param File The path of file
457 #
458 # @retval True If the given file is changed, doesn't exist, or can't be
459 # found in timestamp cache
460 # @retval False If the given file is changed
461 #
462 def IsChanged(File):
463 if not os.path.exists(File):
464 return True
465
466 FileState = os.stat(File)
467 TimeStamp = FileState[-2]
468
469 if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]:
470 FileChanged = False
471 else:
472 FileChanged = True
473 gFileTimeStampCache[File] = TimeStamp
474
475 return FileChanged
476
477 ## Store content in file
478 #
479 # This method is used to save file only when its content is changed. This is
480 # quite useful for "make" system to decide what will be re-built and what won't.
481 #
482 # @param File The path of file
483 # @param Content The new content of the file
484 # @param IsBinaryFile The flag indicating if the file is binary file or not
485 #
486 # @retval True If the file content is changed and the file is renewed
487 # @retval False If the file content is the same
488 #
489 def SaveFileOnChange(File, Content, IsBinaryFile=True):
490 if not IsBinaryFile:
491 Content = Content.replace("\n", os.linesep)
492
493 if os.path.exists(File):
494 try:
495 if Content == open(File, "rb").read():
496 return False
497 except:
498 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
499
500 DirName = os.path.dirname(File)
501 if not CreateDirectory(DirName):
502 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
503 else:
504 if DirName == '':
505 DirName = os.getcwd()
506 if not os.access(DirName, os.W_OK):
507 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
508
509 try:
510 if GlobalData.gIsWindows:
511 try:
512 from PyUtility import SaveFileToDisk
513 if not SaveFileToDisk(File, Content):
514 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
515 except:
516 Fd = open(File, "wb")
517 Fd.write(Content)
518 Fd.close()
519 else:
520 Fd = open(File, "wb")
521 Fd.write(Content)
522 Fd.close()
523 except IOError, X:
524 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)
525
526 return True
527
528 ## Make a Python object persistent on file system
529 #
530 # @param Data The object to be stored in file
531 # @param File The path of file to store the object
532 #
533 def DataDump(Data, File):
534 Fd = None
535 try:
536 Fd = open(File, 'wb')
537 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)
538 except:
539 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)
540 finally:
541 if Fd != None:
542 Fd.close()
543
544 ## Restore a Python object from a file
545 #
546 # @param File The path of file stored the object
547 #
548 # @retval object A python object
549 # @retval None If failure in file operation
550 #
551 def DataRestore(File):
552 Data = None
553 Fd = None
554 try:
555 Fd = open(File, 'rb')
556 Data = cPickle.load(Fd)
557 except Exception, e:
558 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))
559 Data = None
560 finally:
561 if Fd != None:
562 Fd.close()
563 return Data
564
565 ## Retrieve and cache the real path name in file system
566 #
567 # @param Root The root directory of path relative to
568 #
569 # @retval str The path string if the path exists
570 # @retval None If path doesn't exist
571 #
572 class DirCache:
573 _CACHE_ = set()
574 _UPPER_CACHE_ = {}
575
576 def __init__(self, Root):
577 self._Root = Root
578 for F in os.listdir(Root):
579 self._CACHE_.add(F)
580 self._UPPER_CACHE_[F.upper()] = F
581
582 # =[] operator
583 def __getitem__(self, Path):
584 Path = Path[len(os.path.commonprefix([Path, self._Root])):]
585 if not Path:
586 return self._Root
587 if Path and Path[0] == os.path.sep:
588 Path = Path[1:]
589 if Path in self._CACHE_:
590 return os.path.join(self._Root, Path)
591 UpperPath = Path.upper()
592 if UpperPath in self._UPPER_CACHE_:
593 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
594
595 IndexList = []
596 LastSepIndex = -1
597 SepIndex = Path.find(os.path.sep)
598 while SepIndex > -1:
599 Parent = UpperPath[:SepIndex]
600 if Parent not in self._UPPER_CACHE_:
601 break
602 LastSepIndex = SepIndex
603 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
604
605 if LastSepIndex == -1:
606 return None
607
608 Cwd = os.getcwd()
609 os.chdir(self._Root)
610 SepIndex = LastSepIndex
611 while SepIndex > -1:
612 Parent = Path[:SepIndex]
613 ParentKey = UpperPath[:SepIndex]
614 if ParentKey not in self._UPPER_CACHE_:
615 os.chdir(Cwd)
616 return None
617
618 if Parent in self._CACHE_:
619 ParentDir = Parent
620 else:
621 ParentDir = self._UPPER_CACHE_[ParentKey]
622 for F in os.listdir(ParentDir):
623 Dir = os.path.join(ParentDir, F)
624 self._CACHE_.add(Dir)
625 self._UPPER_CACHE_[Dir.upper()] = Dir
626
627 SepIndex = Path.find(os.path.sep, SepIndex + 1)
628
629 os.chdir(Cwd)
630 if Path in self._CACHE_:
631 return os.path.join(self._Root, Path)
632 elif UpperPath in self._UPPER_CACHE_:
633 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
634 return None
635
636 ## Get all files of a directory
637 #
638 # @param Root: Root dir
639 # @param SkipList : The files need be skipped
640 #
641 # @retval A list of all files
642 #
643 def GetFiles(Root, SkipList=None, FullPath=True):
644 OriPath = Root
645 FileList = []
646 for Root, Dirs, Files in os.walk(Root):
647 if SkipList:
648 for Item in SkipList:
649 if Item in Dirs:
650 Dirs.remove(Item)
651
652 for File in Files:
653 File = os.path.normpath(os.path.join(Root, File))
654 if not FullPath:
655 File = File[len(OriPath) + 1:]
656 FileList.append(File)
657
658 return FileList
659
660 ## Check if gvien file exists or not
661 #
662 # @param File File name or path to be checked
663 # @param Dir The directory the file is relative to
664 #
665 # @retval True if file exists
666 # @retval False if file doesn't exists
667 #
668 def ValidFile(File, Ext=None):
669 if Ext != None:
670 Dummy, FileExt = os.path.splitext(File)
671 if FileExt.lower() != Ext.lower():
672 return False
673 if not os.path.exists(File):
674 return False
675 return True
676
677 def RealPath(File, Dir='', OverrideDir=''):
678 NewFile = os.path.normpath(os.path.join(Dir, File))
679 NewFile = GlobalData.gAllFiles[NewFile]
680 if not NewFile and OverrideDir:
681 NewFile = os.path.normpath(os.path.join(OverrideDir, File))
682 NewFile = GlobalData.gAllFiles[NewFile]
683 return NewFile
684
685 def RealPath2(File, Dir='', OverrideDir=''):
686 NewFile = None
687 if OverrideDir:
688 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
689 if NewFile:
690 if OverrideDir[-1] == os.path.sep:
691 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
692 else:
693 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]
694 if GlobalData.gAllFiles:
695 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
696 if not NewFile:
697 NewFile = os.path.normpath(os.path.join(Dir, File))
698 if not os.path.exists(NewFile):
699 return None, None
700 if NewFile:
701 if Dir:
702 if Dir[-1] == os.path.sep:
703 return NewFile[len(Dir):], NewFile[0:len(Dir)]
704 else:
705 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]
706 else:
707 return NewFile, ''
708
709 return None, None
710
711 ## Check if gvien file exists or not
712 #
713 #
714 def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
715 NewFile = File
716 if Ext != None:
717 Dummy, FileExt = os.path.splitext(File)
718 if FileExt.lower() != Ext.lower():
719 return False, File
720
721 # Replace the Edk macros
722 if OverrideDir != '' and OverrideDir != None:
723 if OverrideDir.find('$(EFI_SOURCE)') > -1:
724 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
725 if OverrideDir.find('$(EDK_SOURCE)') > -1:
726 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
727
728 # Replace the default dir to current dir
729 if Dir == '.':
730 Dir = os.getcwd()
731 Dir = Dir[len(Workspace) + 1:]
732
733 # First check if File has Edk definition itself
734 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
735 NewFile = File.replace('$(EFI_SOURCE)', EfiSource)
736 NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)
737 NewFile = AllFiles[os.path.normpath(NewFile)]
738 if NewFile != None:
739 return True, NewFile
740
741 # Second check the path with override value
742 if OverrideDir != '' and OverrideDir != None:
743 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
744 if NewFile != None:
745 return True, NewFile
746
747 # Last check the path with normal definitions
748 File = os.path.join(Dir, File)
749 NewFile = AllFiles[os.path.normpath(File)]
750 if NewFile != None:
751 return True, NewFile
752
753 return False, File
754
755 ## Check if gvien file exists or not
756 #
757 #
758 def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
759 # Replace the Edk macros
760 if OverrideDir != '' and OverrideDir != None:
761 if OverrideDir.find('$(EFI_SOURCE)') > -1:
762 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
763 if OverrideDir.find('$(EDK_SOURCE)') > -1:
764 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
765
766 # Replace the default dir to current dir
767 # Dir is current module dir related to workspace
768 if Dir == '.':
769 Dir = os.getcwd()
770 Dir = Dir[len(Workspace) + 1:]
771
772 NewFile = File
773 RelaPath = AllFiles[os.path.normpath(Dir)]
774 NewRelaPath = RelaPath
775
776 while(True):
777 # First check if File has Edk definition itself
778 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
779 File = File.replace('$(EFI_SOURCE)', EfiSource)
780 File = File.replace('$(EDK_SOURCE)', EdkSource)
781 NewFile = AllFiles[os.path.normpath(File)]
782 if NewFile != None:
783 NewRelaPath = os.path.dirname(NewFile)
784 File = os.path.basename(NewFile)
785 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
786 break
787
788 # Second check the path with override value
789 if OverrideDir != '' and OverrideDir != None:
790 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
791 if NewFile != None:
792 #NewRelaPath = os.path.dirname(NewFile)
793 NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
794 break
795
796 # Last check the path with normal definitions
797 NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))]
798 if NewFile != None:
799 break
800
801 # No file found
802 break
803
804 return NewRelaPath, RelaPath, File
805
806
807 def GetRelPath(Path1, Path2):
808 FileName = os.path.basename(Path2)
809 L1 = os.path.normpath(Path1).split(os.path.normpath('/'))
810 L2 = os.path.normpath(Path2).split(os.path.normpath('/'))
811 for Index in range(0, len(L1)):
812 if L1[Index] != L2[Index]:
813 FileName = '../' * (len(L1) - Index)
814 for Index2 in range(Index, len(L2)):
815 FileName = os.path.join(FileName, L2[Index2])
816 break
817 return os.path.normpath(FileName)
818
819
820 ## Get GUID value from given packages
821 #
822 # @param CName The CName of the GUID
823 # @param PackageList List of packages looking-up in
824 # @param Inffile The driver file
825 #
826 # @retval GuidValue if the CName is found in any given package
827 # @retval None if the CName is not found in all given packages
828 #
829 def GuidValue(CName, PackageList, Inffile = None):
830 for P in PackageList:
831 GuidKeys = P.Guids.keys()
832 if Inffile and P._PrivateGuids:
833 if not Inffile.startswith(P.MetaFile.Dir):
834 GuidKeys = (dict.fromkeys(x for x in P.Guids if x not in P._PrivateGuids)).keys()
835 if CName in GuidKeys:
836 return P.Guids[CName]
837 return None
838
839 ## Get Protocol value from given packages
840 #
841 # @param CName The CName of the GUID
842 # @param PackageList List of packages looking-up in
843 # @param Inffile The driver file
844 #
845 # @retval GuidValue if the CName is found in any given package
846 # @retval None if the CName is not found in all given packages
847 #
848 def ProtocolValue(CName, PackageList, Inffile = None):
849 for P in PackageList:
850 ProtocolKeys = P.Protocols.keys()
851 if Inffile and P._PrivateProtocols:
852 if not Inffile.startswith(P.MetaFile.Dir):
853 ProtocolKeys = (dict.fromkeys(x for x in P.Protocols if x not in P._PrivateProtocols)).keys()
854 if CName in ProtocolKeys:
855 return P.Protocols[CName]
856 return None
857
858 ## Get PPI value from given packages
859 #
860 # @param CName The CName of the GUID
861 # @param PackageList List of packages looking-up in
862 # @param Inffile The driver file
863 #
864 # @retval GuidValue if the CName is found in any given package
865 # @retval None if the CName is not found in all given packages
866 #
867 def PpiValue(CName, PackageList, Inffile = None):
868 for P in PackageList:
869 PpiKeys = P.Ppis.keys()
870 if Inffile and P._PrivatePpis:
871 if not Inffile.startswith(P.MetaFile.Dir):
872 PpiKeys = (dict.fromkeys(x for x in P.Ppis if x not in P._PrivatePpis)).keys()
873 if CName in PpiKeys:
874 return P.Ppis[CName]
875 return None
876
877 ## A string template class
878 #
879 # This class implements a template for string replacement. A string template
880 # looks like following
881 #
882 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
883 #
884 # The string between ${BEGIN} and ${END} will be repeated as many times as the
885 # length of "placeholder_name", which is a list passed through a dict. The
886 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
887 # be not used and, in this case, the "placeholder_name" must not a list and it
888 # will just be replaced once.
889 #
890 class TemplateString(object):
891 _REPEAT_START_FLAG = "BEGIN"
892 _REPEAT_END_FLAG = "END"
893
894 class Section(object):
895 _LIST_TYPES = [type([]), type(set()), type((0,))]
896
897 def __init__(self, TemplateSection, PlaceHolderList):
898 self._Template = TemplateSection
899 self._PlaceHolderList = []
900
901 # Split the section into sub-sections according to the position of placeholders
902 if PlaceHolderList:
903 self._SubSectionList = []
904 SubSectionStart = 0
905 #
906 # The placeholders passed in must be in the format of
907 #
908 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
909 #
910 for PlaceHolder, Start, End in PlaceHolderList:
911 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
912 self._SubSectionList.append(TemplateSection[Start:End])
913 self._PlaceHolderList.append(PlaceHolder)
914 SubSectionStart = End
915 if SubSectionStart < len(TemplateSection):
916 self._SubSectionList.append(TemplateSection[SubSectionStart:])
917 else:
918 self._SubSectionList = [TemplateSection]
919
920 def __str__(self):
921 return self._Template + " : " + str(self._PlaceHolderList)
922
923 def Instantiate(self, PlaceHolderValues):
924 RepeatTime = -1
925 RepeatPlaceHolders = {}
926 NonRepeatPlaceHolders = {}
927
928 for PlaceHolder in self._PlaceHolderList:
929 if PlaceHolder not in PlaceHolderValues:
930 continue
931 Value = PlaceHolderValues[PlaceHolder]
932 if type(Value) in self._LIST_TYPES:
933 if RepeatTime < 0:
934 RepeatTime = len(Value)
935 elif RepeatTime != len(Value):
936 EdkLogger.error(
937 "TemplateString",
938 PARAMETER_INVALID,
939 "${%s} has different repeat time from others!" % PlaceHolder,
940 ExtraData=str(self._Template)
941 )
942 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
943 else:
944 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
945
946 if NonRepeatPlaceHolders:
947 StringList = []
948 for S in self._SubSectionList:
949 if S not in NonRepeatPlaceHolders:
950 StringList.append(S)
951 else:
952 StringList.append(str(NonRepeatPlaceHolders[S]))
953 else:
954 StringList = self._SubSectionList
955
956 if RepeatPlaceHolders:
957 TempStringList = []
958 for Index in range(RepeatTime):
959 for S in StringList:
960 if S not in RepeatPlaceHolders:
961 TempStringList.append(S)
962 else:
963 TempStringList.append(str(RepeatPlaceHolders[S][Index]))
964 StringList = TempStringList
965
966 return "".join(StringList)
967
968 ## Constructor
969 def __init__(self, Template=None):
970 self.String = ''
971 self.IsBinary = False
972 self._Template = Template
973 self._TemplateSectionList = self._Parse(Template)
974
975 ## str() operator
976 #
977 # @retval string The string replaced
978 #
979 def __str__(self):
980 return self.String
981
982 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
983 #
984 # @retval list A list of TemplateString.Section objects
985 #
986 def _Parse(self, Template):
987 SectionStart = 0
988 SearchFrom = 0
989 MatchEnd = 0
990 PlaceHolderList = []
991 TemplateSectionList = []
992 while Template:
993 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
994 if not MatchObj:
995 if MatchEnd <= len(Template):
996 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
997 TemplateSectionList.append(TemplateSection)
998 break
999
1000 MatchString = MatchObj.group(1)
1001 MatchStart = MatchObj.start()
1002 MatchEnd = MatchObj.end()
1003
1004 if MatchString == self._REPEAT_START_FLAG:
1005 if MatchStart > SectionStart:
1006 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
1007 TemplateSectionList.append(TemplateSection)
1008 SectionStart = MatchEnd
1009 PlaceHolderList = []
1010 elif MatchString == self._REPEAT_END_FLAG:
1011 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
1012 TemplateSectionList.append(TemplateSection)
1013 SectionStart = MatchEnd
1014 PlaceHolderList = []
1015 else:
1016 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
1017 SearchFrom = MatchEnd
1018 return TemplateSectionList
1019
1020 ## Replace the string template with dictionary of placeholders and append it to previous one
1021 #
1022 # @param AppendString The string template to append
1023 # @param Dictionary The placeholder dictionaries
1024 #
1025 def Append(self, AppendString, Dictionary=None):
1026 if Dictionary:
1027 SectionList = self._Parse(AppendString)
1028 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])
1029 else:
1030 self.String += AppendString
1031
1032 ## Replace the string template with dictionary of placeholders
1033 #
1034 # @param Dictionary The placeholder dictionaries
1035 #
1036 # @retval str The string replaced with placeholder values
1037 #
1038 def Replace(self, Dictionary=None):
1039 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])
1040
1041 ## Progress indicator class
1042 #
1043 # This class makes use of thread to print progress on console.
1044 #
1045 class Progressor:
1046 # for avoiding deadloop
1047 _StopFlag = None
1048 _ProgressThread = None
1049 _CheckInterval = 0.25
1050
1051 ## Constructor
1052 #
1053 # @param OpenMessage The string printed before progress charaters
1054 # @param CloseMessage The string printed after progress charaters
1055 # @param ProgressChar The charater used to indicate the progress
1056 # @param Interval The interval in seconds between two progress charaters
1057 #
1058 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
1059 self.PromptMessage = OpenMessage
1060 self.CodaMessage = CloseMessage
1061 self.ProgressChar = ProgressChar
1062 self.Interval = Interval
1063 if Progressor._StopFlag == None:
1064 Progressor._StopFlag = threading.Event()
1065
1066 ## Start to print progress charater
1067 #
1068 # @param OpenMessage The string printed before progress charaters
1069 #
1070 def Start(self, OpenMessage=None):
1071 if OpenMessage != None:
1072 self.PromptMessage = OpenMessage
1073 Progressor._StopFlag.clear()
1074 if Progressor._ProgressThread == None:
1075 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
1076 Progressor._ProgressThread.setDaemon(False)
1077 Progressor._ProgressThread.start()
1078
1079 ## Stop printing progress charater
1080 #
1081 # @param CloseMessage The string printed after progress charaters
1082 #
1083 def Stop(self, CloseMessage=None):
1084 OriginalCodaMessage = self.CodaMessage
1085 if CloseMessage != None:
1086 self.CodaMessage = CloseMessage
1087 self.Abort()
1088 self.CodaMessage = OriginalCodaMessage
1089
1090 ## Thread entry method
1091 def _ProgressThreadEntry(self):
1092 sys.stdout.write(self.PromptMessage + " ")
1093 sys.stdout.flush()
1094 TimeUp = 0.0
1095 while not Progressor._StopFlag.isSet():
1096 if TimeUp <= 0.0:
1097 sys.stdout.write(self.ProgressChar)
1098 sys.stdout.flush()
1099 TimeUp = self.Interval
1100 time.sleep(self._CheckInterval)
1101 TimeUp -= self._CheckInterval
1102 sys.stdout.write(" " + self.CodaMessage + "\n")
1103 sys.stdout.flush()
1104
1105 ## Abort the progress display
1106 @staticmethod
1107 def Abort():
1108 if Progressor._StopFlag != None:
1109 Progressor._StopFlag.set()
1110 if Progressor._ProgressThread != None:
1111 Progressor._ProgressThread.join()
1112 Progressor._ProgressThread = None
1113
1114 ## A dict which can access its keys and/or values orderly
1115 #
1116 # The class implements a new kind of dict which its keys or values can be
1117 # accessed in the order they are added into the dict. It guarantees the order
1118 # by making use of an internal list to keep a copy of keys.
1119 #
1120 class sdict(IterableUserDict):
1121 ## Constructor
1122 def __init__(self):
1123 IterableUserDict.__init__(self)
1124 self._key_list = []
1125
1126 ## [] operator
1127 def __setitem__(self, key, value):
1128 if key not in self._key_list:
1129 self._key_list.append(key)
1130 IterableUserDict.__setitem__(self, key, value)
1131
1132 ## del operator
1133 def __delitem__(self, key):
1134 self._key_list.remove(key)
1135 IterableUserDict.__delitem__(self, key)
1136
1137 ## used in "for k in dict" loop to ensure the correct order
1138 def __iter__(self):
1139 return self.iterkeys()
1140
1141 ## len() support
1142 def __len__(self):
1143 return len(self._key_list)
1144
1145 ## "in" test support
1146 def __contains__(self, key):
1147 return key in self._key_list
1148
1149 ## indexof support
1150 def index(self, key):
1151 return self._key_list.index(key)
1152
1153 ## insert support
1154 def insert(self, key, newkey, newvalue, order):
1155 index = self._key_list.index(key)
1156 if order == 'BEFORE':
1157 self._key_list.insert(index, newkey)
1158 IterableUserDict.__setitem__(self, newkey, newvalue)
1159 elif order == 'AFTER':
1160 self._key_list.insert(index + 1, newkey)
1161 IterableUserDict.__setitem__(self, newkey, newvalue)
1162
1163 ## append support
1164 def append(self, sdict):
1165 for key in sdict:
1166 if key not in self._key_list:
1167 self._key_list.append(key)
1168 IterableUserDict.__setitem__(self, key, sdict[key])
1169
1170 def has_key(self, key):
1171 return key in self._key_list
1172
1173 ## Empty the dict
1174 def clear(self):
1175 self._key_list = []
1176 IterableUserDict.clear(self)
1177
1178 ## Return a copy of keys
1179 def keys(self):
1180 keys = []
1181 for key in self._key_list:
1182 keys.append(key)
1183 return keys
1184
1185 ## Return a copy of values
1186 def values(self):
1187 values = []
1188 for key in self._key_list:
1189 values.append(self[key])
1190 return values
1191
1192 ## Return a copy of (key, value) list
1193 def items(self):
1194 items = []
1195 for key in self._key_list:
1196 items.append((key, self[key]))
1197 return items
1198
1199 ## Iteration support
1200 def iteritems(self):
1201 return iter(self.items())
1202
1203 ## Keys interation support
1204 def iterkeys(self):
1205 return iter(self.keys())
1206
1207 ## Values interation support
1208 def itervalues(self):
1209 return iter(self.values())
1210
1211 ## Return value related to a key, and remove the (key, value) from the dict
1212 def pop(self, key, *dv):
1213 value = None
1214 if key in self._key_list:
1215 value = self[key]
1216 self.__delitem__(key)
1217 elif len(dv) != 0 :
1218 value = kv[0]
1219 return value
1220
1221 ## Return (key, value) pair, and remove the (key, value) from the dict
1222 def popitem(self):
1223 key = self._key_list[-1]
1224 value = self[key]
1225 self.__delitem__(key)
1226 return key, value
1227
1228 def update(self, dict=None, **kwargs):
1229 if dict != None:
1230 for k, v in dict.items():
1231 self[k] = v
1232 if len(kwargs):
1233 for k, v in kwargs.items():
1234 self[k] = v
1235
1236 ## Dictionary with restricted keys
1237 #
1238 class rdict(dict):
1239 ## Constructor
1240 def __init__(self, KeyList):
1241 for Key in KeyList:
1242 dict.__setitem__(self, Key, "")
1243
1244 ## []= operator
1245 def __setitem__(self, key, value):
1246 if key not in self:
1247 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,
1248 ExtraData=", ".join(dict.keys(self)))
1249 dict.__setitem__(self, key, value)
1250
1251 ## =[] operator
1252 def __getitem__(self, key):
1253 if key not in self:
1254 return ""
1255 return dict.__getitem__(self, key)
1256
1257 ## del operator
1258 def __delitem__(self, key):
1259 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")
1260
1261 ## Empty the dict
1262 def clear(self):
1263 for Key in self:
1264 self.__setitem__(Key, "")
1265
1266 ## Return value related to a key, and remove the (key, value) from the dict
1267 def pop(self, key, *dv):
1268 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")
1269
1270 ## Return (key, value) pair, and remove the (key, value) from the dict
1271 def popitem(self):
1272 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")
1273
1274 ## Dictionary using prioritized list as key
1275 #
1276 class tdict:
1277 _ListType = type([])
1278 _TupleType = type(())
1279 _Wildcard = 'COMMON'
1280 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1281
1282 def __init__(self, _Single_=False, _Level_=2):
1283 self._Level_ = _Level_
1284 self.data = {}
1285 self._Single_ = _Single_
1286
1287 # =[] operator
1288 def __getitem__(self, key):
1289 KeyType = type(key)
1290 RestKeys = None
1291 if KeyType == self._ListType or KeyType == self._TupleType:
1292 FirstKey = key[0]
1293 if len(key) > 1:
1294 RestKeys = key[1:]
1295 elif self._Level_ > 1:
1296 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1297 else:
1298 FirstKey = key
1299 if self._Level_ > 1:
1300 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1301
1302 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:
1303 FirstKey = self._Wildcard
1304
1305 if self._Single_:
1306 return self._GetSingleValue(FirstKey, RestKeys)
1307 else:
1308 return self._GetAllValues(FirstKey, RestKeys)
1309
1310 def _GetSingleValue(self, FirstKey, RestKeys):
1311 Value = None
1312 #print "%s-%s" % (FirstKey, self._Level_) ,
1313 if self._Level_ > 1:
1314 if FirstKey == self._Wildcard:
1315 if FirstKey in self.data:
1316 Value = self.data[FirstKey][RestKeys]
1317 if Value == None:
1318 for Key in self.data:
1319 Value = self.data[Key][RestKeys]
1320 if Value != None: break
1321 else:
1322 if FirstKey in self.data:
1323 Value = self.data[FirstKey][RestKeys]
1324 if Value == None and self._Wildcard in self.data:
1325 #print "Value=None"
1326 Value = self.data[self._Wildcard][RestKeys]
1327 else:
1328 if FirstKey == self._Wildcard:
1329 if FirstKey in self.data:
1330 Value = self.data[FirstKey]
1331 if Value == None:
1332 for Key in self.data:
1333 Value = self.data[Key]
1334 if Value != None: break
1335 else:
1336 if FirstKey in self.data:
1337 Value = self.data[FirstKey]
1338 elif self._Wildcard in self.data:
1339 Value = self.data[self._Wildcard]
1340 return Value
1341
1342 def _GetAllValues(self, FirstKey, RestKeys):
1343 Value = []
1344 if self._Level_ > 1:
1345 if FirstKey == self._Wildcard:
1346 for Key in self.data:
1347 Value += self.data[Key][RestKeys]
1348 else:
1349 if FirstKey in self.data:
1350 Value += self.data[FirstKey][RestKeys]
1351 if self._Wildcard in self.data:
1352 Value += self.data[self._Wildcard][RestKeys]
1353 else:
1354 if FirstKey == self._Wildcard:
1355 for Key in self.data:
1356 Value.append(self.data[Key])
1357 else:
1358 if FirstKey in self.data:
1359 Value.append(self.data[FirstKey])
1360 if self._Wildcard in self.data:
1361 Value.append(self.data[self._Wildcard])
1362 return Value
1363
1364 ## []= operator
1365 def __setitem__(self, key, value):
1366 KeyType = type(key)
1367 RestKeys = None
1368 if KeyType == self._ListType or KeyType == self._TupleType:
1369 FirstKey = key[0]
1370 if len(key) > 1:
1371 RestKeys = key[1:]
1372 else:
1373 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1374 else:
1375 FirstKey = key
1376 if self._Level_ > 1:
1377 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
1378
1379 if FirstKey in self._ValidWildcardList:
1380 FirstKey = self._Wildcard
1381
1382 if FirstKey not in self.data and self._Level_ > 0:
1383 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
1384
1385 if self._Level_ > 1:
1386 self.data[FirstKey][RestKeys] = value
1387 else:
1388 self.data[FirstKey] = value
1389
1390 def SetGreedyMode(self):
1391 self._Single_ = False
1392 if self._Level_ > 1:
1393 for Key in self.data:
1394 self.data[Key].SetGreedyMode()
1395
1396 def SetSingleMode(self):
1397 self._Single_ = True
1398 if self._Level_ > 1:
1399 for Key in self.data:
1400 self.data[Key].SetSingleMode()
1401
1402 def GetKeys(self, KeyIndex=0):
1403 assert KeyIndex >= 0
1404 if KeyIndex == 0:
1405 return set(self.data.keys())
1406 else:
1407 keys = set()
1408 for Key in self.data:
1409 keys |= self.data[Key].GetKeys(KeyIndex - 1)
1410 return keys
1411
1412 ## Boolean chain list
1413 #
1414 class Blist(UserList):
1415 def __init__(self, initlist=None):
1416 UserList.__init__(self, initlist)
1417 def __setitem__(self, i, item):
1418 if item not in [True, False]:
1419 if item == 0:
1420 item = False
1421 else:
1422 item = True
1423 self.data[i] = item
1424 def _GetResult(self):
1425 Value = True
1426 for item in self.data:
1427 Value &= item
1428 return Value
1429 Result = property(_GetResult)
1430
1431 def ParseConsoleLog(Filename):
1432 Opr = open(os.path.normpath(Filename), 'r')
1433 Opw = open(os.path.normpath(Filename + '.New'), 'w+')
1434 for Line in Opr.readlines():
1435 if Line.find('.efi') > -1:
1436 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()
1437 Opw.write('%s\n' % Line)
1438
1439 Opr.close()
1440 Opw.close()
1441
1442 def AnalyzePcdExpression(Setting):
1443 Setting = Setting.strip()
1444 # There might be escaped quote in a string: \", \\\"
1445 Data = Setting.replace('\\\\', '//').replace('\\\"', '\\\'')
1446 # There might be '|' in string and in ( ... | ... ), replace it with '-'
1447 NewStr = ''
1448 InStr = False
1449 Pair = 0
1450 for ch in Data:
1451 if ch == '"':
1452 InStr = not InStr
1453 elif ch == '(' and not InStr:
1454 Pair += 1
1455 elif ch == ')' and not InStr:
1456 Pair -= 1
1457
1458 if (Pair > 0 or InStr) and ch == TAB_VALUE_SPLIT:
1459 NewStr += '-'
1460 else:
1461 NewStr += ch
1462 FieldList = []
1463 StartPos = 0
1464 while True:
1465 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)
1466 if Pos < 0:
1467 FieldList.append(Setting[StartPos:].strip())
1468 break
1469 FieldList.append(Setting[StartPos:Pos].strip())
1470 StartPos = Pos + 1
1471
1472 return FieldList
1473
1474 ## AnalyzeDscPcd
1475 #
1476 # Analyze DSC PCD value, since there is no data type info in DSC
1477 # This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database
1478 # 1. Feature flag: TokenSpace.PcdCName|PcdValue
1479 # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]
1480 # 3. Dynamic default:
1481 # TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
1482 # TokenSpace.PcdCName|PcdValue
1483 # 4. Dynamic VPD:
1484 # TokenSpace.PcdCName|VpdOffset[|VpdValue]
1485 # TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
1486 # 5. Dynamic HII:
1487 # TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]
1488 # PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
1489 # there might have "|" operator, also in string value.
1490 #
1491 # @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
1492 # @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
1493 # @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
1494 # @retval:
1495 # ValueList: A List contain fields described above
1496 # IsValid: True if conforming EBNF, otherwise False
1497 # Index: The index where PcdValue is in ValueList
1498 #
1499 def AnalyzeDscPcd(Setting, PcdType, DataType=''):
1500 FieldList = AnalyzePcdExpression(Setting)
1501
1502 IsValid = True
1503 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):
1504 Value = FieldList[0]
1505 Size = ''
1506 if len(FieldList) > 1:
1507 Type = FieldList[1]
1508 # Fix the PCD type when no DataType input
1509 if Type == 'VOID*':
1510 DataType = 'VOID*'
1511 else:
1512 Size = FieldList[1]
1513 if len(FieldList) > 2:
1514 Size = FieldList[2]
1515 if DataType == 'VOID*':
1516 IsValid = (len(FieldList) <= 3)
1517 else:
1518 IsValid = (len(FieldList) <= 1)
1519 return [Value, '', Size], IsValid, 0
1520 elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
1521 Value = FieldList[0]
1522 Size = Type = ''
1523 if len(FieldList) > 1:
1524 Type = FieldList[1]
1525 else:
1526 Type = DataType
1527 if len(FieldList) > 2:
1528 Size = FieldList[2]
1529 else:
1530 if Type == 'VOID*':
1531 if Value.startswith("L"):
1532 Size = str((len(Value)- 3 + 1) * 2)
1533 elif Value.startswith("{"):
1534 Size = str(len(Value.split(",")))
1535 else:
1536 Size = str(len(Value) -2 + 1 )
1537 if DataType == 'VOID*':
1538 IsValid = (len(FieldList) <= 3)
1539 else:
1540 IsValid = (len(FieldList) <= 1)
1541 return [Value, Type, Size], IsValid, 0
1542 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):
1543 VpdOffset = FieldList[0]
1544 Value = Size = ''
1545 if not DataType == 'VOID*':
1546 if len(FieldList) > 1:
1547 Value = FieldList[1]
1548 else:
1549 if len(FieldList) > 1:
1550 Size = FieldList[1]
1551 if len(FieldList) > 2:
1552 Value = FieldList[2]
1553 if DataType == 'VOID*':
1554 IsValid = (len(FieldList) <= 3)
1555 else:
1556 IsValid = (len(FieldList) <= 2)
1557 return [VpdOffset, Size, Value], IsValid, 2
1558 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):
1559 HiiString = FieldList[0]
1560 Guid = Offset = Value = Attribute = ''
1561 if len(FieldList) > 1:
1562 Guid = FieldList[1]
1563 if len(FieldList) > 2:
1564 Offset = FieldList[2]
1565 if len(FieldList) > 3:
1566 Value = FieldList[3]
1567 if len(FieldList) > 4:
1568 Attribute = FieldList[4]
1569 IsValid = (3 <= len(FieldList) <= 5)
1570 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3
1571 return [], False, 0
1572
1573 ## AnalyzePcdData
1574 #
1575 # Analyze the pcd Value, Datum type and TokenNumber.
1576 # Used to avoid split issue while the value string contain "|" character
1577 #
1578 # @param[in] Setting: A String contain value/datum type/token number information;
1579 #
1580 # @retval ValueList: A List contain value, datum type and toke number.
1581 #
1582 def AnalyzePcdData(Setting):
1583 ValueList = ['', '', '']
1584
1585 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1586 PtrValue = ValueRe.findall(Setting)
1587
1588 ValueUpdateFlag = False
1589
1590 if len(PtrValue) >= 1:
1591 Setting = re.sub(ValueRe, '', Setting)
1592 ValueUpdateFlag = True
1593
1594 TokenList = Setting.split(TAB_VALUE_SPLIT)
1595 ValueList[0:len(TokenList)] = TokenList
1596
1597 if ValueUpdateFlag:
1598 ValueList[0] = PtrValue[0]
1599
1600 return ValueList
1601
1602 ## AnalyzeHiiPcdData
1603 #
1604 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1605 # Used to avoid split issue while the value string contain "|" character
1606 #
1607 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1608 #
1609 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1610 #
1611 def AnalyzeHiiPcdData(Setting):
1612 ValueList = ['', '', '', '']
1613
1614 TokenList = GetSplitValueList(Setting)
1615 ValueList[0:len(TokenList)] = TokenList
1616
1617 return ValueList
1618
1619 ## AnalyzeVpdPcdData
1620 #
1621 # Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue.
1622 # Used to avoid split issue while the value string contain "|" character
1623 #
1624 # @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information;
1625 #
1626 # @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue.
1627 #
1628 def AnalyzeVpdPcdData(Setting):
1629 ValueList = ['', '', '']
1630
1631 ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$')
1632 PtrValue = ValueRe.findall(Setting)
1633
1634 ValueUpdateFlag = False
1635
1636 if len(PtrValue) >= 1:
1637 Setting = re.sub(ValueRe, '', Setting)
1638 ValueUpdateFlag = True
1639
1640 TokenList = Setting.split(TAB_VALUE_SPLIT)
1641 ValueList[0:len(TokenList)] = TokenList
1642
1643 if ValueUpdateFlag:
1644 ValueList[2] = PtrValue[0]
1645
1646 return ValueList
1647
1648 ## check format of PCD value against its the datum type
1649 #
1650 # For PCD value setting
1651 #
1652 def CheckPcdDatum(Type, Value):
1653 if Type == "VOID*":
1654 ValueRe = re.compile(r'\s*L?\".*\"\s*$')
1655 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))
1656 or (Value.startswith('{') and Value.endswith('}'))
1657 ):
1658 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1659 ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
1660 elif ValueRe.match(Value):
1661 # Check the chars in UnicodeString or CString is printable
1662 if Value.startswith("L"):
1663 Value = Value[2:-1]
1664 else:
1665 Value = Value[1:-1]
1666 Printset = set(string.printable)
1667 Printset.remove(TAB_PRINTCHAR_VT)
1668 Printset.add(TAB_PRINTCHAR_BS)
1669 Printset.add(TAB_PRINTCHAR_NUL)
1670 if not set(Value).issubset(Printset):
1671 PrintList = list(Printset)
1672 PrintList.sort()
1673 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)
1674 elif Type == 'BOOLEAN':
1675 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1676 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1677 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)
1678 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:
1679 try:
1680 Value = long(Value, 0)
1681 except:
1682 return False, "Invalid value [%s] of type [%s];"\
1683 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)
1684 else:
1685 return False, "Invalid type [%s]; must be one of VOID*, BOOLEAN, UINT8, UINT16, UINT32, UINT64." % (Type)
1686
1687 return True, ""
1688
1689 ## Split command line option string to list
1690 #
1691 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1692 # in non-windows platform to launch command
1693 #
1694 def SplitOption(OptionString):
1695 OptionList = []
1696 LastChar = " "
1697 OptionStart = 0
1698 QuotationMark = ""
1699 for Index in range(0, len(OptionString)):
1700 CurrentChar = OptionString[Index]
1701 if CurrentChar in ['"', "'"]:
1702 if QuotationMark == CurrentChar:
1703 QuotationMark = ""
1704 elif QuotationMark == "":
1705 QuotationMark = CurrentChar
1706 continue
1707 elif QuotationMark:
1708 continue
1709
1710 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
1711 if Index > OptionStart:
1712 OptionList.append(OptionString[OptionStart:Index - 1])
1713 OptionStart = Index
1714 LastChar = CurrentChar
1715 OptionList.append(OptionString[OptionStart:])
1716 return OptionList
1717
1718 def CommonPath(PathList):
1719 P1 = min(PathList).split(os.path.sep)
1720 P2 = max(PathList).split(os.path.sep)
1721 for Index in xrange(min(len(P1), len(P2))):
1722 if P1[Index] != P2[Index]:
1723 return os.path.sep.join(P1[:Index])
1724 return os.path.sep.join(P1)
1725
1726 #
1727 # Convert string to C format array
1728 #
1729 def ConvertStringToByteArray(Value):
1730 Value = Value.strip()
1731 if not Value:
1732 return None
1733 if Value[0] == '{':
1734 if not Value.endswith('}'):
1735 return None
1736 Value = Value.replace(' ', '').replace('{', '').replace('}', '')
1737 ValFields = Value.split(',')
1738 try:
1739 for Index in range(len(ValFields)):
1740 ValFields[Index] = str(int(ValFields[Index], 0))
1741 except ValueError:
1742 return None
1743 Value = '{' + ','.join(ValFields) + '}'
1744 return Value
1745
1746 Unicode = False
1747 if Value.startswith('L"'):
1748 if not Value.endswith('"'):
1749 return None
1750 Value = Value[1:]
1751 Unicode = True
1752 elif not Value.startswith('"') or not Value.endswith('"'):
1753 return None
1754
1755 Value = eval(Value) # translate escape character
1756 NewValue = '{'
1757 for Index in range(0,len(Value)):
1758 if Unicode:
1759 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','
1760 else:
1761 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','
1762 Value = NewValue + '0}'
1763 return Value
1764
1765 class PathClass(object):
1766 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
1767 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):
1768 self.Arch = Arch
1769 self.File = str(File)
1770 if os.path.isabs(self.File):
1771 self.Root = ''
1772 self.AlterRoot = ''
1773 else:
1774 self.Root = str(Root)
1775 self.AlterRoot = str(AlterRoot)
1776
1777 # Remove any '.' and '..' in path
1778 if self.Root:
1779 self.Root = mws.getWs(self.Root, self.File)
1780 self.Path = os.path.normpath(os.path.join(self.Root, self.File))
1781 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
1782 # eliminate the side-effect of 'C:'
1783 if self.Root[-1] == ':':
1784 self.Root += os.path.sep
1785 # file path should not start with path separator
1786 if self.Root[-1] == os.path.sep:
1787 self.File = self.Path[len(self.Root):]
1788 else:
1789 self.File = self.Path[len(self.Root) + 1:]
1790 else:
1791 self.Path = os.path.normpath(self.File)
1792
1793 self.SubDir, self.Name = os.path.split(self.File)
1794 self.BaseName, self.Ext = os.path.splitext(self.Name)
1795
1796 if self.Root:
1797 if self.SubDir:
1798 self.Dir = os.path.join(self.Root, self.SubDir)
1799 else:
1800 self.Dir = self.Root
1801 else:
1802 self.Dir = self.SubDir
1803
1804 if IsBinary:
1805 self.Type = Type
1806 else:
1807 self.Type = self.Ext.lower()
1808
1809 self.IsBinary = IsBinary
1810 self.Target = Target
1811 self.TagName = TagName
1812 self.ToolCode = ToolCode
1813 self.ToolChainFamily = ToolChainFamily
1814
1815 self._Key = None
1816
1817 ## Convert the object of this class to a string
1818 #
1819 # Convert member Path of the class to a string
1820 #
1821 # @retval string Formatted String
1822 #
1823 def __str__(self):
1824 return self.Path
1825
1826 ## Override __eq__ function
1827 #
1828 # Check whether PathClass are the same
1829 #
1830 # @retval False The two PathClass are different
1831 # @retval True The two PathClass are the same
1832 #
1833 def __eq__(self, Other):
1834 if type(Other) == type(self):
1835 return self.Path == Other.Path
1836 else:
1837 return self.Path == str(Other)
1838
1839 ## Override __cmp__ function
1840 #
1841 # Customize the comparsion operation of two PathClass
1842 #
1843 # @retval 0 The two PathClass are different
1844 # @retval -1 The first PathClass is less than the second PathClass
1845 # @retval 1 The first PathClass is Bigger than the second PathClass
1846 def __cmp__(self, Other):
1847 if type(Other) == type(self):
1848 OtherKey = Other.Path
1849 else:
1850 OtherKey = str(Other)
1851
1852 SelfKey = self.Path
1853 if SelfKey == OtherKey:
1854 return 0
1855 elif SelfKey > OtherKey:
1856 return 1
1857 else:
1858 return -1
1859
1860 ## Override __hash__ function
1861 #
1862 # Use Path as key in hash table
1863 #
1864 # @retval string Key for hash table
1865 #
1866 def __hash__(self):
1867 return hash(self.Path)
1868
1869 def _GetFileKey(self):
1870 if self._Key == None:
1871 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1872 return self._Key
1873
1874 def _GetTimeStamp(self):
1875 return os.stat(self.Path)[8]
1876
1877 def Validate(self, Type='', CaseSensitive=True):
1878 if GlobalData.gCaseInsensitive:
1879 CaseSensitive = False
1880 if Type and Type.lower() != self.Type:
1881 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)
1882
1883 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
1884 if not RealRoot and not RealFile:
1885 RealFile = self.File
1886 if self.AlterRoot:
1887 RealFile = os.path.join(self.AlterRoot, self.File)
1888 elif self.Root:
1889 RealFile = os.path.join(self.Root, self.File)
1890 if len (mws.getPkgPath()) == 0:
1891 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
1892 else:
1893 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))
1894
1895 ErrorCode = 0
1896 ErrorInfo = ''
1897 if RealRoot != self.Root or RealFile != self.File:
1898 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):
1899 ErrorCode = FILE_CASE_MISMATCH
1900 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"
1901
1902 self.SubDir, self.Name = os.path.split(RealFile)
1903 self.BaseName, self.Ext = os.path.splitext(self.Name)
1904 if self.SubDir:
1905 self.Dir = os.path.join(RealRoot, self.SubDir)
1906 else:
1907 self.Dir = RealRoot
1908 self.File = RealFile
1909 self.Root = RealRoot
1910 self.Path = os.path.join(RealRoot, RealFile)
1911 return ErrorCode, ErrorInfo
1912
1913 Key = property(_GetFileKey)
1914 TimeStamp = property(_GetTimeStamp)
1915
1916 ## Parse PE image to get the required PE informaion.
1917 #
1918 class PeImageClass():
1919 ## Constructor
1920 #
1921 # @param File FilePath of PeImage
1922 #
1923 def __init__(self, PeFile):
1924 self.FileName = PeFile
1925 self.IsValid = False
1926 self.Size = 0
1927 self.EntryPoint = 0
1928 self.SectionAlignment = 0
1929 self.SectionHeaderList = []
1930 self.ErrorInfo = ''
1931 try:
1932 PeObject = open(PeFile, 'rb')
1933 except:
1934 self.ErrorInfo = self.FileName + ' can not be found\n'
1935 return
1936 # Read DOS header
1937 ByteArray = array.array('B')
1938 ByteArray.fromfile(PeObject, 0x3E)
1939 ByteList = ByteArray.tolist()
1940 # DOS signature should be 'MZ'
1941 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':
1942 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'
1943 return
1944
1945 # Read 4 byte PE Signature
1946 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])
1947 PeObject.seek(PeOffset)
1948 ByteArray = array.array('B')
1949 ByteArray.fromfile(PeObject, 4)
1950 # PE signature should be 'PE\0\0'
1951 if ByteArray.tostring() != 'PE\0\0':
1952 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'
1953 return
1954
1955 # Read PE file header
1956 ByteArray = array.array('B')
1957 ByteArray.fromfile(PeObject, 0x14)
1958 ByteList = ByteArray.tolist()
1959 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])
1960 if SecNumber == 0:
1961 self.ErrorInfo = self.FileName + ' has no section header'
1962 return
1963
1964 # Read PE optional header
1965 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])
1966 ByteArray = array.array('B')
1967 ByteArray.fromfile(PeObject, OptionalHeaderSize)
1968 ByteList = ByteArray.tolist()
1969 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])
1970 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])
1971 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])
1972
1973 # Read each Section Header
1974 for Index in range(SecNumber):
1975 ByteArray = array.array('B')
1976 ByteArray.fromfile(PeObject, 0x28)
1977 ByteList = ByteArray.tolist()
1978 SecName = self._ByteListToStr(ByteList[0:8])
1979 SecVirtualSize = self._ByteListToInt(ByteList[8:12])
1980 SecRawAddress = self._ByteListToInt(ByteList[20:24])
1981 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])
1982 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))
1983 self.IsValid = True
1984 PeObject.close()
1985
1986 def _ByteListToStr(self, ByteList):
1987 String = ''
1988 for index in range(len(ByteList)):
1989 if ByteList[index] == 0:
1990 break
1991 String += chr(ByteList[index])
1992 return String
1993
1994 def _ByteListToInt(self, ByteList):
1995 Value = 0
1996 for index in range(len(ByteList) - 1, -1, -1):
1997 Value = (Value << 8) | int(ByteList[index])
1998 return Value
1999
2000
2001 class SkuClass():
2002
2003 DEFAULT = 0
2004 SINGLE = 1
2005 MULTIPLE =2
2006
2007 def __init__(self,SkuIdentifier='', SkuIds={}):
2008
2009 self.AvailableSkuIds = sdict()
2010 self.SkuIdSet = []
2011 self.SkuIdNumberSet = []
2012 if SkuIdentifier == '' or SkuIdentifier is None:
2013 self.SkuIdSet = ['DEFAULT']
2014 self.SkuIdNumberSet = ['0U']
2015 elif SkuIdentifier == 'ALL':
2016 self.SkuIdSet = SkuIds.keys()
2017 self.SkuIdNumberSet = [num.strip() + 'U' for num in SkuIds.values()]
2018 else:
2019 r = SkuIdentifier.split('|')
2020 self.SkuIdSet=[r[k].strip() for k in range(len(r))]
2021 k = None
2022 try:
2023 self.SkuIdNumberSet = [SkuIds[k].strip() + 'U' for k in self.SkuIdSet]
2024 except Exception:
2025 EdkLogger.error("build", PARAMETER_INVALID,
2026 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2027 % (k, " | ".join(SkuIds.keys())))
2028 if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet and SkuIdentifier != 'ALL':
2029 self.SkuIdSet.remove('DEFAULT')
2030 self.SkuIdNumberSet.remove('0U')
2031 for each in self.SkuIdSet:
2032 if each in SkuIds:
2033 self.AvailableSkuIds[each] = SkuIds[each]
2034 else:
2035 EdkLogger.error("build", PARAMETER_INVALID,
2036 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
2037 % (each, " | ".join(SkuIds.keys())))
2038
2039 def __SkuUsageType(self):
2040
2041 if len(self.SkuIdSet) == 1:
2042 if self.SkuIdSet[0] == 'DEFAULT':
2043 return SkuClass.DEFAULT
2044 else:
2045 return SkuClass.SINGLE
2046 else:
2047 return SkuClass.MULTIPLE
2048
2049 def __GetAvailableSkuIds(self):
2050 return self.AvailableSkuIds
2051
2052 def __GetSystemSkuID(self):
2053 if self.__SkuUsageType() == SkuClass.SINGLE:
2054 return self.SkuIdSet[0]
2055 else:
2056 return 'DEFAULT'
2057 def __GetAvailableSkuIdNumber(self):
2058 return self.SkuIdNumberSet
2059 SystemSkuId = property(__GetSystemSkuID)
2060 AvailableSkuIdSet = property(__GetAvailableSkuIds)
2061 SkuUsageType = property(__SkuUsageType)
2062 AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)
2063
2064 #
2065 # Pack a registry format GUID
2066 #
2067 def PackRegistryFormatGuid(Guid):
2068 Guid = Guid.split('-')
2069 return pack('=LHHBBBBBBBB',
2070 int(Guid[0], 16),
2071 int(Guid[1], 16),
2072 int(Guid[2], 16),
2073 int(Guid[3][-4:-2], 16),
2074 int(Guid[3][-2:], 16),
2075 int(Guid[4][-12:-10], 16),
2076 int(Guid[4][-10:-8], 16),
2077 int(Guid[4][-8:-6], 16),
2078 int(Guid[4][-6:-4], 16),
2079 int(Guid[4][-4:-2], 16),
2080 int(Guid[4][-2:], 16)
2081 )
2082
2083 def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Value):
2084 if PcdDatumType == 'VOID*':
2085 if Value.startswith('L'):
2086 if not Value[1]:
2087 EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2088 Value = Value[0] + '"' + Value[1:] + '"'
2089 elif Value.startswith('H'):
2090 if not Value[1]:
2091 EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2092 Value = Value[1:]
2093 else:
2094 if not Value[0]:
2095 EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"')
2096 Value = '"' + Value + '"'
2097
2098 IsValid, Cause = CheckPcdDatum(PcdDatumType, Value)
2099 if not IsValid:
2100 EdkLogger.error("build", FORMAT_INVALID, Cause, ExtraData="%s.%s" % (TokenSpaceGuidCName, TokenCName))
2101 if PcdDatumType == 'BOOLEAN':
2102 Value = Value.upper()
2103 if Value == 'TRUE' or Value == '1':
2104 Value = '1'
2105 elif Value == 'FALSE' or Value == '0':
2106 Value = '0'
2107 return Value
2108
2109 ##
2110 #
2111 # This acts like the main() function for the script, unless it is 'import'ed into another
2112 # script.
2113 #
2114 if __name__ == '__main__':
2115 pass
2116