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