--- /dev/null
+/** @file\r
+ File is FfsProcess class which is used to get the corresponding FFS layout\r
+ information for driver module. \r
+ \r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+package org.tianocore.build;\r
+\r
+import java.io.File;\r
+import java.util.Vector;\r
+\r
+import javax.xml.namespace.QName;\r
+\r
+import org.apache.tools.ant.BuildException;\r
+import org.apache.tools.ant.Project;\r
+import org.apache.xmlbeans.XmlCursor;\r
+import org.tianocore.BuildOptionsDocument;\r
+import org.tianocore.build.global.GlobalData;\r
+import org.tianocore.build.global.SurfaceAreaQuery;\r
+import org.tianocore.build.id.FpdModuleIdentification;\r
+import org.tianocore.common.definitions.EdkDefinitions;\r
+import org.tianocore.common.logger.EdkLog;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+/** \r
+ <p><code>FfsProcess</code> is a class to find the corresponding FFS layout. </p>\r
+ \r
+ <p>The FFS Layout is like following: </p>\r
+ \r
+ <pre>\r
+ <Ffs type="APPLICATION">\r
+ <Attribute Name="FFS_FILETYPE" Value="EFI_FV_FILETYPE_APPLICATION" />\r
+ <Attribute Name="FFS_ATTRIB_CHECKSUM" Value="TRUE" />\r
+ <Sections EncapsulationType="Compress">\r
+ <Sections EncapsulationType="Guid-Defined">\r
+ <Section SectionType="EFI_SECTION_PE32" /> \r
+ <Section SectionType="EFI_SECTION_USER_INTERFACE" />\r
+ <Section SectionType="EFI_SECTION_VERSION" /> \r
+ </Sections>\r
+ </Sections>\r
+ </Ffs>\r
+ </pre>\r
+ \r
+ @since GenBuild 1.0\r
+**/\r
+public class FfsProcess {\r
+\r
+ private BuildOptionsDocument.BuildOptions.Ffs ffsXmlObject;\r
+\r
+ ///\r
+ /// ANT script to call GenFfs\r
+ ///\r
+ private Element ffsNode = null;\r
+\r
+ ///\r
+ /// Module base name\r
+ ///\r
+ private String basename;\r
+\r
+ ///\r
+ /// Sections type: normal\r
+ ///\r
+ private static int MODE_NONE = 0;\r
+\r
+ ///\r
+ /// Sections type: compress\r
+ ///\r
+ private static int MODE_COMPRESS = 1;\r
+\r
+ ///\r
+ /// Sections type: guid-define\r
+ ///\r
+ private static int MODE_GUID_DEFINED = 2;\r
+\r
+ ///\r
+ /// mapping from section type to section output file extension\r
+ ///\r
+ public static final String[][] sectionExt = EdkDefinitions.SectionTypeExtensions;\r
+\r
+ /**\r
+ search in the type, if componentType is listed in type, return true; \r
+ otherwise return false.\r
+ \r
+ @param type a list supported component type separated by comma\r
+ @param componentType current module component type\r
+ @return whether componentType is one of type \r
+ **/\r
+ private boolean isMatch(String type, String componentType) {\r
+ String[] items = type.split("[ \t]*,[ \t]*");\r
+ for (int i = 0; i < items.length; i++) {\r
+ if (items[i].equalsIgnoreCase(componentType)) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ Find the corresponding FFS layout in <code>FPD</code>. \r
+ \r
+ @param buildType Current module's component type\r
+ @param project Ant project\r
+ @return whether find the corresponding FFS layout\r
+ @throws BuildException\r
+ If can't find FFS Layout in FPD.\r
+ **/\r
+ public boolean initSections(String buildType, Project project, FpdModuleIdentification fpdModuleId) throws BuildException {\r
+ //\r
+ // Try to find Ffs layout from FPD file\r
+ //\r
+ SurfaceAreaQuery saq = new SurfaceAreaQuery(GlobalData.getFpdBuildOptionsMap());\r
+ BuildOptionsDocument.BuildOptions.Ffs[] ffsArray = saq.getFpdFfs();\r
+ for (int i = 0; i < ffsArray.length; i++) {\r
+ if (isMatch(ffsArray[i].getFfsKey(), buildType)) {\r
+ ffsXmlObject = ffsArray[i];\r
+ return true;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // If FfsFormatKey is not null, report exception and fail build\r
+ // Otherwise report warning message\r
+ //\r
+ if (buildType == null) {\r
+ EdkLog.log(EdkLog.EDK_WARNING, "Warning: this module doesn't specify a FfsFormatKey. ");\r
+ } else {\r
+ throw new BuildException("Can't find the FfsFormatKey [" + buildType + "] attribute in the FPD file!"); \r
+ }\r
+\r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ Recursive parse the FFS layout. Find out all section type here used. \r
+ \r
+ @param document BaseName_build.xml Xml document\r
+ @param basename Module's base name\r
+ @param guid Module's GUID\r
+ @param targetFilename Module's final file name (GUID-BaseName.APP)\r
+ @return List of section type\r
+ **/\r
+ public String[] getGenSectionElements(Document document, String basename, String guid, String targetFilename) {\r
+ this.basename = basename;\r
+ if (ffsXmlObject == null) {\r
+ return new String[0];\r
+ }\r
+ Vector<String> sectionList = new Vector<String>();\r
+ XmlCursor cursor = null;\r
+\r
+ cursor = ffsXmlObject.newCursor();\r
+\r
+ int mode = MODE_NONE;\r
+ Element genffsfileEle = document.createElement("genffsfile");\r
+ genffsfileEle.setAttribute("outputDir", "${BIN_DIR}");\r
+ genffsfileEle.setAttribute("moduleType", "${MODULE_TYPE}");\r
+ genffsfileEle.setAttribute("BaseName", basename);\r
+ genffsfileEle.setAttribute("fileGuid", guid);\r
+\r
+ if (cursor.toFirstChild()) {\r
+ do {\r
+ if (cursor.getName().getLocalPart().equalsIgnoreCase("Attribute")) {\r
+ String name = cursor.getAttributeText(new QName("Name"));\r
+ String value = cursor.getAttributeText(new QName("Value"));\r
+ genffsfileEle.setAttribute(changeAttributeName(name), value);\r
+ } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {\r
+ cursor.push();\r
+ dealSection(mode, document, genffsfileEle, cursor, sectionList);\r
+ cursor.pop();\r
+ } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {\r
+ cursor.push();\r
+ dealSections(mode, document, genffsfileEle, cursor, sectionList);\r
+ cursor.pop();\r
+ }\r
+ } while (cursor.toNextSibling());\r
+ }\r
+ //\r
+ // Check dependency \r
+ //\r
+ Element outofdateEle = document.createElement("OnDependency");\r
+ Element sourceEle = document.createElement("sourcefiles");\r
+ String[] result = new String[sectionList.size()];\r
+ for (int i = 0; i < sectionList.size(); i++) {\r
+ result[i] = (String) sectionList.get(i);\r
+ Element pathEle = document.createElement("file");\r
+ pathEle.setAttribute("name", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename\r
+ + getSectionExt(result[i]));\r
+ sourceEle.appendChild(pathEle);\r
+ }\r
+ outofdateEle.appendChild(sourceEle);\r
+ Element targetEle = document.createElement("targetfiles");\r
+ Element fileEle = document.createElement("file");\r
+ fileEle.setAttribute("name", "${BIN_DIR}" + File.separatorChar + targetFilename);\r
+ targetEle.appendChild(fileEle);\r
+ outofdateEle.appendChild(targetEle);\r
+ Element sequentialEle = document.createElement("sequential");\r
+ sequentialEle.appendChild(genffsfileEle);\r
+ outofdateEle.appendChild(sequentialEle);\r
+ ffsNode = outofdateEle;\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ Change the attribute name. For example: \r
+ \r
+ <pre>\r
+ Before change: FFS_ATTRIB_CHECKSUM \r
+ After change: ffsATTRIBCHECKSUM\r
+ </pre>\r
+ \r
+ @param name Original attribute name\r
+ @return Changed attribute name\r
+ **/\r
+ private String changeAttributeName(String name) {\r
+ String[] strs = name.split("_");\r
+ String str = strs[0].toLowerCase();\r
+ for (int j = 1; j < strs.length; j++) {\r
+ str += strs[j];\r
+ }\r
+ return str;\r
+ }\r
+\r
+ /**\r
+ Recursively deal with Sections. If sections does not specify a type, then omit it.\r
+ \r
+ @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)\r
+ @param doc Xml Document\r
+ @param root Root Node\r
+ @param cursor Current FFS layout cursor\r
+ @param list List of section type here used\r
+ **/\r
+ private void dealSections(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {\r
+ String type = cursor.getAttributeText(new QName("EncapsulationType"));\r
+ String toolName = cursor.getAttributeText(new QName("ToolName"));\r
+ String sectType = cursor.getAttributeText(new QName("SectionType"));\r
+ if (type == null && sectType == null) {\r
+ if (cursor.toFirstChild()) {\r
+ do {\r
+ if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {\r
+ cursor.push();\r
+ dealSection(mode, doc, root, cursor, list);\r
+ cursor.pop();\r
+ } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {\r
+ cursor.push();\r
+ dealSections(mode, doc, root, cursor, list);\r
+ cursor.pop();\r
+ }\r
+ } while (cursor.toNextSibling());\r
+ }\r
+ return;\r
+ }\r
+ Element ele;\r
+ Element toolEle = null;\r
+ if (type.equalsIgnoreCase("COMPRESS") && (toolName == null || toolName.equalsIgnoreCase(""))) {\r
+ mode = MODE_COMPRESS;\r
+ //\r
+ // <gensection sectiontype="EFI_SECTION_COMPRESSION"> \r
+ // \r
+ ele = doc.createElement("gensection");\r
+ ele.setAttribute("sectionType", "EFI_SECTION_COMPRESSION");\r
+ \r
+ } else {\r
+ mode = MODE_GUID_DEFINED;\r
+ //\r
+ // <gensection sectiontype="EFI_SECTION_GUID_DEFINED">\r
+ // \r
+ ele = doc.createElement("gensection");\r
+ if (type != null) {\r
+ if (type.equalsIgnoreCase("COMPRESS")) {\r
+ ele.setAttribute("sectionType", "EFI_SECTION_COMPRESSION");\r
+ }else {\r
+ ele.setAttribute("sectiontype", "EFI_SECTION_GUID_DEFINED"); \r
+ }\r
+ \r
+ } else {\r
+ ele.setAttribute("sectiontype", sectType);\r
+ }\r
+ //\r
+ // <tool toolName="${OEMTOOLPATH}\toolname"\r
+ // outputPath = "${DEST_DIR_OUTPUT}">\r
+ //\r
+ toolEle = doc.createElement("tool");\r
+ if (toolName == null || toolName.equalsIgnoreCase("")) {\r
+ toolEle.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "bin"\r
+ + File.separatorChar + "GenCRC32Section");\r
+ }else{\r
+ File toolExe = new File(toolName);\r
+ //\r
+ // If <Tool> element exist, add sub element under <tool> . \r
+ // \r
+ if (toolExe.isAbsolute()) {\r
+ toolEle.setAttribute("toolName", toolName);\r
+ } else {\r
+ toolEle.setAttribute("toolName", "${WORKSPACE_DIR}" + File.separatorChar + "Tools" + File.separatorChar + "bin"\r
+ + File.separatorChar + toolName);\r
+ }\r
+ }\r
+ \r
+ toolEle.setAttribute("outputPath", "${DEST_DIR_OUTPUT}");\r
+ ele.appendChild(toolEle);\r
+ }\r
+ if (cursor.toFirstChild()) {\r
+ do {\r
+ if (cursor.getName().getLocalPart().equalsIgnoreCase("Section")) {\r
+ cursor.push();\r
+ if (toolEle == null) {\r
+ dealSection(mode, doc, ele, cursor, list);\r
+ } else {\r
+ dealSection(mode, doc, toolEle, cursor, list);\r
+ }\r
+ \r
+ cursor.pop();\r
+ } else if (cursor.getName().getLocalPart().equalsIgnoreCase("Sections")) {\r
+ cursor.push();\r
+ if (toolEle == null) {\r
+ dealSections(mode, doc, ele, cursor, list);\r
+ } else {\r
+ dealSections(mode, doc, toolEle, cursor, list);\r
+ }\r
+ \r
+ cursor.pop();\r
+ }\r
+ } while (cursor.toNextSibling());\r
+ }\r
+ root.appendChild(ele);\r
+ }\r
+ \r
+ /**\r
+ Recursively deal with section.\r
+ \r
+ @param mode Current node mode (MODE_NONE | MODE_COMPREE | MODE_GUID_DEFINED)\r
+ @param doc Xml Document\r
+ @param root Root Node\r
+ @param cursor Current FFS layout cursor\r
+ @param list List of section type here used\r
+ **/\r
+ private void dealSection(int mode, Document doc, Element root, XmlCursor cursor, Vector<String> list) {\r
+ String type = cursor.getAttributeText(new QName("SectionType"));\r
+ \r
+ //\r
+ // Judge if file is specified? Yes, just use the file, else call Build Macro\r
+ // If fileName is null, means without FileNames specify in FPD file\r
+ //\r
+ String fileName = null;\r
+ cursor.push();\r
+ if (cursor.toFirstChild()) {\r
+ do {\r
+ if (cursor.getName().getLocalPart().equalsIgnoreCase("Filenames")) {\r
+ cursor.push();\r
+ if (cursor.toFirstChild()) {\r
+ do {\r
+ if (cursor.getName().getLocalPart().equalsIgnoreCase("Filename")) {\r
+ fileName = cursor.getTextValue();\r
+ }\r
+ } while (cursor.toNextSibling());\r
+ }\r
+ cursor.pop();\r
+ }\r
+ } while (cursor.toNextSibling());\r
+ }\r
+\r
+ cursor.pop();\r
+ \r
+ if (fileName == null) {\r
+ list.addElement(type);\r
+ }\r
+ if (mode == MODE_GUID_DEFINED) {\r
+ //\r
+ // <input file="${DEST_DIR_OUTPUT}\Bds.pe32"/>\r
+ //\r
+ Element ele = doc.createElement("input");\r
+ if (fileName == null) {\r
+ ele.setAttribute("file", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));\r
+ } else {\r
+ ele.setAttribute("file", "${PLATFORM_DIR}" + File.separatorChar + fileName);\r
+ }\r
+ root.appendChild(ele);\r
+ } else {\r
+ //\r
+ // <sectFile fileName= "..."/>\r
+ //\r
+ Element ele = doc.createElement("sectFile");\r
+ if (fileName == null) {\r
+ ele.setAttribute("fileName", "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + getSectionExt(type));\r
+ } else {\r
+ ele.setAttribute("fileName", "${PLATFORM_DIR}" + File.separatorChar + fileName);\r
+ }\r
+ root.appendChild(ele);\r
+ }\r
+ }\r
+\r
+ /**\r
+ Get the corresponding section file suffix.\r
+ \r
+ @param type Section type\r
+ @return Corresponding section file extension\r
+ **/\r
+ private String getSectionExt(String type) {\r
+ for (int i = 0; i < sectionExt.length; i++) {\r
+ if (sectionExt[i][0].equalsIgnoreCase(type)) {\r
+ return sectionExt[i][1];\r
+ }\r
+ }\r
+ return ".sec";\r
+ }\r
+\r
+ /**\r
+ Return the ANT script to call GenFfs Tool.\r
+ \r
+ @return ANT script to call GenFfs Tool\r
+ **/\r
+ public Element getFfsNode() {\r
+ return ffsNode;\r
+ }\r
+}\r