]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/GenBuild/org/tianocore/build/FfsProcess.java
Support calling customized compression tool in FrameworkTask.
[mirror_edk2.git] / Tools / Source / GenBuild / org / tianocore / build / FfsProcess.java
1 /** @file
2 File is FfsProcess class which is used to get the corresponding FFS layout
3 information for driver module.
4
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
10
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.
13 **/
14 package org.tianocore.build;
15
16 import java.io.File;
17 import java.util.Vector;
18
19 import javax.xml.namespace.QName;
20
21 import org.apache.tools.ant.BuildException;
22 import org.apache.tools.ant.Project;
23 import org.apache.xmlbeans.XmlCursor;
24 import org.tianocore.BuildOptionsDocument;
25 import org.tianocore.build.global.GlobalData;
26 import org.tianocore.build.global.SurfaceAreaQuery;
27 import org.tianocore.build.id.FpdModuleIdentification;
28 import org.tianocore.common.definitions.EdkDefinitions;
29 import org.tianocore.common.logger.EdkLog;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32
33 /**
34 <p><code>FfsProcess</code> is a class to find the corresponding FFS layout. </p>
35
36 <p>The FFS Layout is like following: </p>
37
38 <pre>
39 &lt;Ffs type="APPLICATION"&gt;
40 &lt;Attribute Name="FFS_FILETYPE" Value="EFI_FV_FILETYPE_APPLICATION" /&gt;
41 &lt;Attribute Name="FFS_ATTRIB_CHECKSUM" Value="TRUE" /&gt;
42 &lt;Sections EncapsulationType="Compress"&gt;
43 &lt;Sections EncapsulationType="Guid-Defined"&gt;
44 &lt;Section SectionType="EFI_SECTION_PE32" /&gt;
45 &lt;Section SectionType="EFI_SECTION_USER_INTERFACE" /&gt;
46 &lt;Section SectionType="EFI_SECTION_VERSION" /&gt;
47 &lt;/Sections&gt;
48 &lt;/Sections&gt;
49 &lt;/Ffs&gt;
50 </pre>
51
52 @since GenBuild 1.0
53 **/
54 public class FfsProcess {
55
56 private BuildOptionsDocument.BuildOptions.Ffs ffsXmlObject;
57
58 ///
59 /// ANT script to call GenFfs
60 ///
61 private Element ffsNode = null;
62
63 ///
64 /// Module base name
65 ///
66 private String basename;
67
68 ///
69 /// Sections type: normal
70 ///
71 private static int MODE_NONE = 0;
72
73 ///
74 /// Sections type: compress
75 ///
76 private static int MODE_COMPRESS = 1;
77
78 ///
79 /// Sections type: guid-define
80 ///
81 private static int MODE_GUID_DEFINED = 2;
82
83 ///
84 /// mapping from section type to section output file extension
85 ///
86 public static final String[][] sectionExt = EdkDefinitions.SectionTypeExtensions;
87
88 /**
89 search in the type, if componentType is listed in type, return true;
90 otherwise return false.
91
92 @param type a list supported component type separated by comma
93 @param componentType current module component type
94 @return whether componentType is one of type
95 **/
96 private boolean isMatch(String type, String componentType) {
97 String[] items = type.split("[ \t]*,[ \t]*");
98 for (int i = 0; i < items.length; i++) {
99 if (items[i].equalsIgnoreCase(componentType)) {
100 return true;
101 }
102 }
103 return false;
104 }
105
106 /**
107 Find the corresponding FFS layout in <code>FPD</code>.
108
109 @param buildType Current module's component type
110 @param project Ant project
111 @return whether find the corresponding FFS layout
112 @throws BuildException
113 If can't find FFS Layout in FPD.
114 **/
115 public boolean initSections(String buildType, Project project, FpdModuleIdentification fpdModuleId) throws BuildException {
116 //
117 // Try to find Ffs layout from FPD file
118 //
119 SurfaceAreaQuery saq = new SurfaceAreaQuery(GlobalData.getFpdBuildOptionsMap());
120 BuildOptionsDocument.BuildOptions.Ffs[] ffsArray = saq.getFpdFfs();
121 for (int i = 0; i < ffsArray.length; i++) {
122 if (isMatch(ffsArray[i].getFfsKey(), buildType)) {
123 ffsXmlObject = ffsArray[i];
124 return true;
125 }
126 }
127
128 //
129 // If FfsFormatKey is not null, report exception and fail build
130 // Otherwise report warning message
131 //
132 if (buildType == null) {
133 EdkLog.log(EdkLog.EDK_WARNING, "Warning: this module doesn't specify a FfsFormatKey. ");
134 } else {
135 throw new BuildException("Can't find the FfsFormatKey [" + buildType + "] attribute in the FPD file!");
136 }
137
138 return false;
139 }
140
141 /**
142 Recursive parse the FFS layout. Find out all section type here used.
143
144 @param document BaseName_build.xml Xml document
145 @param basename Module's base name
146 @param guid Module's GUID
147 @param targetFilename Module's final file name (GUID-BaseName.APP)
148 @return List of section type
149 **/
150 public String[] getGenSectionElements(Document document, String basename, String guid, String targetFilename) {
151 this.basename = basename;
152 if (ffsXmlObject == null) {
153 return new String[0];
154 }
155 Vector<String> sectionList = new Vector<String>();
156 XmlCursor cursor = null;
157
158 cursor = ffsXmlObject.newCursor();
159
160 int mode = MODE_NONE;
161 Element genffsfileEle = document.createElement("genffsfile");
162 genffsfileEle.setAttribute("outputDir", "${BIN_DIR}");
163 genffsfileEle.setAttribute("moduleType", "${MODULE_TYPE}");
164 genffsfileEle.setAttribute("BaseName", basename);
165 genffsfileEle.setAttribute("fileGuid", guid);
166
167 if (cursor.toFirstChild()) {
168 do {
169 if (cursor.getName().getLocalPart().equalsIgnoreCase("Attribute")) {
170 String name = cursor.getAttributeText(new QName("Name"));
171 String value = cursor.getAttributeText(new QName("Value"));
172 genffsfileEle.setAttribute(changeAttributeName(name), value);
173 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
174 cursor.push();
175 dealSection(mode, document, genffsfileEle, cursor, sectionList);
176 cursor.pop();
177 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
178 cursor.push();
179 dealSections(mode, document, genffsfileEle, cursor, sectionList);
180 cursor.pop();
181 }
182 } while (cursor.toNextSibling());
183 }
184 //
185 // Check dependency
186 //
187 Element outofdateEle = document.createElement("OnDependency");
188 Element sourceEle = document.createElement("sourcefiles");
189 String[] result = new String[sectionList.size()];
190 for (int i = 0; i < sectionList.size(); i++) {
191 result[i] = (String) sectionList.get(i);
192 Element pathEle = document.createElement("file");
193 pathEle.setAttribute("name", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename
194 + getSectionExt(result[i]));
195 sourceEle.appendChild(pathEle);
196 }
197 outofdateEle.appendChild(sourceEle);
198 Element targetEle = document.createElement("targetfiles");
199 Element fileEle = document.createElement("file");
200 fileEle.setAttribute("name", "${BIN_DIR}" + File.separatorChar + targetFilename);
201 targetEle.appendChild(fileEle);
202 outofdateEle.appendChild(targetEle);
203 Element sequentialEle = document.createElement("sequential");
204 sequentialEle.appendChild(genffsfileEle);
205 outofdateEle.appendChild(sequentialEle);
206 ffsNode = outofdateEle;
207 return result;
208 }
209
210 /**
211 Change the attribute name. For example:
212
213 <pre>
214 Before change: FFS_ATTRIB_CHECKSUM
215 After change: ffsATTRIBCHECKSUM
216 </pre>
217
218 @param name Original attribute name
219 @return Changed attribute name
220 **/
221 private String changeAttributeName(String name) {
222 String[] strs = name.split("_");
223 String str = strs[0].toLowerCase();
224 for (int j = 1; j < strs.length; j++) {
225 str += strs[j];
226 }
227 return str;
228 }
229
230 /**
231 Recursively deal with Sections. If sections does not specify a type, then omit it.
232
233 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
234 @param doc Xml Document
235 @param root Root Node
236 @param cursor Current FFS layout cursor
237 @param list List of section type here used
238 **/
239 private void dealSections(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
240 String type = cursor.getAttributeText(new QName("EncapsulationType"));
241 String toolName = cursor.getAttributeText(new QName("ToolName"));
242 String sectType = cursor.getAttributeText(new QName("SectionType"));
243 if (type == null && sectType == null) {
244 if (cursor.toFirstChild()) {
245 do {
246 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
247 cursor.push();
248 dealSection(mode, doc, root, cursor, list);
249 cursor.pop();
250 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
251 cursor.push();
252 dealSections(mode, doc, root, cursor, list);
253 cursor.pop();
254 }
255 } while (cursor.toNextSibling());
256 }
257 return;
258 }
259 Element ele;
260 Element toolEle = null;
261 if (type.equalsIgnoreCase("COMPRESS") && (toolName == null || toolName.equalsIgnoreCase(""))) {
262 mode = MODE_COMPRESS;
263 //
264 // <gensection sectiontype="EFI_SECTION_COMPRESSION">
265 //
266 ele = doc.createElement("gensection");
267 ele.setAttribute("sectionType", "EFI_SECTION_COMPRESSION");
268
269 } else {
270 mode = MODE_GUID_DEFINED;
271 //
272 // <gensection sectiontype="EFI_SECTION_GUID_DEFINED">
273 //
274 ele = doc.createElement("gensection");
275 if (type != null) {
276 ele.setAttribute("sectiontype", "EFI_SECTION_GUID_DEFINED");
277 } else {
278 ele.setAttribute("sectiontype", sectType);
279 }
280 //
281 // <tool toolName="${OEMTOOLPATH}\toolname"
282 // outputPath = "${DEST_DIR_OUTPUT}">
283 //
284 toolEle = doc.createElement("tool");
285 if (toolName == null || toolName.equalsIgnoreCase("")) {
286 toolEle.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "bin"
287 + File.separatorChar + "GenCRC32Section");
288 }else{
289 File toolExe = new File(toolName);
290 //
291 // If <Tool> element exist, add sub element under <tool> .
292 //
293 if (toolExe.isAbsolute()) {
294 toolEle.setAttribute("toolName", toolName);
295 } else {
296 toolEle.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "bin"
297 + File.separatorChar + toolName);
298 }
299 }
300
301 toolEle.setAttribute("outputPath", "${DEST_DIR_OUTPUT}");
302 ele.appendChild(toolEle);
303 }
304 if (cursor.toFirstChild()) {
305 do {
306 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
307 cursor.push();
308 if (toolEle == null) {
309 dealSection(mode, doc, ele, cursor, list);
310 } else {
311 dealSection(mode, doc, toolEle, cursor, list);
312 }
313
314 cursor.pop();
315 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
316 cursor.push();
317 if (toolEle == null) {
318 dealSections(mode, doc, ele, cursor, list);
319 } else {
320 dealSections(mode, doc, toolEle, cursor, list);
321 }
322
323 cursor.pop();
324 }
325 } while (cursor.toNextSibling());
326 }
327 root.appendChild(ele);
328 }
329
330 /**
331 Recursively deal with section.
332
333 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
334 @param doc Xml Document
335 @param root Root Node
336 @param cursor Current FFS layout cursor
337 @param list List of section type here used
338 **/
339 private void dealSection(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
340 String type = cursor.getAttributeText(new QName("SectionType"));
341
342 //
343 // Judge if file is specified? Yes, just use the file, else call Build Macro
344 // If fileName is null, means without FileNames specify in FPD file
345 //
346 String fileName = null;
347 cursor.push();
348 if (cursor.toFirstChild()) {
349 do {
350 if (cursor.getName().getLocalPart().equalsIgnoreCase("Filenames")) {
351 cursor.push();
352 if (cursor.toFirstChild()) {
353 do {
354 if (cursor.getName().getLocalPart().equalsIgnoreCase("Filename")) {
355 fileName = cursor.getTextValue();
356 }
357 } while (cursor.toNextSibling());
358 }
359 cursor.pop();
360 }
361 } while (cursor.toNextSibling());
362 }
363
364 cursor.pop();
365
366 if (fileName == null) {
367 list.addElement(type);
368 }
369 if (mode == MODE_GUID_DEFINED) {
370 //
371 // <input file="${DEST_DIR_OUTPUT}\Bds.pe32"/>
372 //
373 Element ele = doc.createElement("input");
374 if (fileName == null) {
375 ele.setAttribute("file", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
376 } else {
377 ele.setAttribute("file", "${PLATFORM_DIR}" + File.separatorChar + fileName);
378 }
379 root.appendChild(ele);
380 } else {
381 //
382 // <sectFile fileName= "..."/>
383 //
384 Element ele = doc.createElement("sectFile");
385 if (fileName == null) {
386 ele.setAttribute("fileName", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
387 } else {
388 ele.setAttribute("fileName", "${PLATFORM_DIR}" + File.separatorChar + fileName);
389 }
390 root.appendChild(ele);
391 }
392 }
393
394 /**
395 Get the corresponding section file suffix.
396
397 @param type Section type
398 @return Corresponding section file extension
399 **/
400 private String getSectionExt(String type) {
401 for (int i = 0; i < sectionExt.length; i++) {
402 if (sectionExt[i][0].equalsIgnoreCase(type)) {
403 return sectionExt[i][1];
404 }
405 }
406 return ".sec";
407 }
408
409 /**
410 Return the ANT script to call GenFfs Tool.
411
412 @return ANT script to call GenFfs Tool
413 **/
414 public Element getFfsNode() {
415 return ffsNode;
416 }
417 }