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