dbbddba3db107067a46c712e43b14bc1162e51d4
[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.w3c.dom.Document;
30 import org.w3c.dom.Element;
31 import org.w3c.dom.NamedNodeMap;
32 import org.w3c.dom.Node;
33 import org.w3c.dom.NodeList;
34
35 /**
36 <p><code>FfsProcess</code> is a class to find the corresponding FFS layout. </p>
37
38 <p>Property <code>COMMON_FILE</code> specified which file to search. The element
39 in <code>COMMON_FILE</code> is like following: </p>
40
41 <pre>
42 &lt;Ffs type="APPLICATION"&gt;
43 &lt;Attribute Name="FFS_FILETYPE" Value="EFI_FV_FILETYPE_APPLICATION" /&gt;
44 &lt;Attribute Name="FFS_ATTRIB_CHECKSUM" Value="TRUE" /&gt;
45 &lt;Sections EncapsulationType="Compress"&gt;
46 &lt;Sections EncapsulationType="Guid-Defined"&gt;
47 &lt;Section SectionType="EFI_SECTION_PE32" /&gt;
48 &lt;Section SectionType="EFI_SECTION_USER_INTERFACE" /&gt;
49 &lt;Section SectionType="EFI_SECTION_VERSION" /&gt;
50 &lt;/Sections&gt;
51 &lt;/Sections&gt;
52 &lt;/Ffs&gt;
53 </pre>
54
55 @since GenBuild 1.0
56 **/
57 public class FfsProcess {
58
59 ///
60 /// Xml Document Node for corresponding FFS layout
61 ///
62 private Node ffs;
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) throws BuildException {
135 //
136 // first try to sections defined in PLATFORM level
137 //
138
139 //
140 // if module specify sections itself, it's okay
141 // otherwise find sections from WORKSPACE default setting with
142 // ComponentType
143 //
144 if (ffs == null) {
145 File file = new File(project.getProperty("COMMON_FILE"));
146 //
147 // if common file is not existed, just return
148 //
149 if (!file.exists()) {
150 return false;
151 }
152 DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
153 try {
154 DocumentBuilder dombuilder = domfac.newDocumentBuilder();
155 InputStream is = new FileInputStream(file);
156 Document doc = dombuilder.parse(is);
157 Element root = doc.getDocumentElement();
158 NodeList items = root.getChildNodes();
159 for (int i = 0; i < items.getLength(); i++) {
160 Node node = items.item(i);
161 if (node.getNodeType() == Node.ELEMENT_NODE) {
162 String nodeName = node.getNodeName();
163 if (nodeName.equalsIgnoreCase("Ffs")) {
164 NamedNodeMap attr = node.getAttributes();
165 Node type = attr.getNamedItem("type");
166 if (type != null) {
167 if (isMatch(type.getTextContent(), buildType)) {
168 ffs = node;
169 return true;
170 }
171 }
172 }
173 }
174 }
175 } catch (Exception e) {
176 throw new BuildException("Parse COMMON_FILE [" + file.getPath() + "] error!\n" + e.getMessage());
177 }
178 }
179 if (ffs == null) {
180 return false;
181 } else {
182 return true;
183 }
184 }
185
186 /**
187 Recursive parse the FFS layout. Find out all section type here used.
188
189 @param document BaseName_build.xml Xml document
190 @param basename Module's base name
191 @param guid Module's GUID
192 @param targetFilename Module's final file name (GUID-BaseName.APP)
193 @return List of section type
194 **/
195 public String[] getGenSectionElements(Document document, String basename, String guid, String targetFilename) {
196 this.basename = basename;
197 if (ffs == null) {
198 return new String[0];
199 }
200 Vector<String> sectionList = new Vector<String>();
201 XmlCursor cursor = null;
202 try {
203 cursor = XmlObject.Factory.parse(ffs).newCursor();
204 } catch (Exception e) {
205 return null;
206 }
207 int mode = MODE_NONE;
208 Element root = document.createElement("genffsfile");
209 root.setAttribute("outputDir", "${BIN_DIR}");
210 root.setAttribute("BaseName", basename);
211 root.setAttribute("fileGuid", guid);
212 cursor.toFirstChild();
213 if (cursor.toFirstChild()) {
214 do {
215 if (cursor.getName().getLocalPart().equalsIgnoreCase("Attribute")) {
216 String name = cursor.getAttributeText(new QName("Name"));
217 String value = cursor.getAttributeText(new QName("Value"));
218 root.setAttribute(changeAttributeName(name), value);
219 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
220 cursor.push();
221 dealSection(mode, document, root, cursor, sectionList);
222 cursor.pop();
223 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
224 cursor.push();
225 dealSections(mode, document, root, cursor, sectionList);
226 cursor.pop();
227 }
228 } while (cursor.toNextSibling());
229 }
230 //
231 // Check dependency
232 //
233 Element outofdateEle = document.createElement("OnDependency");
234 Element sourceEle = document.createElement("sourcefiles");
235 String[] result = new String[sectionList.size()];
236 for (int i = 0; i < sectionList.size(); i++) {
237 result[i] = (String) sectionList.get(i);
238 Element pathEle = document.createElement("file");
239 pathEle.setAttribute("name", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename
240 + getSectionExt(result[i]));
241 sourceEle.appendChild(pathEle);
242 }
243 outofdateEle.appendChild(sourceEle);
244 Element targetEle = document.createElement("targetfiles");
245 Element fileEle = document.createElement("file");
246 fileEle.setAttribute("name", "${BIN_DIR}\\" + targetFilename);
247 targetEle.appendChild(fileEle);
248 outofdateEle.appendChild(targetEle);
249 Element sequentialEle = document.createElement("sequential");
250 sequentialEle.appendChild(root);
251 outofdateEle.appendChild(sequentialEle);
252 ffsNode = outofdateEle;
253 return result;
254 }
255
256 /**
257 Change the attribute name. For example:
258
259 <pre>
260 Before change: FFS_ATTRIB_CHECKSUM
261 After change: ffsATTRIBCHECKSUM
262 </pre>
263
264 @param name Original attribute name
265 @return Changed attribute name
266 **/
267 private String changeAttributeName(String name) {
268 String[] strs = name.split("_");
269 String str = strs[0].toLowerCase();
270 for (int j = 1; j < strs.length; j++) {
271 str += strs[j];
272 }
273 return str;
274 }
275
276 /**
277 Recursively deal with Sections. If sections does not specify a type, then omit it.
278
279 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
280 @param doc Xml Document
281 @param root Root Node
282 @param cursor Current FFS layout cursor
283 @param list List of section type here used
284 **/
285 private void dealSections(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
286 String type = cursor.getAttributeText(new QName("EncapsulationType"));
287 if (type == null) {
288 if (cursor.toFirstChild()) {
289 do {
290 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
291 cursor.push();
292 dealSection(mode, doc, root, cursor, list);
293 cursor.pop();
294 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
295 cursor.push();
296 dealSections(mode, doc, root, cursor, list);
297 cursor.pop();
298 }
299 } while (cursor.toNextSibling());
300 }
301 return;
302 }
303 Element ele;
304 if (type.equalsIgnoreCase("COMPRESS")) {
305 mode = MODE_COMPRESS;
306 //
307 // <compress compressName = "dummy">
308 //
309 ele = doc.createElement("compress");
310 ele.setAttribute("compressName", "dummy");
311 } else {
312 mode = MODE_GUID_DEFINED;
313 //
314 // <tool toolName="${OEMTOOLPATH}\toolname"
315 // outputPath = "${DEST_DIR_OUTPUT}">
316 //
317 ele = doc.createElement("tool");
318 ele.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "Bin"
319 + File.separatorChar + "GenCRC32Section");
320 ele.setAttribute("outputPath", "${DEST_DIR_OUTPUT}");
321 }
322 if (cursor.toFirstChild()) {
323 do {
324 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
325 cursor.push();
326 dealSection(mode, doc, ele, cursor, list);
327 cursor.pop();
328 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
329 cursor.push();
330 dealSections(mode, doc, ele, cursor, list);
331 cursor.pop();
332 }
333 } while (cursor.toNextSibling());
334 }
335 root.appendChild(ele);
336 }
337
338 /**
339 Recursively deal with section.
340
341 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
342 @param doc Xml Document
343 @param root Root Node
344 @param cursor Current FFS layout cursor
345 @param list List of section type here used
346 **/
347 private void dealSection(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
348 String type = cursor.getAttributeText(new QName("SectionType"));
349 list.addElement(type);
350 if (mode == MODE_GUID_DEFINED) {
351 //
352 // <input file="${DEST_DIR_OUTPUT}\Bds.pe32"/>
353 //
354 Element ele = doc.createElement("input");
355 ele.setAttribute("file", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
356 root.appendChild(ele);
357 } else {
358 //
359 // <sectFile fileName= "..."/>
360 //
361 Element ele = doc.createElement("sectFile");
362 ele.setAttribute("fileName", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
363 root.appendChild(ele);
364 }
365 }
366
367 /**
368 Get the corresponding section file suffix.
369
370 @param type Section type
371 @return Corresponding section file extension
372 **/
373 private String getSectionExt(String type) {
374 for (int i = 0; i < sectionExt.length; i++) {
375 if (sectionExt[i][0].equalsIgnoreCase(type)) {
376 return sectionExt[i][1];
377 }
378 }
379 return ".sec";
380 }
381
382 /**
383 Return the ANT script to call GenFfs Tool.
384
385 @return ANT script to call GenFfs Tool
386 **/
387 public Element getFfsNode() {
388 return ffsNode;
389 }
390 }