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