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