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