/* Copyright (C) 2008 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jeroen Frijters jeroen@frijters.net */ using System; using System.Globalization; using IKVM.Reflection.Emit; namespace IKVM.Reflection.Writer { sealed class VersionInfo { private AssemblyName name; private string fileName; internal string copyright; internal string trademark; internal string product; internal string company; private string description; private string title; internal string informationalVersion; private string fileVersion; internal void SetName(AssemblyName name) { this.name = name; } internal void SetFileName(string assemblyFileName) { this.fileName = System.IO.Path.GetFileName(assemblyFileName); } internal void SetAttribute(AssemblyBuilder asm, CustomAttributeBuilder cab) { Universe u = cab.Constructor.Module.universe; Type type = cab.Constructor.DeclaringType; if (copyright == null && type == u.System_Reflection_AssemblyCopyrightAttribute) { copyright = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (trademark == null && type == u.System_Reflection_AssemblyTrademarkAttribute) { trademark = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (product == null && type == u.System_Reflection_AssemblyProductAttribute) { product = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (company == null && type == u.System_Reflection_AssemblyCompanyAttribute) { company = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (description == null && type == u.System_Reflection_AssemblyDescriptionAttribute) { description = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (title == null && type == u.System_Reflection_AssemblyTitleAttribute) { title = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (informationalVersion == null && type == u.System_Reflection_AssemblyInformationalVersionAttribute) { informationalVersion = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } else if (fileVersion == null && type == u.System_Reflection_AssemblyFileVersionAttribute) { fileVersion = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); } } internal void Write(ByteBuffer bb) { if (fileVersion == null) { if (name.Version != null) { fileVersion = name.Version.ToString(); } else { fileVersion = "0.0.0.0"; } } int codepage = 1200; // Unicode codepage int lcid = 0x7f; try { if (name.CultureInfo != null) { #if CORECLR throw new NotImplementedException(); #else lcid = name.CultureInfo.LCID; #endif } } catch (ArgumentException) { // AssemblyName.CultureInfo throws an ArgumentException if AssemblyBuilder.__SetAssemblyCulture() was used to specify a non-existing culture } Version filever = ParseVersionRobust(fileVersion); int fileVersionMajor = filever.Major; int fileVersionMinor = filever.Minor; int fileVersionBuild = filever.Build; int fileVersionRevision = filever.Revision; int productVersionMajor = fileVersionMajor; int productVersionMinor = fileVersionMinor; int productVersionBuild = fileVersionBuild; int productVersionRevision = fileVersionRevision; if (informationalVersion != null) { Version productver = ParseVersionRobust(informationalVersion); productVersionMajor = productver.Major; productVersionMinor = productver.Minor; productVersionBuild = productver.Build; productVersionRevision = productver.Revision; } ByteBuffer stringTable = new ByteBuffer(512); stringTable.Write((short)0); // wLength (placeholder) stringTable.Write((short)0); // wValueLength stringTable.Write((short)1); // wType WriteUTF16Z(stringTable, string.Format("{0:x4}{1:x4}", lcid, codepage)); stringTable.Align(4); WriteString(stringTable, "Comments", description); WriteString(stringTable, "CompanyName", company); WriteString(stringTable, "FileDescription", title); WriteString(stringTable, "FileVersion", fileVersion); WriteString(stringTable, "InternalName", name.Name); WriteString(stringTable, "LegalCopyright", copyright); WriteString(stringTable, "LegalTrademarks", trademark); WriteString(stringTable, "OriginalFilename", fileName); WriteString(stringTable, "ProductName", product); WriteString(stringTable, "ProductVersion", informationalVersion); stringTable.Position = 0; stringTable.Write((short)stringTable.Length); ByteBuffer stringFileInfo = new ByteBuffer(512); stringFileInfo.Write((short)0); // wLength (placeholder) stringFileInfo.Write((short)0); // wValueLength stringFileInfo.Write((short)1); // wType WriteUTF16Z(stringFileInfo, "StringFileInfo"); stringFileInfo.Align(4); stringFileInfo.Write(stringTable); stringFileInfo.Position = 0; stringFileInfo.Write((short)stringFileInfo.Length); byte[] preamble1 = new byte[] { // VS_VERSIONINFO (platform SDK) 0x34, 0x00, // wValueLength 0x00, 0x00, // wType 0x56, 0x00, 0x53, 0x00, 0x5F, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x00, 0x00, // "VS_VERSION_INFO\0" 0x00, 0x00, // Padding1 (32 bit alignment) // VS_FIXEDFILEINFO starts 0xBD, 0x04, 0xEF, 0xFE, // dwSignature (0xFEEF04BD) 0x00, 0x00, 0x01, 0x00, // dwStrucVersion }; byte[] preamble2 = new byte[] { 0x3F, 0x00, 0x00, 0x00, // dwFileFlagsMask (??) 0x00, 0x00, 0x00, 0x00, // dwFileFlags (??) 0x04, 0x00, 0x00, 0x00, // dwFileOS 0x02, 0x00, 0x00, 0x00, // dwFileType 0x00, 0x00, 0x00, 0x00, // dwFileSubtype 0x00, 0x00, 0x00, 0x00, // dwFileDateMS 0x00, 0x00, 0x00, 0x00, // dwFileDateLS // Padding2 (32 bit alignment) // VarFileInfo 0x44, 0x00, // wLength 0x00, 0x00, // wValueLength 0x01, 0x00, // wType 0x56, 0x00, 0x61, 0x00, 0x72, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x66, 0x00, 0x6F, 0x00, 0x00, 0x00, // "VarFileInfo\0" 0x00, 0x00, // Padding // Var 0x24, 0x00, // wLength 0x04, 0x00, // wValueLength 0x00, 0x00, // wType 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00, // "Translation\0" 0x00, 0x00, // Padding (32 bit alignment) }; bb.Write((short)(2 + preamble1.Length + 8 + 8 + preamble2.Length + 4 + stringFileInfo.Length)); bb.Write(preamble1); bb.Write((short)fileVersionMinor); bb.Write((short)fileVersionMajor); bb.Write((short)fileVersionRevision); bb.Write((short)fileVersionBuild); bb.Write((short)productVersionMinor); bb.Write((short)productVersionMajor); bb.Write((short)productVersionRevision); bb.Write((short)productVersionBuild); bb.Write(preamble2); bb.Write((short)lcid); bb.Write((short)codepage); bb.Write(stringFileInfo); } private static void WriteUTF16Z(ByteBuffer bb, string str) { foreach (char c in str) { bb.Write((short)c); } bb.Write((short)0); } private static void WriteString(ByteBuffer bb, string name, string value) { value = value ?? " "; int pos = bb.Position; bb.Write((short)0); // wLength (placeholder) bb.Write((short)(value.Length + 1));// wValueLength bb.Write((short)1); // wType WriteUTF16Z(bb, name); bb.Align(4); WriteUTF16Z(bb, value); bb.Align(4); int savedPos = bb.Position; bb.Position = pos; bb.Write((short)(savedPos - pos)); bb.Position = savedPos; } private static Version ParseVersionRobust(string ver) { int index = 0; ushort major = ParseVersionPart(ver, ref index); ushort minor = ParseVersionPart(ver, ref index); ushort build = ParseVersionPart(ver, ref index); ushort revision = ParseVersionPart(ver, ref index); return new Version(major, minor, build, revision); } private static ushort ParseVersionPart(string str, ref int pos) { ushort value = 0; while (pos < str.Length) { char c = str[pos]; if (c == '.') { pos++; break; } else if (c >= '0' && c <= '9') { value *= 10; value += (ushort)(c - '0'); pos++; } else { break; } } return value; } } }