1 /* 2 Copyright (C) 2008 Jeroen Frijters 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not 13 claim that you wrote the original software. If you use this software 14 in a product, an acknowledgment in the product documentation would be 15 appreciated but is not required. 16 2. Altered source versions must be plainly marked as such, and must not be 17 misrepresented as being the original software. 18 3. This notice may not be removed or altered from any source distribution. 19 20 Jeroen Frijters 21 jeroen@frijters.net 22 23 */ 24 using System; 25 using System.Globalization; 26 using IKVM.Reflection.Emit; 27 28 namespace IKVM.Reflection.Writer 29 { 30 sealed class VersionInfo 31 { 32 private AssemblyName name; 33 private string fileName; 34 internal string copyright; 35 internal string trademark; 36 internal string product; 37 internal string company; 38 private string description; 39 private string title; 40 internal string informationalVersion; 41 private string fileVersion; 42 SetName(AssemblyName name)43 internal void SetName(AssemblyName name) 44 { 45 this.name = name; 46 } 47 SetFileName(string assemblyFileName)48 internal void SetFileName(string assemblyFileName) 49 { 50 this.fileName = System.IO.Path.GetFileName(assemblyFileName); 51 } 52 SetAttribute(AssemblyBuilder asm, CustomAttributeBuilder cab)53 internal void SetAttribute(AssemblyBuilder asm, CustomAttributeBuilder cab) 54 { 55 Universe u = cab.Constructor.Module.universe; 56 Type type = cab.Constructor.DeclaringType; 57 if (copyright == null && type == u.System_Reflection_AssemblyCopyrightAttribute) 58 { 59 copyright = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 60 } 61 else if (trademark == null && type == u.System_Reflection_AssemblyTrademarkAttribute) 62 { 63 trademark = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 64 } 65 else if (product == null && type == u.System_Reflection_AssemblyProductAttribute) 66 { 67 product = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 68 } 69 else if (company == null && type == u.System_Reflection_AssemblyCompanyAttribute) 70 { 71 company = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 72 } 73 else if (description == null && type == u.System_Reflection_AssemblyDescriptionAttribute) 74 { 75 description = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 76 } 77 else if (title == null && type == u.System_Reflection_AssemblyTitleAttribute) 78 { 79 title = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 80 } 81 else if (informationalVersion == null && type == u.System_Reflection_AssemblyInformationalVersionAttribute) 82 { 83 informationalVersion = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 84 } 85 else if (fileVersion == null && type == u.System_Reflection_AssemblyFileVersionAttribute) 86 { 87 fileVersion = (string)cab.DecodeBlob(asm).GetConstructorArgument(0); 88 } 89 } 90 Write(ByteBuffer bb)91 internal void Write(ByteBuffer bb) 92 { 93 if (fileVersion == null) 94 { 95 if (name.Version != null) 96 { 97 fileVersion = name.Version.ToString(); 98 } 99 else 100 { 101 fileVersion = "0.0.0.0"; 102 } 103 } 104 105 int codepage = 1200; // Unicode codepage 106 int lcid = 0x7f; 107 try 108 { 109 if (name.CultureInfo != null) 110 { 111 #if CORECLR 112 throw new NotImplementedException(); 113 #else 114 lcid = name.CultureInfo.LCID; 115 #endif 116 } 117 } 118 catch (ArgumentException) 119 { 120 // AssemblyName.CultureInfo throws an ArgumentException if AssemblyBuilder.__SetAssemblyCulture() was used to specify a non-existing culture 121 } 122 123 Version filever = ParseVersionRobust(fileVersion); 124 int fileVersionMajor = filever.Major; 125 int fileVersionMinor = filever.Minor; 126 int fileVersionBuild = filever.Build; 127 int fileVersionRevision = filever.Revision; 128 129 int productVersionMajor = fileVersionMajor; 130 int productVersionMinor = fileVersionMinor; 131 int productVersionBuild = fileVersionBuild; 132 int productVersionRevision = fileVersionRevision; 133 if (informationalVersion != null) 134 { 135 Version productver = ParseVersionRobust(informationalVersion); 136 productVersionMajor = productver.Major; 137 productVersionMinor = productver.Minor; 138 productVersionBuild = productver.Build; 139 productVersionRevision = productver.Revision; 140 } 141 142 ByteBuffer stringTable = new ByteBuffer(512); 143 stringTable.Write((short)0); // wLength (placeholder) 144 stringTable.Write((short)0); // wValueLength 145 stringTable.Write((short)1); // wType 146 WriteUTF16Z(stringTable, string.Format("{0:x4}{1:x4}", lcid, codepage)); 147 stringTable.Align(4); 148 149 WriteString(stringTable, "Comments", description); 150 WriteString(stringTable, "CompanyName", company); 151 WriteString(stringTable, "FileDescription", title); 152 WriteString(stringTable, "FileVersion", fileVersion); 153 WriteString(stringTable, "InternalName", name.Name); 154 WriteString(stringTable, "LegalCopyright", copyright); 155 WriteString(stringTable, "LegalTrademarks", trademark); 156 WriteString(stringTable, "OriginalFilename", fileName); 157 WriteString(stringTable, "ProductName", product); 158 WriteString(stringTable, "ProductVersion", informationalVersion); 159 160 stringTable.Position = 0; 161 stringTable.Write((short)stringTable.Length); 162 163 ByteBuffer stringFileInfo = new ByteBuffer(512); 164 stringFileInfo.Write((short)0); // wLength (placeholder) 165 stringFileInfo.Write((short)0); // wValueLength 166 stringFileInfo.Write((short)1); // wType 167 WriteUTF16Z(stringFileInfo, "StringFileInfo"); 168 stringFileInfo.Align(4); 169 stringFileInfo.Write(stringTable); 170 stringFileInfo.Position = 0; 171 stringFileInfo.Write((short)stringFileInfo.Length); 172 173 byte[] preamble1 = new byte[] { 174 // VS_VERSIONINFO (platform SDK) 175 0x34, 0x00, // wValueLength 176 0x00, 0x00, // wType 177 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" 178 0x00, 0x00, // Padding1 (32 bit alignment) 179 // VS_FIXEDFILEINFO starts 180 0xBD, 0x04, 0xEF, 0xFE, // dwSignature (0xFEEF04BD) 181 0x00, 0x00, 0x01, 0x00, // dwStrucVersion 182 }; 183 byte[] preamble2 = new byte[] { 184 0x3F, 0x00, 0x00, 0x00, // dwFileFlagsMask (??) 185 0x00, 0x00, 0x00, 0x00, // dwFileFlags (??) 186 0x04, 0x00, 0x00, 0x00, // dwFileOS 187 0x02, 0x00, 0x00, 0x00, // dwFileType 188 0x00, 0x00, 0x00, 0x00, // dwFileSubtype 189 0x00, 0x00, 0x00, 0x00, // dwFileDateMS 190 0x00, 0x00, 0x00, 0x00, // dwFileDateLS 191 // Padding2 (32 bit alignment) 192 // VarFileInfo 193 0x44, 0x00, // wLength 194 0x00, 0x00, // wValueLength 195 0x01, 0x00, // wType 196 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" 197 0x00, 0x00, // Padding 198 // Var 199 0x24, 0x00, // wLength 200 0x04, 0x00, // wValueLength 201 0x00, 0x00, // wType 202 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" 203 0x00, 0x00, // Padding (32 bit alignment) 204 }; 205 bb.Write((short)(2 + preamble1.Length + 8 + 8 + preamble2.Length + 4 + stringFileInfo.Length)); 206 bb.Write(preamble1); 207 bb.Write((short)fileVersionMinor); 208 bb.Write((short)fileVersionMajor); 209 bb.Write((short)fileVersionRevision); 210 bb.Write((short)fileVersionBuild); 211 bb.Write((short)productVersionMinor); 212 bb.Write((short)productVersionMajor); 213 bb.Write((short)productVersionRevision); 214 bb.Write((short)productVersionBuild); 215 bb.Write(preamble2); 216 bb.Write((short)lcid); 217 bb.Write((short)codepage); 218 bb.Write(stringFileInfo); 219 } 220 WriteUTF16Z(ByteBuffer bb, string str)221 private static void WriteUTF16Z(ByteBuffer bb, string str) 222 { 223 foreach (char c in str) 224 { 225 bb.Write((short)c); 226 } 227 bb.Write((short)0); 228 } 229 WriteString(ByteBuffer bb, string name, string value)230 private static void WriteString(ByteBuffer bb, string name, string value) 231 { 232 value = value ?? " "; 233 int pos = bb.Position; 234 bb.Write((short)0); // wLength (placeholder) 235 bb.Write((short)(value.Length + 1));// wValueLength 236 bb.Write((short)1); // wType 237 WriteUTF16Z(bb, name); 238 bb.Align(4); 239 WriteUTF16Z(bb, value); 240 bb.Align(4); 241 int savedPos = bb.Position; 242 bb.Position = pos; 243 bb.Write((short)(savedPos - pos)); 244 bb.Position = savedPos; 245 } 246 ParseVersionRobust(string ver)247 private static Version ParseVersionRobust(string ver) 248 { 249 int index = 0; 250 ushort major = ParseVersionPart(ver, ref index); 251 ushort minor = ParseVersionPart(ver, ref index); 252 ushort build = ParseVersionPart(ver, ref index); 253 ushort revision = ParseVersionPart(ver, ref index); 254 return new Version(major, minor, build, revision); 255 } 256 ParseVersionPart(string str, ref int pos)257 private static ushort ParseVersionPart(string str, ref int pos) 258 { 259 ushort value = 0; 260 while (pos < str.Length) 261 { 262 char c = str[pos]; 263 if (c == '.') 264 { 265 pos++; 266 break; 267 } 268 else if (c >= '0' && c <= '9') 269 { 270 value *= 10; 271 value += (ushort)(c - '0'); 272 pos++; 273 } 274 else 275 { 276 break; 277 } 278 } 279 return value; 280 } 281 } 282 } 283