]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/GenBuild/org/tianocore/build/FfsProcess.java
Fixed EDKT102;
[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 module specify sections itself, it's okay
167 // otherwise find sections from WORKSPACE default setting with
168 // ComponentType
169 //
170 if (ffs == null) {
171 File file = new File(project.getProperty("COMMON_FILE"));
172 //
173 // if common file is not existed, just return
174 //
175 if (!file.exists()) {
176 return false;
177 }
178 DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
179 try {
180 DocumentBuilder dombuilder = domfac.newDocumentBuilder();
181 InputStream is = new FileInputStream(file);
182 Document doc = dombuilder.parse(is);
183 Element root = doc.getDocumentElement();
184 NodeList items = root.getChildNodes();
185 for (int i = 0; i < items.getLength(); i++) {
186 Node node = items.item(i);
187 if (node.getNodeType() == Node.ELEMENT_NODE) {
188 String nodeName = node.getNodeName();
189 if (nodeName.equalsIgnoreCase("Ffs")) {
190 NamedNodeMap attr = node.getAttributes();
191 Node type = attr.getNamedItem("type");
192 if (type != null) {
193 if (isMatch(type.getTextContent(), buildType)) {
194 ffs = node;
195 return true;
196 }
197 }
198 }
199 }
200 }
201 } catch (Exception e) {
202 throw new BuildException("Parse COMMON_FILE [" + file.getPath() + "] error!\n" + e.getMessage());
203 }
204 }
205 if (ffs == null) {
206 return false;
207 } else {
208 return true;
209 }
210 }
211
212 /**
213 Recursive parse the FFS layout. Find out all section type here used.
214
215 @param document BaseName_build.xml Xml document
216 @param basename Module's base name
217 @param guid Module's GUID
218 @param targetFilename Module's final file name (GUID-BaseName.APP)
219 @return List of section type
220 **/
221 public String[] getGenSectionElements(Document document, String basename, String guid, String targetFilename) {
222 this.basename = basename;
223 if (ffs == null && ffsXmlObject == null) {
224 return new String[0];
225 }
226 Vector<String> sectionList = new Vector<String>();
227 XmlCursor cursor = null;
228 try {
229 if (ffsXmlObject == null) {
230 cursor = XmlObject.Factory.parse(ffs).newCursor();
231 }
232 else {
233 cursor = ffsXmlObject.newCursor();
234 }
235 } catch (Exception e) {
236 return null;
237 }
238 int mode = MODE_NONE;
239 Element root = document.createElement("genffsfile");
240 root.setAttribute("outputDir", "${BIN_DIR}");
241 root.setAttribute("moduleType", "${MODULE_TYPE}");
242 root.setAttribute("BaseName", basename);
243 root.setAttribute("fileGuid", guid);
244 if (ffsXmlObject == null) {
245 cursor.toFirstChild();
246 }
247 if (cursor.toFirstChild()) {
248 do {
249 if (cursor.getName().getLocalPart().equalsIgnoreCase("Attribute")) {
250 String name = cursor.getAttributeText(new QName("Name"));
251 String value = cursor.getAttributeText(new QName("Value"));
252 root.setAttribute(changeAttributeName(name), value);
253 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
254 cursor.push();
255 dealSection(mode, document, root, cursor, sectionList);
256 cursor.pop();
257 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
258 cursor.push();
259 dealSections(mode, document, root, cursor, sectionList);
260 cursor.pop();
261 }
262 } while (cursor.toNextSibling());
263 }
264 //
265 // Check dependency
266 //
267 Element outofdateEle = document.createElement("OnDependency");
268 Element sourceEle = document.createElement("sourcefiles");
269 String[] result = new String[sectionList.size()];
270 for (int i = 0; i < sectionList.size(); i++) {
271 result[i] = (String) sectionList.get(i);
272 Element pathEle = document.createElement("file");
273 pathEle.setAttribute("name", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename
274 + getSectionExt(result[i]));
275 sourceEle.appendChild(pathEle);
276 }
277 outofdateEle.appendChild(sourceEle);
278 Element targetEle = document.createElement("targetfiles");
279 Element fileEle = document.createElement("file");
280 fileEle.setAttribute("name", "${BIN_DIR}\\" + targetFilename);
281 targetEle.appendChild(fileEle);
282 outofdateEle.appendChild(targetEle);
283 Element sequentialEle = document.createElement("sequential");
284 sequentialEle.appendChild(root);
285 outofdateEle.appendChild(sequentialEle);
286 ffsNode = outofdateEle;
287 return result;
288 }
289
290 /**
291 Change the attribute name. For example:
292
293 <pre>
294 Before change: FFS_ATTRIB_CHECKSUM
295 After change: ffsATTRIBCHECKSUM
296 </pre>
297
298 @param name Original attribute name
299 @return Changed attribute name
300 **/
301 private String changeAttributeName(String name) {
302 String[] strs = name.split("_");
303 String str = strs[0].toLowerCase();
304 for (int j = 1; j < strs.length; j++) {
305 str += strs[j];
306 }
307 return str;
308 }
309
310 /**
311 Recursively deal with Sections. If sections does not specify a type, then omit it.
312
313 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
314 @param doc Xml Document
315 @param root Root Node
316 @param cursor Current FFS layout cursor
317 @param list List of section type here used
318 **/
319 private void dealSections(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
320 String type = cursor.getAttributeText(new QName("EncapsulationType"));
321 if (type == null) {
322 if (cursor.toFirstChild()) {
323 do {
324 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
325 cursor.push();
326 dealSection(mode, doc, root, cursor, list);
327 cursor.pop();
328 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
329 cursor.push();
330 dealSections(mode, doc, root, cursor, list);
331 cursor.pop();
332 }
333 } while (cursor.toNextSibling());
334 }
335 return;
336 }
337 Element ele;
338 if (type.equalsIgnoreCase("COMPRESS")) {
339 mode = MODE_COMPRESS;
340 //
341 // <compress compressName = "dummy">
342 //
343 ele = doc.createElement("compress");
344 ele.setAttribute("compressName", "dummy");
345 } else {
346 mode = MODE_GUID_DEFINED;
347 //
348 // <tool toolName="${OEMTOOLPATH}\toolname"
349 // outputPath = "${DEST_DIR_OUTPUT}">
350 //
351 ele = doc.createElement("tool");
352 ele.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "Bin"
353 + File.separatorChar + "GenCRC32Section");
354 ele.setAttribute("outputPath", "${DEST_DIR_OUTPUT}");
355 }
356 if (cursor.toFirstChild()) {
357 do {
358 if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {
359 cursor.push();
360 dealSection(mode, doc, ele, cursor, list);
361 cursor.pop();
362 } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {
363 cursor.push();
364 dealSections(mode, doc, ele, cursor, list);
365 cursor.pop();
366 }
367 } while (cursor.toNextSibling());
368 }
369 root.appendChild(ele);
370 }
371
372 /**
373 Recursively deal with section.
374
375 @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)
376 @param doc Xml Document
377 @param root Root Node
378 @param cursor Current FFS layout cursor
379 @param list List of section type here used
380 **/
381 private void dealSection(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {
382 String type = cursor.getAttributeText(new QName("SectionType"));
383 list.addElement(type);
384 if (mode == MODE_GUID_DEFINED) {
385 //
386 // <input file="${DEST_DIR_OUTPUT}\Bds.pe32"/>
387 //
388 Element ele = doc.createElement("input");
389 ele.setAttribute("file", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
390 root.appendChild(ele);
391 } else {
392 //
393 // <sectFile fileName= "..."/>
394 //
395 Element ele = doc.createElement("sectFile");
396 ele.setAttribute("fileName", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));
397 root.appendChild(ele);
398 }
399 }
400
401 /**
402 Get the corresponding section file suffix.
403
404 @param type Section type
405 @return Corresponding section file extension
406 **/
407 private String getSectionExt(String type) {
408 for (int i = 0; i < sectionExt.length; i++) {
409 if (sectionExt[i][0].equalsIgnoreCase(type)) {
410 return sectionExt[i][1];
411 }
412 }
413 return ".sec";
414 }
415
416 /**
417 Return the ANT script to call GenFfs Tool.
418
419 @return ANT script to call GenFfs Tool
420 **/
421 public Element getFfsNode() {
422 return ffsNode;
423 }
424 }