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