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