summaryrefslogtreecommitdiff
path: root/src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java')
-rw-r--r--src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java364
1 files changed, 364 insertions, 0 deletions
diff --git a/src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java b/src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java
new file mode 100644
index 0000000..f16f94e
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/cpptasks/platforms/WindowsPlatform.java
@@ -0,0 +1,364 @@
+/*
+ *
+ * Copyright 2004 The Ant-Contrib project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.cpptasks.platforms;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import net.sf.antcontrib.cpptasks.CUtil;
+import net.sf.antcontrib.cpptasks.TargetMatcher;
+import net.sf.antcontrib.cpptasks.VersionInfo;
+import net.sf.antcontrib.cpptasks.compiler.LinkType;
+
+
+/**
+ * Platform specific behavior for Microsoft Windows.
+ *
+ * @author Curt Arnold
+ */
+public final class WindowsPlatform {
+
+ /**
+ * Constructor.
+ */
+ private WindowsPlatform() {
+ }
+ /**
+ * Adds source or object files to the bidded fileset to
+ * support version information.
+ *
+ * @param versionInfo version information
+ * @param linkType link type
+ * @param isDebug true if debug build
+ * @param outputFile name of generated executable
+ * @param objDir directory for generated files
+ * @param matcher bidded fileset
+ * @throws IOException if unable to write version resource
+ */
+ public static void addVersionFiles(final VersionInfo versionInfo,
+ final LinkType linkType,
+ final File outputFile,
+ final boolean isDebug,
+ final File objDir,
+ final TargetMatcher matcher)
+ throws IOException {
+ if (versionInfo == null) {
+ throw new NullPointerException("versionInfo");
+ }
+ if (linkType == null) {
+ throw new NullPointerException("linkType");
+ }
+ if (outputFile == null) {
+ throw new NullPointerException("outputFile");
+ }
+ if (objDir == null) {
+ throw new NullPointerException("objDir");
+ }
+
+ /**
+ * Fully resolve version info
+ */
+ VersionInfo mergedInfo = versionInfo.merge();
+
+ File versionResource = new File(objDir, "versioninfo.rc");
+
+ boolean notChanged = false;
+ //
+ // if the resource exists
+ //
+ if (versionResource.exists()) {
+ ByteArrayOutputStream memStream = new ByteArrayOutputStream();
+ Writer writer = new BufferedWriter(new OutputStreamWriter(memStream));
+ writeResource(writer, mergedInfo, outputFile, isDebug, linkType);
+ writer.close();
+ ByteArrayInputStream proposedResource = new ByteArrayInputStream(
+ memStream.toByteArray());
+
+ InputStream existingResource = new FileInputStream(versionResource);
+ //
+ //
+ //
+ notChanged = hasSameContent(proposedResource, existingResource);
+ existingResource.close();
+ }
+
+ //
+ // if the resource file did not exist or will be changed then
+ // write the file
+ //
+ if (!notChanged) {
+ Writer writer = new BufferedWriter(
+ new OutputStreamWriter(
+ new FileOutputStream(versionResource)));
+ writeResource(writer, mergedInfo, outputFile, isDebug, linkType);
+ writer.close();
+ }
+ if (matcher != null) {
+ matcher.visit(new File(versionResource.getParent()),
+ versionResource.getName());
+ }
+
+ }
+
+ /**
+ * Compare two input streams for duplicate content
+ *
+ * Naive implementation, but should not be performance issue.
+ * @param stream1 stream
+ * @param stream2 stream
+ * @return true if streams are identical in content
+ * @throws IOException if error reading streams
+ */
+ private static boolean hasSameContent(final InputStream stream1,
+ final InputStream stream2)
+ throws IOException {
+ int byte1 = -1;
+ int byte2 = -1;
+ do {
+ byte1 = stream1.read();
+ byte2 = stream2.read();
+
+ }
+ while (byte1 == byte2 && byte1 != -1);
+ return (byte1 == byte2);
+ }
+
+
+ /**
+ * Parse version string into array of four short values.
+ * @param version String version
+ * @return short[] four element array
+ */
+ public static short[] parseVersion(final String version) {
+ short[] values = new short[] {
+ 0, 0, 0, 0};
+ if (version != null) {
+ StringBuffer buf = new StringBuffer(version);
+ int start = 0;
+ for (int i = 0; i < 4; i++) {
+ int end = version.indexOf('.', start);
+ if (end <= 0) {
+ end = version.length();
+ for (int j = end; j > start; j--) {
+ String part = buf.substring(start, end);
+ try {
+ values[i] = Short.parseShort(part);
+ break;
+ } catch (NumberFormatException ex) {
+ values[i] = 0;
+ }
+ }
+ break;
+ } else {
+ String part = buf.substring(start, end);
+ try {
+ values[i] = Short.parseShort(part);
+ start = end + 1;
+ } catch (NumberFormatException ex) {
+ break;
+ }
+ }
+ }
+ }
+ return values;
+ }
+
+ /**
+ * Converts parsed version information into a string representation.
+ *
+ * @param buf StringBuffer string buffer to receive version number
+ * @param version short[] four-element array
+ */
+ private static void encodeVersion(final StringBuffer buf,
+ final short[] version) {
+ for (int i = 0; i < 3; i++) {
+ buf.append(Short.toString(version[i]));
+ buf.append(',');
+ }
+ buf.append(Short.toString(version[3]));
+ }
+
+ /**
+ * Writes windows resource.
+ * @param writer writer, may not be nul
+ * @param versionInfo version information
+ * @param outputFile executable file
+ * @param isDebug true if debug
+ * @param linkType link type
+ * @throws IOException if error writing resource file
+ */
+ public static void writeResource(final Writer writer,
+ final VersionInfo versionInfo,
+ final File outputFile,
+ final boolean isDebug,
+ final LinkType linkType) throws IOException {
+
+ //writer.write("#include \"windows.h\"\n");
+
+ writer.write("VS_VERSION_INFO VERSIONINFO\n");
+ StringBuffer buf = new StringBuffer("FILEVERSION ");
+ encodeVersion(buf, parseVersion(versionInfo.getFileversion()));
+ buf.append("\nPRODUCTVERSION ");
+ encodeVersion(buf, parseVersion(versionInfo.getProductversion()));
+ buf.append("\n");
+ writer.write(buf.toString());
+ buf.setLength(0);
+ buf.append("FILEFLAGSMASK 0x1L /* VS_FF_DEBUG */");
+ Boolean patched = versionInfo.getPatched();
+ Boolean prerelease = versionInfo.getPrerelease();
+ if (patched != null) {
+ buf.append(" | 0x4L /* VS_FF_PATCHED */");
+ }
+ if (prerelease != null) {
+ buf.append(" | 0x2L /* VS_FF_PRERELEASE */");
+ }
+ if (versionInfo.getPrivatebuild() != null) {
+ buf.append(" | 0x8L /* VS_FF_PRIVATEBUILD */");
+ }
+ if (versionInfo.getSpecialbuild() != null) {
+ buf.append(" | 0x20L /* VS_FF_SPECIALBUILD */");
+ }
+ buf.append('\n');
+ writer.write(buf.toString());
+ buf.setLength(0);
+ buf.append("FILEFLAGS ");
+
+ if (isDebug) {
+ buf.append("0x1L /* VS_FF_DEBUG */ | ");
+ }
+ if (Boolean.TRUE.equals(patched)) {
+ buf.append("0x4L /* VS_FF_PATCHED */ | ");
+ }
+ if (Boolean.TRUE.equals(prerelease)) {
+ buf.append("0x2L /* VS_FF_PRERELEASE */ | ");
+ }
+ if (Boolean.TRUE.equals(versionInfo.getPrivatebuild())) {
+ buf.append("0x8L /* VS_FF_PRIVATEBUILD */ | ");
+ }
+ if (Boolean.TRUE.equals(versionInfo.getSpecialbuild())) {
+ buf.append("0x20L /* VS_FF_SPECIALBUILD */ | ");
+ }
+ if (buf.length() > 10) {
+ buf.setLength(buf.length() - 3);
+ buf.append('\n');
+ } else {
+ buf.append("0\n");
+ }
+ writer.write(buf.toString());
+ buf.setLength(0);
+
+ writer.write("FILEOS 0x40004 /* VOS_NT_WINDOWS32 */\nFILETYPE ");
+ if (linkType.isExecutable()) {
+ writer.write("0x1L /* VFT_APP */\n");
+ } else {
+ if (linkType.isSharedLibrary()) {
+ writer.write("0x2L /* VFT_DLL */\n");
+ } else if (linkType.isStaticLibrary()) {
+ writer.write("0x7L /* VFT_STATIC_LIB */\n");
+ } else {
+ writer.write("0x0L /* VFT_UNKNOWN */\n");
+ }
+ }
+ writer.write("FILESUBTYPE 0x0L\n");
+ writer.write("BEGIN\n");
+ writer.write("BLOCK \"StringFileInfo\"\n");
+ writer.write(" BEGIN\n#ifdef UNICODE\nBLOCK \"040904B0\"\n");
+ writer.write("#else\nBLOCK \"040904E4\"\n#endif\n");
+ writer.write("BEGIN\n");
+ if (versionInfo.getFilecomments() != null) {
+ writer.write("VALUE \"Comments\", \"");
+ writer.write(versionInfo.getFilecomments());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getCompanyname() != null) {
+ writer.write("VALUE \"CompanyName\", \"");
+ writer.write(versionInfo.getCompanyname());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getFiledescription() != null) {
+ writer.write("VALUE \"FileDescription\", \"");
+ writer.write(versionInfo.getFiledescription());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getFileversion() != null) {
+ writer.write("VALUE \"FileVersion\", \"");
+ writer.write(versionInfo.getFileversion());
+ writer.write("\\0\"\n");
+ }
+ String baseName = CUtil.getBasename(outputFile);
+ String internalName = versionInfo.getInternalname();
+ if (internalName == null) {
+ internalName = baseName;
+ }
+ writer.write("VALUE \"InternalName\", \"");
+ writer.write(internalName);
+ writer.write("\\0\"\n");
+ if (versionInfo.getLegalcopyright() != null) {
+ writer.write("VALUE \"LegalCopyright\", \"");
+ writer.write(versionInfo.getLegalcopyright());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getLegaltrademarks() != null) {
+ writer.write("VALUE \"LegalTrademarks\", \"");
+ writer.write(versionInfo.getLegaltrademarks());
+ writer.write("\\0\"\n");
+ }
+ writer.write("VALUE \"OriginalFilename\", \"");
+ writer.write(baseName);
+ writer.write("\\0\"\n");
+ if (versionInfo.getPrivatebuild() != null) {
+ writer.write("VALUE \"PrivateBuild\", \"");
+ writer.write(versionInfo.getPrivatebuild());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getProductname() != null) {
+ writer.write("VALUE \"ProductName\", \"");
+ writer.write(versionInfo.getProductname());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getProductversion() != null) {
+ writer.write("VALUE \"ProductVersion\", \"");
+ writer.write(versionInfo.getProductversion());
+ writer.write("\\0\"\n");
+ }
+ if (versionInfo.getSpecialbuild() != null) {
+ writer.write("VALUE \"SpecialBuild\", \"");
+ writer.write(versionInfo.getSpecialbuild());
+ writer.write("\\0\"\n");
+ }
+ writer.write("END\n");
+ writer.write("END\n");
+
+ writer.write("BLOCK \"VarFileInfo\"\n");
+ writer.write("BEGIN\n#ifdef UNICODE\n");
+ writer.write("VALUE \"Translation\", 0x409, 1200\n");
+ writer.write("#else\n");
+ writer.write("VALUE \"Translation\", 0x409, 1252\n");
+ writer.write("#endif\n");
+ writer.write("END\n");
+ writer.write("END\n");
+ }
+
+}