2 File is FfsProcess class which is used to get the corresponding FFS layout
3 information for driver module.
5 Copyright (c) 2006, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 package org
.tianocore
.build
;
17 import java
.io
.FileInputStream
;
18 import java
.io
.FileOutputStream
;
19 import java
.io
.FileReader
;
20 import java
.io
.FileWriter
;
21 import java
.security
.MessageDigest
;
22 import java
.util
.Vector
;
24 import javax
.xml
.namespace
.QName
;
26 import org
.apache
.tools
.ant
.BuildException
;
27 import org
.apache
.tools
.ant
.Project
;
28 import org
.apache
.xmlbeans
.XmlCursor
;
29 import org
.tianocore
.BuildOptionsDocument
;
30 import org
.tianocore
.build
.global
.GlobalData
;
31 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
32 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
33 import org
.tianocore
.common
.definitions
.EdkDefinitions
;
34 import org
.tianocore
.common
.logger
.EdkLog
;
35 import org
.w3c
.dom
.Document
;
36 import org
.w3c
.dom
.Element
;
39 <p><code>FfsProcess</code> is a class to find the corresponding FFS layout. </p>
41 <p>The FFS Layout is like following: </p>
44 <Ffs type="APPLICATION">
45 <Attribute Name="FFS_FILETYPE" Value="EFI_FV_FILETYPE_APPLICATION" />
46 <Attribute Name="FFS_ATTRIB_CHECKSUM" Value="TRUE" />
47 <Sections EncapsulationType="Compress">
48 <Sections EncapsulationType="Guid-Defined">
49 <Section SectionType="EFI_SECTION_PE32" />
50 <Section SectionType="EFI_SECTION_USER_INTERFACE" />
51 <Section SectionType="EFI_SECTION_VERSION" />
59 public class FfsProcess
{
61 private BuildOptionsDocument
.BuildOptions
.Ffs ffsXmlObject
;
63 private Project project
= null;
65 /// ANT script to call GenFfs
67 private Element ffsNode
= null;
72 private String basename
;
75 /// Sections type: normal
77 private static int MODE_NONE
= 0;
80 /// Sections type: compress
82 private static int MODE_COMPRESS
= 1;
85 /// Sections type: guid-define
87 private static int MODE_GUID_DEFINED
= 2;
90 /// mapping from section type to section output file extension
92 public static final String
[][] sectionExt
= EdkDefinitions
.SectionTypeExtensions
;
95 search in the type, if componentType is listed in type, return true;
96 otherwise return false.
98 @param type a list supported component type separated by comma
99 @param componentType current module component type
100 @return whether componentType is one of type
102 private boolean isMatch(String type
, String componentType
) {
103 String
[] items
= type
.split("[ \t]*,[ \t]*");
104 for (int i
= 0; i
< items
.length
; i
++) {
105 if (items
[i
].equalsIgnoreCase(componentType
)) {
113 Find the corresponding FFS layout in <code>FPD</code>.
115 @param buildType Current module's component type
116 @param project Ant project
117 @return whether find the corresponding FFS layout
118 @throws BuildException
119 If can't find FFS Layout in FPD.
121 public boolean initSections(String buildType
, Project project
, FpdModuleIdentification fpdModuleId
) throws BuildException
{
122 this.project
= project
;
124 // Try to find Ffs layout from FPD file
126 SurfaceAreaQuery saq
= new SurfaceAreaQuery(GlobalData
.getFpdBuildOptionsMap());
127 BuildOptionsDocument
.BuildOptions
.Ffs
[] ffsArray
= saq
.getFpdFfs();
128 for (int i
= 0; i
< ffsArray
.length
; i
++) {
129 if (isMatch(ffsArray
[i
].getFfsKey(), buildType
)) {
130 ffsXmlObject
= ffsArray
[i
];
137 // If FfsFormatKey is not null, report exception and fail build
138 // Otherwise report warning message
140 if (buildType
== null) {
141 EdkLog
.log(EdkLog
.EDK_WARNING
, "Warning: this module doesn't specify a FfsFormatKey. ");
143 throw new BuildException("Can't find the FfsFormatKey [" + buildType
+ "] attribute in the FPD file!");
150 Recursive parse the FFS layout. Find out all section type here used.
152 @param document BaseName_build.xml Xml document
153 @param basename Module's base name
154 @param guid Module's GUID
155 @param targetFilename Module's final file name (GUID-BaseName.APP)
156 @return List of section type
158 public String
[] getGenSectionElements(Document document
, String basename
, String guid
, String targetFilename
) {
159 this.basename
= basename
;
160 if (ffsXmlObject
== null) {
161 return new String
[0];
163 Vector
<String
> sectionList
= new Vector
<String
>();
164 XmlCursor cursor
= null;
166 cursor
= ffsXmlObject
.newCursor();
168 int mode
= MODE_NONE
;
169 Element genffsfileEle
= document
.createElement("genffsfile");
170 genffsfileEle
.setAttribute("outputDir", "${BIN_DIR}");
171 genffsfileEle
.setAttribute("moduleType", "${MODULE_TYPE}");
172 genffsfileEle
.setAttribute("BaseName", basename
);
173 genffsfileEle
.setAttribute("fileGuid", guid
);
175 if (cursor
.toFirstChild()) {
177 if (cursor
.getName().getLocalPart().equalsIgnoreCase("Attribute")) {
178 String name
= cursor
.getAttributeText(new QName("Name"));
179 String value
= cursor
.getAttributeText(new QName("Value"));
180 genffsfileEle
.setAttribute(changeAttributeName(name
), value
);
181 } else if (cursor
.getName().getLocalPart().equalsIgnoreCase("Section")) {
183 dealSection(mode
, document
, genffsfileEle
, cursor
, sectionList
);
185 } else if (cursor
.getName().getLocalPart().equalsIgnoreCase("Sections")) {
187 dealSections(mode
, document
, genffsfileEle
, cursor
, sectionList
);
190 } while (cursor
.toNextSibling());
195 Element outofdateEle
= document
.createElement("OnDependency");
196 Element sourceEle
= document
.createElement("sourcefiles");
197 Vector
<String
> sections
= new Vector
<String
>();
198 for (int i
= 0; i
< sectionList
.size(); i
++) {
199 String section
= (String
) sectionList
.get(i
);
200 if (isSectionType(section
)) {
201 sections
.addElement(section
);
203 Element pathEle
= document
.createElement("file");
204 pathEle
.setAttribute("name", getSectionFile(basename
, section
));
205 sourceEle
.appendChild(pathEle
);
208 // add FFS layout digest into the source file list
210 Element pathEle
= document
.createElement("file");
211 pathEle
.setAttribute("name", "${DEST_DIR_OUTPUT}" + File
.separator
+ "ffs.md5");
212 sourceEle
.appendChild(pathEle
);
214 String
[] result
= sections
.toArray(new String
[sections
.size()]);
216 outofdateEle
.appendChild(sourceEle
);
217 Element targetEle
= document
.createElement("targetfiles");
218 Element fileEle
= document
.createElement("file");
219 fileEle
.setAttribute("name", "${BIN_DIR}" + File
.separatorChar
+ targetFilename
);
220 targetEle
.appendChild(fileEle
);
221 outofdateEle
.appendChild(targetEle
);
222 Element sequentialEle
= document
.createElement("sequential");
223 sequentialEle
.appendChild(genffsfileEle
);
224 outofdateEle
.appendChild(sequentialEle
);
225 ffsNode
= outofdateEle
;
230 Change the attribute name. For example:
233 Before change: FFS_ATTRIB_CHECKSUM
234 After change: ffsATTRIBCHECKSUM
237 @param name Original attribute name
238 @return Changed attribute name
240 private String
changeAttributeName(String name
) {
241 String
[] strs
= name
.split("_");
242 String str
= strs
[0].toLowerCase();
243 for (int j
= 1; j
< strs
.length
; j
++) {
250 Recursively deal with Sections. If sections does not specify a type, then omit it.
252 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
253 @param doc Xml Document
254 @param root Root Node
255 @param cursor Current FFS layout cursor
256 @param list List of section type here used
258 private void dealSections(int mode
, Document doc
, Element root
, XmlCursor cursor
, Vector
<String
> list
) {
259 String type
= cursor
.getAttributeText(new QName("EncapsulationType"));
260 String toolName
= cursor
.getAttributeText(new QName("ToolName"));
261 String sectType
= cursor
.getAttributeText(new QName("SectionType"));
262 if (type
== null && sectType
== null) {
263 if (cursor
.toFirstChild()) {
265 if (cursor
.getName().getLocalPart().equalsIgnoreCase("Section")) {
267 dealSection(mode
, doc
, root
, cursor
, list
);
269 } else if (cursor
.getName().getLocalPart().equalsIgnoreCase("Sections")) {
271 dealSections(mode
, doc
, root
, cursor
, list
);
274 } while (cursor
.toNextSibling());
279 Element toolEle
= null;
280 if (type
.equalsIgnoreCase("COMPRESS") && (toolName
== null || toolName
.equalsIgnoreCase(""))) {
281 mode
= MODE_COMPRESS
;
283 // <gensection sectiontype="EFI_SECTION_COMPRESSION">
285 ele
= doc
.createElement("gensection");
286 ele
.setAttribute("sectionType", "EFI_SECTION_COMPRESSION");
289 mode
= MODE_GUID_DEFINED
;
291 // <gensection sectiontype="EFI_SECTION_GUID_DEFINED">
293 ele
= doc
.createElement("gensection");
295 if (type
.equalsIgnoreCase("COMPRESS")) {
296 ele
.setAttribute("sectionType", "EFI_SECTION_COMPRESSION");
298 ele
.setAttribute("sectiontype", "EFI_SECTION_GUID_DEFINED");
302 ele
.setAttribute("sectiontype", sectType
);
305 // <tool toolName="${OEMTOOLPATH}\toolname"
306 // outputPath = "${DEST_DIR_OUTPUT}">
308 toolEle
= doc
.createElement("tool");
309 if (toolName
== null || toolName
.equalsIgnoreCase("")) {
310 toolEle
.setAttribute("toolName", "${WORKSPACE_DIR}" + File
.separatorChar
+ "Tools" + File
.separatorChar
+ "bin"
311 + File
.separatorChar
+ "GenCRC32Section");
313 File toolExe
= new File(toolName
);
315 // If <Tool> element exist, add sub element under <tool> .
317 if (toolExe
.isAbsolute()) {
318 toolEle
.setAttribute("toolName", toolName
);
320 toolEle
.setAttribute("toolName", "${WORKSPACE_DIR}" + File
.separatorChar
+ "Tools" + File
.separatorChar
+ "bin"
321 + File
.separatorChar
+ toolName
);
325 toolEle
.setAttribute("outputPath", "${DEST_DIR_OUTPUT}");
326 ele
.appendChild(toolEle
);
328 if (cursor
.toFirstChild()) {
330 if (cursor
.getName().getLocalPart().equalsIgnoreCase("Section")) {
332 if (toolEle
== null) {
333 dealSection(mode
, doc
, ele
, cursor
, list
);
335 dealSection(mode
, doc
, toolEle
, cursor
, list
);
339 } else if (cursor
.getName().getLocalPart().equalsIgnoreCase("Sections")) {
341 if (toolEle
== null) {
342 dealSections(mode
, doc
, ele
, cursor
, list
);
344 dealSections(mode
, doc
, toolEle
, cursor
, list
);
349 } while (cursor
.toNextSibling());
351 root
.appendChild(ele
);
355 Recursively deal with section.
357 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
358 @param doc Xml Document
359 @param root Root Node
360 @param cursor Current FFS layout cursor
361 @param list List of section type here used
363 private void dealSection(int mode
, Document doc
, Element root
, XmlCursor cursor
, Vector
<String
> list
) {
364 String type
= cursor
.getAttributeText(new QName("SectionType"));
365 String alignment
= cursor
.getAttributeText(new QName("Alignment"));
368 // Judge if file is specified? Yes, just use the file, else call Build Macro
369 // If fileName is null, means without FileNames specify in FPD file
371 String fileName
= null;
373 if (cursor
.toFirstChild()) {
375 if (cursor
.getName().getLocalPart().equalsIgnoreCase("Filenames")) {
377 if (cursor
.toFirstChild()) {
379 if (cursor
.getName().getLocalPart().equalsIgnoreCase("Filename")) {
380 fileName
= cursor
.getTextValue();
382 } while (cursor
.toNextSibling());
386 } while (cursor
.toNextSibling());
391 if (fileName
== null) {
392 list
.addElement(type
);
394 list
.addElement(fileName
);
397 if (mode
== MODE_GUID_DEFINED
) {
399 // <input file="${DEST_DIR_OUTPUT}\Bds.pe32"/>
401 Element ele
= doc
.createElement("input");
402 if (fileName
== null) {
403 ele
.setAttribute("file", getSectionFile(basename
, type
));
405 ele
.setAttribute("file", fileName
);
407 root
.appendChild(ele
);
410 // <sectFile fileName= "..."/>
412 Element ele
= doc
.createElement("sectFile");
413 if (fileName
== null) {
414 ele
.setAttribute("fileName", getSectionFile(basename
, type
));
416 ele
.setAttribute("fileName", fileName
);
418 if (alignment
!= null) {
419 ele
.setAttribute("Alignment", alignment
);
421 root
.appendChild(ele
);
426 Get the corresponding section file suffix.
428 @param type Section type
429 @return Corresponding section file extension
431 private String
getSectionFile(String basename
, String type
) {
432 for (int i
= 0; i
< sectionExt
.length
; i
++) {
433 if (sectionExt
[i
][0].equalsIgnoreCase(type
)) {
434 return "${DEST_DIR_OUTPUT}" + File
.separatorChar
+ basename
+ sectionExt
[i
][1];
440 private boolean isSectionType(String type
) {
441 for (int i
= 0; i
< sectionExt
.length
; i
++) {
442 if (sectionExt
[i
][0].equalsIgnoreCase(type
)) {
450 Return the ANT script to call GenFfs Tool.
452 @return ANT script to call GenFfs Tool
454 public Element
getFfsNode() {
458 private void genDigest() {
459 String digestFilePath
= project
.getProperty("DEST_DIR_OUTPUT");
460 if (digestFilePath
== null) {
461 EdkLog
.log(EdkLog
.EDK_WARNING
, "Warning: cannot get DEST_DIR_OUTPUT!");
468 MessageDigest md5
= null;
470 md5
= MessageDigest
.getInstance("MD5");
472 // convert the FFS layout XML DOM tree into string and use it to
473 // calculate its MD5 digest value
475 md5
.update(ffsXmlObject
.xmlText().getBytes());
476 } catch (Exception e
) {
477 EdkLog
.log(EdkLog
.EDK_WARNING
, "Warning: " + e
.getMessage());
482 // get the MD5 digest value
484 byte[] digest
= md5
.digest();
487 // put the digest in a file named "ffs.md5" if it doesn't exist, otherwise
488 // we will compare the digest in the file with the one just calculated
490 digestFilePath
+= File
.separator
+ "ffs.md5";
491 File digestFile
= new File(digestFilePath
);
492 if (digestFile
.exists()) {
493 byte[] oldDigest
= new byte[digest
.length
];
495 FileInputStream fIn
= new FileInputStream(digestFile
);
498 } catch (Exception e
) {
499 throw new BuildException(e
.getMessage());
502 boolean noChange
= true;
503 for (int i
= 0; i
< oldDigest
.length
; ++i
) {
504 if (digest
[i
] != oldDigest
[i
]) {
516 // update the "ffs.md5" file content with new digest value
519 FileOutputStream fOut
= new FileOutputStream(digestFile
);
522 } catch (Exception e
) {
523 throw new BuildException(e
.getMessage());