+++ /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.io.FileInputStream;\r
-import java.io.FileOutputStream;\r
-import java.io.FileReader;\r
-import java.io.FileWriter;\r
-import java.security.MessageDigest;\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
- private Project project = null;\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
- this.project = project;\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
- genDigest();\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
- Vector<String> sections = new Vector<String>();\r
- for (int i = 0; i < sectionList.size(); i++) {\r
- String section = (String) sectionList.get(i);\r
- if (isSectionType(section)) {\r
- sections.addElement(section);\r
- }\r
- Element pathEle = document.createElement("file");\r
- pathEle.setAttribute("name", getSectionFile(basename, section));\r
- sourceEle.appendChild(pathEle);\r
- }\r
- //\r
- // add FFS layout digest into the source file list\r
- // \r
- Element pathEle = document.createElement("file");\r
- pathEle.setAttribute("name", "${DEST_DIR_OUTPUT}" + File.separator + "ffs.md5");\r
- sourceEle.appendChild(pathEle);\r
-\r
- String[] result = sections.toArray(new String[sections.size()]);\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
- String alignment = cursor.getAttributeText(new QName("Alignment"));\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
- } else {\r
- list.addElement(fileName);\r
- }\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", getSectionFile(basename, type));\r
- } else {\r
- ele.setAttribute("file", 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", getSectionFile(basename, type));\r
- } else {\r
- ele.setAttribute("fileName", fileName);\r
- }\r
- if (alignment != null) {\r
- ele.setAttribute("Alignment", alignment);\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 getSectionFile(String basename, String type) {\r
- for (int i = 0; i < sectionExt.length; i++) {\r
- if (sectionExt[i][0].equalsIgnoreCase(type)) {\r
- return "${DEST_DIR_OUTPUT}" + File.separatorChar + basename + sectionExt[i][1];\r
- }\r
- }\r
- return type;\r
- }\r
-\r
- private boolean isSectionType(String type) {\r
- for (int i = 0; i < sectionExt.length; i++) {\r
- if (sectionExt[i][0].equalsIgnoreCase(type)) {\r
- return true;\r
- }\r
- }\r
- return false;\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
- private void genDigest() {\r
- String digestFilePath = project.getProperty("DEST_DIR_OUTPUT");\r
- if (digestFilePath == null) {\r
- EdkLog.log(EdkLog.EDK_WARNING, "Warning: cannot get DEST_DIR_OUTPUT!");\r
- return;\r
- }\r
-\r
- //\r
- // use MD5 algorithm\r
- // \r
- MessageDigest md5 = null;\r
- try {\r
- md5 = MessageDigest.getInstance("MD5");\r
- //\r
- // convert the FFS layout XML DOM tree into string and use it to\r
- // calculate its MD5 digest value\r
- // \r
- md5.update(ffsXmlObject.xmlText().getBytes());\r
- } catch (Exception e) {\r
- EdkLog.log(EdkLog.EDK_WARNING, "Warning: " + e.getMessage());\r
- return;\r
- }\r
-\r
- //\r
- // get the MD5 digest value\r
- // \r
- byte[] digest = md5.digest();\r
-\r
- //\r
- // put the digest in a file named "ffs.md5" if it doesn't exist, otherwise\r
- // we will compare the digest in the file with the one just calculated\r
- // \r
- digestFilePath += File.separator + "ffs.md5";\r
- File digestFile = new File(digestFilePath);\r
- if (digestFile.exists()) {\r
- byte[] oldDigest = new byte[digest.length];\r
- try {\r
- FileInputStream fIn = new FileInputStream(digestFile);\r
- fIn.read(oldDigest);\r
- fIn.close();\r
- } catch (Exception e) {\r
- throw new BuildException(e.getMessage());\r
- }\r
-\r
- boolean noChange = true;\r
- for (int i = 0; i < oldDigest.length; ++i) {\r
- if (digest[i] != oldDigest[i]) {\r
- noChange = false;\r
- break;\r
- }\r
- }\r
-\r
- if (noChange) {\r
- return;\r
- }\r
- }\r
-\r
- //\r
- // update the "ffs.md5" file content with new digest value\r
- // \r
- try {\r
- FileOutputStream fOut = new FileOutputStream(digestFile);\r
- fOut.write(digest);\r
- fOut.close();\r
- } catch (Exception e) {\r
- throw new BuildException(e.getMessage());\r
- }\r
- }\r
-}\r