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