c432b8c3eb025ce26fb1ceb56ceeed9939a0366d
[mirror_edk2.git] / Tools / Source / PcdTools / org / tianocore / pcd / action / PlatformPcdPreprocessAction.java
1 /** @file
2 PlatformPcdPreprocessAction class.
3
4 The abstract parent class PlatformPcdPreprocessAction, This class is to collect platform's
5 pcd build information from fpd file.
6 This class will be extended by building tools and wizard tools.
7
8 Copyright (c) 2006, Intel Corporation
9 All rights reserved. This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18 package org.tianocore.pcd.action;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.UUID;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25
26 import org.tianocore.DynamicPcdBuildDefinitionsDocument.DynamicPcdBuildDefinitions;
27 import org.tianocore.PcdBuildDefinitionDocument.PcdBuildDefinition;
28 import org.tianocore.pcd.entity.*;
29 import org.tianocore.pcd.entity.Token;
30 import org.tianocore.pcd.entity.MemoryDatabaseManager;
31 import org.tianocore.pcd.exception.PlatformPcdPreprocessException;
32
33 /**
34 The abstract parent class PlatformPcdPreprocessAction, This class is to collect platform's
35 pcd build information from fpd file.
36 This class will be extended by building tools and wizard tools.
37
38 **/
39 public abstract class PlatformPcdPreprocessAction {
40 ///
41 /// PCD memory database
42 ///
43 private MemoryDatabaseManager pcdDbManager;
44
45 ///
46 /// Errors string when perform preprocess
47 ///
48 private String errorString;
49
50 ///
51 /// the count of errors when perform preprocess
52 ///
53 private int errorCount;
54
55 /**
56 Default contructor function
57 **/
58 public PlatformPcdPreprocessAction() {
59 pcdDbManager = null;
60 errorString = null;
61 }
62
63 /**
64 Set parameter pcdDbManager
65
66 @param pcdDbManager
67 **/
68 public void setPcdDbManager(MemoryDatabaseManager pcdDbManager) {
69 this.pcdDbManager = pcdDbManager;
70 }
71
72 /**
73 Get parameter pcdDbManager
74
75 @return MemoryDatabaseManager
76 **/
77 public MemoryDatabaseManager getPcdDbManager() {
78 return pcdDbManager;
79 }
80 /**
81 Abstract function: retrieve module information from FPD file.
82
83 In building environement, this function will be implementated by FpdParserTask.
84
85 @return List<ModuleInfo> the component array.
86 @throws PlatformPcdPreprocessException get all modules in <ModuleSA> in FPD file.
87
88 **/
89 public abstract List<ModulePcdInfoFromFpd> getComponentsFromFpd()
90 throws PlatformPcdPreprocessException;
91
92 /**
93 Abstract function to get GUID string from SPD file.
94
95 In building evnironment, this function will be implementated by GlobaData.
96
97 @param guidCName the CName of GUID
98
99 @return String Guid information from SPD file.
100 @throws PlatformPcdPreprocessException
101 Fail to get Guid information from SPD file.
102 **/
103 public abstract String getGuidInfoFromSpd(String guidCName)
104 throws PlatformPcdPreprocessException;
105
106 /**
107 Abstract function: Verification the PCD data.
108
109 In different environment, such as building environment and wizard environment,
110 it has different implementation according to optimization.
111
112 @param cName The token name
113 @param moduleName The module who use this PCD token
114 @param datum The PCD's datum
115 @param datumType The PCD's datum type
116 @param maxDatumSize The max size for PCD's Datum.
117
118 @return String exception strings.
119
120 **/
121 public abstract String verifyDatum(String cName,
122 String moduleName,
123 String datum,
124 Token.DATUM_TYPE datumType,
125 int maxDatumSize);
126
127 /**
128 Abstract function: Get dynamic information for a token
129
130 @param token
131 @param moduleName
132
133 @return DynamicPcdBuildDefinitions.PcdBuildData
134 **/
135 public abstract DynamicPcdBuildDefinitions.PcdBuildData
136 getDynamicInfoFromFpd(Token token,
137 String moduleName)
138 throws PlatformPcdPreprocessException;
139
140 /**
141 Abstract function: Get all dynamic PCD information from FPD file.
142
143 @return List<DynamicPcdBuildDefinitions.PcdBuildData> All DYNAMIC PCD list in <DynamicPcdBuildDefinitions> in FPD file.
144 @throws PlatformPcdPreprocessBuildException Failure to get dynamic information list.
145
146 **/
147 public abstract List<DynamicPcdBuildDefinitions.PcdBuildData>
148 getAllDynamicPcdInfoFromFpd()
149 throws PlatformPcdPreprocessException;
150
151 /**
152 Return the error string after preprocess
153
154 @return String error string
155 **/
156 public String getErrorString() {
157 return errorString;
158 }
159
160 public void putError(String error) {
161 if (errorString == null) {
162 errorString = "### ERROR[" + errorCount + "] ###\r\n" + error + "\r\n";
163 } else {
164 errorString += "### ERROR[" + errorCount + "] ###\r\n" + error + "\r\n";
165 }
166
167 errorCount++;
168 }
169
170 /**
171 Collect all PCD information from FPD file into PCD memory database.
172
173 **/
174 public void initPcdMemoryDbWithPlatformInfo()
175 throws PlatformPcdPreprocessException {
176 int index = 0;
177 int pcdIndex = 0;
178 List<PcdBuildDefinition.PcdData> pcdBuildDataArray = new ArrayList<PcdBuildDefinition.PcdData>();
179 PcdBuildDefinition.PcdData pcdBuildData = null;
180 Token token = null;
181 List<ModulePcdInfoFromFpd> modules = null;
182 String primaryKey = null;
183 String exceptionString = null;
184 UsageInstance usageInstance = null;
185 Token.PCD_TYPE pcdType = Token.PCD_TYPE.UNKNOWN;
186 Token.DATUM_TYPE datumType = Token.DATUM_TYPE.UNKNOWN;
187 long tokenNumber = 0;
188 String moduleName = null;
189 String datum = null;
190 int maxDatumSize = 0;
191 String tokenSpaceStrRet = null;
192
193 //
194 // ----------------------------------------------
195 // 1), Get all <ModuleSA> from FPD file.
196 // ----------------------------------------------
197 //
198 modules = getComponentsFromFpd();
199
200 if (modules == null) {
201 throw new PlatformPcdPreprocessException(
202 "No modules found in the FPD file.\nPlease check whether there are elements in <FrameworkModules> in the FPD file!");
203 }
204
205 //
206 // -------------------------------------------------------------------
207 // 2), Loop all modules to process <PcdBuildDeclarations> for each module.
208 // -------------------------------------------------------------------
209 //
210 for (index = 0; index < modules.size(); index++) {
211 //
212 // It is legal for a module does not contains ANY pcd build definitions.
213 //
214 if (modules.get(index).pcdBuildDefinition == null) {
215 continue;
216 }
217
218 pcdBuildDataArray = modules.get(index).pcdBuildDefinition.getPcdDataList();
219
220 moduleName = modules.get(index).usageId.moduleName;
221
222 //
223 // ----------------------------------------------------------------------
224 // 2.1), Loop all Pcd entry for a module and add it into memory database.
225 // ----------------------------------------------------------------------
226 //
227 for (pcdIndex = 0; pcdIndex < pcdBuildDataArray.size(); pcdIndex++) {
228 pcdBuildData = pcdBuildDataArray.get(pcdIndex);
229
230 tokenSpaceStrRet = getGuidInfoFromSpd(pcdBuildData.getTokenSpaceGuidCName());
231
232 if (tokenSpaceStrRet == null) {
233 putError("Failed to get Token Space Guid for token " + pcdBuildData.getCName() +
234 " from any SPD file. You must have an <GuidDeclaration> for this Token Space Guid!");
235 //
236 // Do not break preprocess, continues to analysis.
237 // All errors will be summary to be shown.
238 //
239 continue;
240 }
241
242 primaryKey = Token.getPrimaryKeyString(pcdBuildData.getCName(), tokenSpaceStrRet);
243 pcdType = Token.getPcdTypeFromString(pcdBuildData.getItemType().toString());
244 datumType = Token.getdatumTypeFromString(pcdBuildData.getDatumType().toString());
245 tokenNumber = Long.decode(pcdBuildData.getToken().toString());
246 if (pcdBuildData.getValue() != null) {
247 datum = pcdBuildData.getValue().toString();
248 } else {
249 datum = null;
250 }
251 maxDatumSize = pcdBuildData.getMaxDatumSize();
252
253 if ((pcdType == Token.PCD_TYPE.FEATURE_FLAG) &&
254 (datumType != Token.DATUM_TYPE.BOOLEAN)){
255 exceptionString = String.format("In FPD file, for PCD %s in module %s, the PCD type is FEATURE_FLAG but "+
256 "datum type for this PCD entry is not BOOLEAN!",
257 pcdBuildData.getCName(),
258 moduleName);
259 putError(exceptionString);
260 //
261 // Do not break preprocess, continues to analysis.
262 // All errors will be summary to be shown.
263 //
264 continue;
265 }
266
267 //
268 // -------------------------------------------------------------------------------------------
269 // 2.1.1), Do some necessary checking work for FixedAtBuild, FeatureFlag and PatchableInModule
270 // -------------------------------------------------------------------------------------------
271 //
272 if (!Token.isDynamic(pcdType)) {
273 //
274 // Value is required.
275 //
276 if (datum == null) {
277 exceptionString = String.format("In the FPD file, there is no value for PCD entry %s in module %s!",
278 pcdBuildData.getCName(),
279 moduleName);
280 putError(exceptionString);
281 //
282 // Do not break preprocess, continues to analysis.
283 // All errors will be summary to be shown.
284 //
285 continue;
286 }
287
288 //
289 // Check whether the datum size is matched datum type.
290 //
291 if ((exceptionString = verifyDatum(pcdBuildData.getCName(),
292 moduleName,
293 datum,
294 datumType,
295 maxDatumSize)) != null) {
296 putError(exceptionString);
297 //
298 // Do not break preprocess, continues to analysis.
299 // All errors will be summary to be shown.
300 //
301 continue;
302 }
303 }
304
305 //
306 // ---------------------------------------------------------------------------------
307 // 2.1.2), Create token or update token information for current anaylized PCD data.
308 // ---------------------------------------------------------------------------------
309 //
310 if (pcdDbManager.isTokenInDatabase(primaryKey)) {
311 //
312 // If the token is already exist in database, do some necessary checking
313 // and add a usage instance into this token in database
314 //
315 token = pcdDbManager.getTokenByKey(primaryKey);
316
317 //
318 // checking for DatumType, DatumType should be unique for one PCD used in different
319 // modules.
320 //
321 if (token.datumType != datumType) {
322 exceptionString = String.format("In the FPD file, the datum type of the PCD entry %s is %s, which is different from %s which was previously defined!",
323 pcdBuildData.getCName(),
324 pcdBuildData.getDatumType().toString(),
325 Token.getStringOfdatumType(token.datumType));
326 putError(exceptionString);
327 //
328 // Do not break preprocess, continues to analysis.
329 // All errors will be summary to be shown.
330 //
331 continue;
332 }
333
334 //
335 // Check token number is valid
336 //
337 if (tokenNumber != token.tokenNumber) {
338 exceptionString = String.format("In the FPD file, the token number of PCD entry %s in module %s is different from the same PCD entry in other modules!",
339 pcdBuildData.getCName(),
340 moduleName);
341 putError(exceptionString);
342 //
343 // Do not break preprocess, continues to analysis.
344 // All errors will be summary to be shown.
345 //
346 continue;
347 }
348
349 //
350 // For same PCD used in different modules, the PCD type should all be dynamic or non-dynamic.
351 //
352 if (token.isDynamicPCD != Token.isDynamic(pcdType)) {
353 exceptionString = String.format("In the FPD file, for PCD entry %s in module %s, you defined dynamic or non-dynamic PCD type which"+
354 " is different from other module's definition.",
355 token.cName,
356 moduleName);
357 putError(exceptionString);
358 //
359 // Do not break preprocess, continues to analysis.
360 // All errors will be summary to be shown.
361 //
362 continue;
363 }
364
365 if (token.isDynamicPCD) {
366 //
367 // Check datum is equal the datum in dynamic information.
368 // For dynamic PCD, you can do not write <Value> in sperated every <PcdBuildDefinition> in different <ModuleSA>,
369 // But if you write, the <Value> must be same as the value in <DynamicPcdBuildDefinitions>.
370 //
371 if (!token.isSkuEnable() &&
372 (token.getDefaultSku().type == DynamicTokenValue.VALUE_TYPE.DEFAULT_TYPE) &&
373 (datum != null)) {
374 if (!datum.equalsIgnoreCase(token.getDefaultSku().value)) {
375 exceptionString = String.format("In the FPD file, for dynamic PCD %s in module %s, the datum in <ModuleSA> is "+
376 "not equal to the datum type in <DynamicPcdBuildDefinitions>. This is "+
377 "illega! You cannot set <Value> in <ModuleSA> for a dynamic PCD!",
378 token.cName,
379 moduleName);
380 putError(exceptionString);
381 //
382 // Do not break preprocess, continues to analysis.
383 // All errors will be summary to be shown.
384 //
385 continue;
386 }
387 }
388
389 if ((maxDatumSize != 0) &&
390 (maxDatumSize != token.datumSize)){
391 exceptionString = String.format("In the FPD file, for dynamic PCD %s in module %s, the max datum size is %d which "+
392 "is different than <MaxDatumSize> %d defined in <DynamicPcdBuildDefinitions>!",
393 token.cName,
394 moduleName,
395 maxDatumSize,
396 token.datumSize);
397 putError(exceptionString);
398 //
399 // Do not break preprocess, continues to analysis.
400 // All errors will be summary to be shown.
401 //
402 continue;
403 }
404 }
405
406 } else {
407 //
408 // If the token is not in database, create a new token instance and add
409 // a usage instance into this token in database.
410 //
411 tokenSpaceStrRet = getGuidInfoFromSpd(pcdBuildData.getTokenSpaceGuidCName());
412
413 if (tokenSpaceStrRet == null) {
414 putError("Failed to get the Token Space Guid for token" + token.cName +
415 " from any SPD file. You must have a <GuidDeclaration> for this Token Space Guid!");
416 //
417 // Do not break preprocess, continues to analysis.
418 // All errors will be summary to be shown.
419 //
420 continue;
421 }
422
423 token = new Token(pcdBuildData.getCName(), tokenSpaceStrRet);
424
425 token.datumType = datumType;
426 token.tokenNumber = tokenNumber;
427 token.isDynamicPCD = Token.isDynamic(pcdType);
428 token.datumSize = maxDatumSize;
429
430 if (token.isDynamicPCD) {
431 //
432 // For Dynamic and Dynamic Ex type, need find the dynamic information
433 // in <DynamicPcdBuildDefinition> section in FPD file.
434 //
435 if (null == updateDynamicInformation(moduleName,
436 token,
437 datum,
438 maxDatumSize)) {
439 continue;
440 }
441 }
442
443 pcdDbManager.addTokenToDatabase(primaryKey, token);
444 }
445
446 //
447 // -----------------------------------------------------------------------------------
448 // 2.1.3), Add the PcdType in current module into this Pcd token's supported PCD type.
449 // -----------------------------------------------------------------------------------
450 //
451 token.updateSupportPcdType(pcdType);
452
453 //
454 // ------------------------------------------------
455 // 2.1.4), Create an usage instance for this token.
456 // ------------------------------------------------
457 //
458 usageInstance = new UsageInstance(token,
459 modules.get(index).usageId,
460 pcdType,
461 datum,
462 maxDatumSize);
463 if (!token.addUsageInstance(usageInstance)) {
464 putError(String.format("PCD %s for module %s(%s) already exists in the database.\nPlease check all PCD build entries "+
465 "in the %s module's <ModuleSA> section to make sure there are no duplicated definitions in the FPD file!",
466 token.cName,
467 modules.get(index).usageId.moduleGuid,
468 moduleName,
469 moduleName));
470 continue;
471 }
472 }
473 }
474
475 //
476 // ------------------------------------------------
477 // 3), Add unreference dynamic_Ex pcd token into Pcd database.
478 // ------------------------------------------------
479 //
480 List<Token> tokenArray = getUnreferencedDynamicPcd();
481 if (tokenArray != null) {
482 for (index = 0; index < tokenArray.size(); index++) {
483 pcdDbManager.addTokenToDatabase(tokenArray.get(index).getPrimaryKeyString(),
484 tokenArray.get(index));
485 }
486 }
487 }
488
489 /**
490 Update dynamic information for PCD entry.
491
492 Dynamic information is retrieved from <PcdDynamicBuildDeclarations> in
493 FPD file.
494
495 @param moduleName The name of the module who use this PCD
496 @param token The token instance
497 @param datum The <datum> in module's PCD information
498 @param maxDatumSize The <maxDatumSize> in module's PCD information
499
500 @return Token
501 */
502 private Token updateDynamicInformation(String moduleName,
503 Token token,
504 String datum,
505 int maxDatumSize)
506 throws PlatformPcdPreprocessException {
507 int index = 0;
508 int offset;
509 String exceptionString = null;
510 SkuInstance skuInstance = null;
511 String temp;
512 boolean hasSkuId0 = false;
513 long tokenNumber = 0;
514 String hiiDefaultValue = null;
515 String variableGuidString = null;
516
517 List<DynamicPcdBuildDefinitions.PcdBuildData.SkuInfo> skuInfoList = null;
518 DynamicPcdBuildDefinitions.PcdBuildData dynamicInfo = null;
519
520 dynamicInfo = getDynamicInfoFromFpd(token, moduleName);
521 if (dynamicInfo == null) {
522 exceptionString = String.format("In the FPD file, the Dynamic PCD %s is used by module %s.\n" +
523 "However, there is no dynamic information in the <DynamicPcdBuildDefinitions> " +
524 "section of the FPD file. This section is required!",
525 token.cName,
526 moduleName);
527 putError(exceptionString);
528 return null;
529 }
530
531 token.datumSize = dynamicInfo.getMaxDatumSize();
532
533 exceptionString = verifyDatum(token.cName,
534 moduleName,
535 null,
536 token.datumType,
537 token.datumSize);
538 if (exceptionString != null) {
539 throw new PlatformPcdPreprocessException(exceptionString);
540 }
541
542 if ((maxDatumSize != 0) &&
543 (maxDatumSize != token.datumSize)) {
544 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the datum size in module %s is %d, but "+
545 "the datum size in <DynamicPcdBuildDefinitions> is %d, they do not match!",
546 token.cName,
547 moduleName,
548 maxDatumSize,
549 dynamicInfo.getMaxDatumSize());
550 putError(exceptionString);
551 return null;
552 }
553 tokenNumber = Long.decode(dynamicInfo.getToken().toString());
554 if (tokenNumber != token.tokenNumber) {
555 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the token number in module %s is 0x%x, but "+
556 "in the <DynamicPcdBuildDefinictions> section, the token number is 0x%x, they do not match!",
557 token.cName,
558 moduleName,
559 token.tokenNumber,
560 tokenNumber);
561 putError(exceptionString);
562 return null;
563 }
564
565 token.dynamicExTokenNumber = tokenNumber;
566
567 skuInfoList = dynamicInfo.getSkuInfoList();
568
569 //
570 // Loop all sku data
571 //
572 for (index = 0; index < skuInfoList.size(); index++) {
573 skuInstance = new SkuInstance();
574 //
575 // Although SkuId in schema is BigInteger, but in fact, sku id is 32 bit value.
576 //
577 temp = skuInfoList.get(index).getSkuId().toString();
578 skuInstance.id = Integer.decode(temp);
579 if (skuInstance.id == 0) {
580 hasSkuId0 = true;
581 }
582 //
583 // Judge whether is DefaultGroup at first, because most case is DefautlGroup.
584 //
585 if (skuInfoList.get(index).getValue() != null) {
586 skuInstance.value.setValue(skuInfoList.get(index).getValue().toString());
587 if ((exceptionString = verifyDatum(token.cName,
588 null,
589 skuInfoList.get(index).getValue().toString(),
590 token.datumType,
591 token.datumSize)) != null) {
592 putError(exceptionString);
593 return null;
594 }
595
596 token.skuData.add(skuInstance);
597
598 //
599 // Judege wether is same of datum between module's information
600 // and dynamic information.
601 //
602 if (datum != null) {
603 if ((skuInstance.id == 0) &&
604 !datum.toString().equalsIgnoreCase(skuInfoList.get(index).getValue().toString())) {
605 exceptionString = "In the FPD file, for dynamic PCD " + token.cName + ", the value in module " + moduleName + " is " + datum.toString() + " but the "+
606 "value of SKU 0 data in <DynamicPcdBuildDefinition> is " + skuInstance.value.value + ". They must be same!"+
607 " Also, you cannot define a value for a dynamic PCD in the <ModuleSA> section!";
608 putError(exceptionString);
609 return null;
610 }
611 }
612 continue;
613 }
614
615 //
616 // Judge whether is HII group case.
617 //
618 if (skuInfoList.get(index).getVariableName() != null) {
619 exceptionString = null;
620 if (skuInfoList.get(index).getVariableGuid() == null) {
621 exceptionString = String.format("In the FPD file, for dynamic PCD %s in <DynamicPcdBuildDefinitions> section in FPD "+
622 "file, use of HII was defined, but there is no <VariableGuid> defined for SKU %d data!",
623 token.cName,
624 index);
625 putError(exceptionString);
626 return null;
627 }
628
629 if (skuInfoList.get(index).getVariableOffset() == null) {
630 exceptionString = String.format("In the FPD file, for dynamic PCD %s in <DynamicPcdBuildDefinitions> section in FPD "+
631 "file, use of HII was defined, but there is no <VariableOffset> defined for SKU %d data!",
632 token.cName,
633 index);
634 putError(exceptionString);
635 return null;
636 }
637
638 if (skuInfoList.get(index).getHiiDefaultValue() == null) {
639 exceptionString = String.format("In the FPD file, for dynamic PCD %s in <DynamicPcdBuildDefinitions> section in FPD "+
640 "file, use of HII was defined, but there is no <HiiDefaultValue> defined for SKU %d data!",
641 token.cName,
642 index);
643 putError(exceptionString);
644 return null;
645 }
646
647 if (skuInfoList.get(index).getHiiDefaultValue() != null) {
648 hiiDefaultValue = skuInfoList.get(index).getHiiDefaultValue().toString();
649 } else {
650 hiiDefaultValue = null;
651 }
652
653 if ((exceptionString = verifyDatum(token.cName,
654 null,
655 hiiDefaultValue,
656 token.datumType,
657 token.datumSize)) != null) {
658 throw new PlatformPcdPreprocessException(exceptionString);
659 }
660
661 offset = Integer.decode(skuInfoList.get(index).getVariableOffset());
662 if (offset > 0xFFFF) {
663 putError(String.format("In the FPD file, for dynamic PCD %s, the variable offset defined in SKU %d data "+
664 "exceeds 64K, which is not allowed!",
665 token.cName,
666 index));
667 return null;
668 }
669
670 //
671 // Get variable guid string according to the name of guid which will be mapped into a GUID in SPD file.
672 //
673 variableGuidString = getGuidInfoFromSpd(skuInfoList.get(index).getVariableGuid().toString());
674 if (variableGuidString == null) {
675 putError(String.format("In the FPD file, for dynamic PCD %s, the variable guid: %s cannot be found in any SPD file!",
676 token.cName,
677 skuInfoList.get(index).getVariableGuid().toString()));
678 return null;
679 }
680 String variableStr = skuInfoList.get(index).getVariableName();
681 Pattern pattern = Pattern.compile("0x([a-fA-F0-9]){4}");
682 Matcher matcher = pattern.matcher(variableStr);
683 List<String> varNameList = new ArrayList<String>();
684 while (matcher.find()){
685 String str = variableStr.substring(matcher.start(),matcher.end());
686 varNameList.add(str);
687 }
688
689 skuInstance.value.setHiiData(varNameList,
690 translateSchemaStringToUUID(variableGuidString),
691 skuInfoList.get(index).getVariableOffset(),
692 skuInfoList.get(index).getHiiDefaultValue().toString());
693 token.skuData.add(skuInstance);
694 continue;
695 }
696
697 if (skuInfoList.get(index).getVpdOffset() != null) {
698 skuInstance.value.setVpdData(skuInfoList.get(index).getVpdOffset());
699 token.skuData.add(skuInstance);
700 continue;
701 }
702
703 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the dynamic info must "+
704 "be one of: 'DefaultGroup', 'HIIGroup', 'VpdGroup'.",
705 token.cName);
706 putError(exceptionString);
707 return null;
708 }
709
710 if (!hasSkuId0) {
711 exceptionString = String.format("In the FPD file, for dynamic PCD %s in <DynamicPcdBuildDefinitions>, there is "+
712 "no SKU ID = 0 data, which is required for every dynamic PCD",
713 token.cName);
714 putError(exceptionString);
715 return null;
716 }
717
718 return token;
719 }
720
721 /**
722 Get all dynamic PCD defined in <DynamicPcdBuildDefinitions> which unreferenced by
723 any <ModuleSA> in FPD file.
724
725 @return List<Token> Return PCD token
726 **/
727 private List<Token> getUnreferencedDynamicPcd () throws PlatformPcdPreprocessException {
728 List<Token> tokenArray = new ArrayList<Token>();
729 Token token = null;
730 List<DynamicPcdBuildDefinitions.PcdBuildData> dynamicPcdBuildDataArray = null;
731 DynamicPcdBuildDefinitions.PcdBuildData pcdBuildData = null;
732 List<DynamicPcdBuildDefinitions.PcdBuildData.SkuInfo> skuInfoList = null;
733 Token.PCD_TYPE pcdType;
734 SkuInstance skuInstance = null;
735 String primaryKey = null;
736 boolean hasSkuId0 = false;
737 int index, offset, index2;
738 String temp;
739 String exceptionString;
740 String hiiDefaultValue;
741 String tokenSpaceStrRet;
742 String variableGuidString;
743
744 dynamicPcdBuildDataArray = getAllDynamicPcdInfoFromFpd();
745 if (dynamicPcdBuildDataArray == null) {
746 return null;
747 }
748
749 for (index2 = 0; index2 < dynamicPcdBuildDataArray.size(); index2++) {
750 pcdBuildData = dynamicPcdBuildDataArray.get(index2);
751 tokenSpaceStrRet = getGuidInfoFromSpd(pcdBuildData.getTokenSpaceGuidCName());
752
753 if (tokenSpaceStrRet == null) {
754 putError("Failed to get the Token Space Guid for token" + pcdBuildData.getCName());
755 continue;
756 }
757
758 primaryKey = Token.getPrimaryKeyString(pcdBuildData.getCName(),
759 tokenSpaceStrRet);
760
761 if (pcdDbManager.isTokenInDatabase(primaryKey)) {
762 continue;
763 }
764
765 pcdType = Token.getPcdTypeFromString(pcdBuildData.getItemType().toString());
766 if (pcdType != Token.PCD_TYPE.DYNAMIC_EX) {
767 putError(String.format("In the FPD file, it not allowed to define DYNAMIC PCD %s that is not used by any module",
768 pcdBuildData.getCName()));
769 continue;
770 }
771
772 //
773 // Create new token for unreference dynamic PCD token
774 //
775 token = new Token(pcdBuildData.getCName(), tokenSpaceStrRet);
776 token.datumSize = pcdBuildData.getMaxDatumSize();
777
778
779 token.datumType = Token.getdatumTypeFromString(pcdBuildData.getDatumType().toString());
780 token.tokenNumber = Long.decode(pcdBuildData.getToken().toString());
781 token.dynamicExTokenNumber = token.tokenNumber;
782 token.isDynamicPCD = true;
783 token.updateSupportPcdType(pcdType);
784
785 exceptionString = verifyDatum(token.cName,
786 null,
787 null,
788 token.datumType,
789 token.datumSize);
790 if (exceptionString != null) {
791 putError(exceptionString);
792 continue;
793 }
794
795 skuInfoList = pcdBuildData.getSkuInfoList();
796
797 //
798 // Loop all sku data
799 //
800 for (index = 0; index < skuInfoList.size(); index++) {
801 skuInstance = new SkuInstance();
802 //
803 // Although SkuId in schema is BigInteger, but in fact, sku id is 32 bit value.
804 //
805 temp = skuInfoList.get(index).getSkuId().toString();
806 skuInstance.id = Integer.decode(temp);
807 if (skuInstance.id == 0) {
808 hasSkuId0 = true;
809 }
810 //
811 // Judge whether is DefaultGroup at first, because most case is DefautlGroup.
812 //
813 if (skuInfoList.get(index).getValue() != null) {
814 skuInstance.value.setValue(skuInfoList.get(index).getValue().toString());
815 if ((exceptionString = verifyDatum(token.cName,
816 null,
817 skuInfoList.get(index).getValue().toString(),
818 token.datumType,
819 token.datumSize)) != null) {
820 putError(exceptionString);
821 continue;
822 }
823
824 token.skuData.add(skuInstance);
825
826 continue;
827 }
828
829 //
830 // Judge whether is HII group case.
831 //
832 if (skuInfoList.get(index).getVariableName() != null) {
833 exceptionString = null;
834 if (skuInfoList.get(index).getVariableGuid() == null) {
835 exceptionString = String.format("In the FPD file, for dynamic PCD %s in the <DynamicPcdBuildDefinitions> section of the FPD "+
836 "file, use of HII is defined, but there is no <VariableGuid> defined for SKU %d data!",
837 token.cName,
838 index);
839 putError(exceptionString);
840 continue;
841 }
842
843 if (skuInfoList.get(index).getVariableOffset() == null) {
844 exceptionString = String.format("In the FPD file, for dynamic PCD %s in the <DynamicPcdBuildDefinitions> section of the FPD "+
845 "file, use of HII is defined, but there is no <VariableOffset> defined for SKU %d data!",
846 token.cName,
847 index);
848 putError(exceptionString);
849 continue;
850 }
851
852 if (skuInfoList.get(index).getHiiDefaultValue() == null) {
853 exceptionString = String.format("In the FPD file, for dynamic PCD %s in the <DynamicPcdBuildDefinitions> section of the FPD "+
854 "file, use of HII is defined, but there is no <HiiDefaultValue> defined for SKU %d data!",
855 token.cName,
856 index);
857 putError(exceptionString);
858 continue;
859 }
860
861 if (skuInfoList.get(index).getHiiDefaultValue() != null) {
862 hiiDefaultValue = skuInfoList.get(index).getHiiDefaultValue().toString();
863 } else {
864 hiiDefaultValue = null;
865 }
866
867 if ((exceptionString = verifyDatum(token.cName,
868 null,
869 hiiDefaultValue,
870 token.datumType,
871 token.datumSize)) != null) {
872 putError(exceptionString);
873 continue;
874 }
875
876 offset = Integer.decode(skuInfoList.get(index).getVariableOffset());
877 if (offset > 0xFFFF) {
878 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the variable offset defined in SKU %d data "+
879 "exceeds 64K, which is not allowed!",
880 token.cName,
881 index);
882 putError(exceptionString);
883 continue;
884 }
885
886 //
887 // Get variable guid string according to the name of guid which will be mapped into a GUID in SPD file.
888 //
889 variableGuidString = getGuidInfoFromSpd(skuInfoList.get(index).getVariableGuid().toString());
890 if (variableGuidString == null) {
891 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the variable guid %s cannot be found in any SPD file!",
892 token.cName,
893 skuInfoList.get(index).getVariableGuid().toString());
894 putError(exceptionString);
895 continue;
896 }
897 String variableStr = skuInfoList.get(index).getVariableName();
898 Pattern pattern = Pattern.compile("0x([a-fA-F0-9]){4}");
899 Matcher matcher = pattern.matcher(variableStr);
900 List<String> varNameList = new ArrayList<String>();
901 while (matcher.find()){
902 String str = variableStr.substring(matcher.start(),matcher.end());
903 varNameList.add(str);
904 }
905
906 skuInstance.value.setHiiData(varNameList,
907 translateSchemaStringToUUID(variableGuidString),
908 skuInfoList.get(index).getVariableOffset(),
909 skuInfoList.get(index).getHiiDefaultValue().toString());
910 token.skuData.add(skuInstance);
911 continue;
912 }
913
914 if (skuInfoList.get(index).getVpdOffset() != null) {
915 skuInstance.value.setVpdData(skuInfoList.get(index).getVpdOffset());
916 token.skuData.add(skuInstance);
917 continue;
918 }
919
920 exceptionString = String.format("In the FPD file, for dynamic PCD %s, the dynamic info must "+
921 "be one of 'DefaultGroup', 'HIIGroup', 'VpdGroup'.",
922 token.cName);
923 putError(exceptionString);
924 }
925
926 if (!hasSkuId0) {
927 exceptionString = String.format("In the FPD file, for dynamic PCD %s in <DynamicPcdBuildDefinitions>, there is "+
928 "no SKU ID = 0 data, which is required for every dynamic PCD",
929 token.cName);
930 putError(exceptionString);
931 continue;
932 }
933
934 tokenArray.add(token);
935 }
936
937 return tokenArray;
938 }
939
940 /**
941 Translate the schema string to UUID instance.
942
943 In schema, the string of UUID is defined as following two types string:
944 1) GuidArrayType: pattern = 0x[a-fA-F0-9]{1,8},( )*0x[a-fA-F0-9]{1,4},(
945 )*0x[a-fA-F0-9]{1,4}(,( )*\{)?(,?( )*0x[a-fA-F0-9]{1,2}){8}( )*(\})?
946
947 2) GuidNamingConvention: pattern =
948 [a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}
949
950 This function will convert string and create uuid instance.
951
952 @param uuidString UUID string in XML file
953
954 @return UUID UUID instance
955 **/
956 private UUID translateSchemaStringToUUID(String uuidString)
957 throws PlatformPcdPreprocessException {
958 String temp;
959 String[] splitStringArray;
960 int index;
961 int chIndex;
962 int chLen;
963
964 if (uuidString == null) {
965 return null;
966 }
967
968 if (uuidString.length() == 0) {
969 return null;
970 }
971
972 if (uuidString.equals("0") ||
973 uuidString.equalsIgnoreCase("0x0")) {
974 return new UUID(0, 0);
975 }
976
977 uuidString = uuidString.replaceAll("\\{", "");
978 uuidString = uuidString.replaceAll("\\}", "");
979
980 //
981 // If the UUID schema string is GuidArrayType type then need translate
982 // to GuidNamingConvention type at first.
983 //
984 if ((uuidString.charAt(0) == '0') && ((uuidString.charAt(1) == 'x') || (uuidString.charAt(1) == 'X'))) {
985 splitStringArray = uuidString.split("," );
986 if (splitStringArray.length != 11) {
987 throw new PlatformPcdPreprocessException ("Wrong format for GUID string: " + uuidString);
988 }
989
990 //
991 // Remove blank space from these string and remove header string "0x"
992 //
993 for (index = 0; index < 11; index++) {
994 splitStringArray[index] = splitStringArray[index].trim();
995 splitStringArray[index] = splitStringArray[index].substring(2, splitStringArray[index].length());
996 }
997
998 //
999 // Add heading '0' to normalize the string length
1000 //
1001 for (index = 3; index < 11; index++) {
1002 chLen = splitStringArray[index].length();
1003 for (chIndex = 0; chIndex < 2 - chLen; chIndex++) {
1004 splitStringArray[index] = "0" + splitStringArray[index];
1005 }
1006 }
1007
1008 //
1009 // construct the final GuidNamingConvention string
1010 //
1011 temp = String.format("%s-%s-%s-%s%s-%s%s%s%s%s%s",
1012 splitStringArray[0],
1013 splitStringArray[1],
1014 splitStringArray[2],
1015 splitStringArray[3],
1016 splitStringArray[4],
1017 splitStringArray[5],
1018 splitStringArray[6],
1019 splitStringArray[7],
1020 splitStringArray[8],
1021 splitStringArray[9],
1022 splitStringArray[10]);
1023 uuidString = temp;
1024 }
1025
1026 return UUID.fromString(uuidString);
1027 }
1028 }
1029