public Dictionary <String, String> GetFixedFileInfo() { VersionItem root = VSVersionInfo; Dictionary <String, String> ffi = root.Value as Dictionary <String, String>; Dictionary <String, String> ret = new Dictionary <String, String>(ffi); // this copies contents return(ret); }
// VS_VERSION parsing assisted by looking at the source of the Vestris ResourceLib ( http://www.codeproject.com/KB/library/ResourceLib.aspx ) // it helped with figuring out how to processing padding; my recursive approach diffthers from his though internal static VersionResourceData TryCreate(Byte[] data, ResourceLang lang) { using (MemoryStream s = new MemoryStream(data)) using (BinaryReader rdr = new BinaryReader(s, Encoding.Unicode)) { // good thing VS_VERSION_INFO uses UTF16 throughout try { VersionItem root = RecurseItem(Mode.Root, rdr); return(new VersionResourceData(root, data, lang)); } catch (AnolisException) { // TODO: how should this be logged? return(null); } } //using }
public Dictionary <String, String> GetStringTable() { VersionItem item = GetFirstItem(VSVersionInfo, Mode.StringTable); if (item == null) { return(null); } Dictionary <String, String> ret = new Dictionary <String, String>(); foreach (VersionItem str in item.Children) { ret.Add(str.Key, str.Value == null ? String.Empty : str.Value.ToString()); } return(ret); }
internal static VersionResourceData TryCreate(Byte[] data, ResourceLang lang) { using (MemoryStream s = new MemoryStream(data)) using (BinaryReader rdr = new BinaryReader(s, Encoding.Unicode)) { // good thing VS_VERSION_INFO uses UTF16 throughout // new approach: // recursively build a tree of versionitem classes then handle them intelligently afterwards Mode mode = Mode.Root; VersionItem root = new VersionItem(); root.Mode = mode; root.wLength = rdr.ReadUInt16(); root.wValueLength = rdr.ReadUInt16(); root.wType = rdr.ReadUInt16(); root.szKey = GetKey(mode, rdr, out mode); root.padding = Pad(rdr); UInt32 signature = rdr.ReadUInt32(); if (signature != 0xFEEF04BD) { throw new InvalidOperationException("lol wtf"); } rdr.ReadBytes(48); // this is where FixedFileInfo goes (58 - 4) Byte[] padding2 = Pad(rdr); List <Object> children = new List <Object>(); // 1 2 3 4 5 6 Int32 bytesRead = 2 + 2 + 2 + ((root.szKey.Length * 2) + 2) + root.padding.Length + 4 + 48; _bytesRead = bytesRead; while (bytesRead < root.wLength) { VersionItem child = RecurseItem(GetNextMode(mode), rdr); // no need to switch since the children will always be VersionItems children.Add(child); bytesRead += child.wLength; } root.children = children.ToArray(); return(null); } //using }
private VersionItem GetFirstItem(VersionItem parent, Mode mode) { if (parent.Mode == mode) { return(parent); } foreach (VersionItem item in parent.Children) { if (item.Mode == mode) { return(item); } VersionItem match = GetFirstItem(item, mode); if (match != null) { return(match); } } return(null); }
private static VersionItem RecurseItem(VersionItemMode mode, BinaryReader rdr) { Int64 initPos = rdr.BaseStream.Position; VersionItem item = new VersionItem(mode); item.Length = rdr.ReadUInt16(); item.ValueLength = rdr.ReadUInt16(); item.Type = rdr.ReadUInt16(); item.Key = GetKey(mode, rdr, out item._mode); rdr.Align4(); mode = item.Mode; List <VersionItem> children = new List <VersionItem>(); while (rdr.BaseStream.Position < initPos + item.Length) { switch (mode) { case Mode.Root: if (item.Value == null) { Byte[] ffiBytes = rdr.ReadBytes(item.ValueLength); // this is where FixedFileInfo goes /*Byte[] padding2 = */ rdr.Align4(); if (ffiBytes.Length >= 52) // 52 == 0x34 { VSFixedFileInfo ffi = new VSFixedFileInfo(ffiBytes); if (ffi.Signature != 0xFEEF04BD) { throw new InvalidOperationException("Unrecognised VS_VERSIONINFO Signature"); } Dictionary <String, String> ffiDict = FfiToDict(ffi); item.Value = ffiDict; } else { throw new InvalidOperationException("Unexpected VS_FIXEDFILEINFO length"); } } goto default; case Mode.String: Byte[] bytes = rdr.ReadBytes(item.ValueLength * 2); String s = Encoding.Unicode.GetString(bytes.SubArray(0, bytes.Length - 2)); // miss out the null terminator item.Value = s; break; case Mode.Var: Byte[] data = rdr.ReadBytes(item.ValueLength); // wValueLength = size in bytes item.Value = data; // data is a DWORD array indicating the language and code page combinations supported by this file. // The low-order word of each DWORD must contain a Microsoft language identifier, and the high-order word must contain the IBM code page number. // Either high-order or low-order word can be zero, indicating that the file is language or code page independent. // ms-help://MS.MSDNQTR.v90.en/winui/winui/windowsuserinterface/resources/versioninformation/versioninformationreference/versioninformationstructures/var.htm break; default: VersionItem child = RecurseItem(GetNextMode(mode), rdr); children.Add(child); break; } // the reader was corrupted before entering the third String of the first StringTable of the StringFileInfo // so let's see if padding here helps rdr.Align4(); } rdr.Align4(); item.Children = children.ToArray(); return(item); }
private VersionResourceData(VersionItem root, Byte[] rawData, ResourceLang lang) : base(lang, rawData) { VSVersionInfo = root; }
private static VersionItem RecurseItem(Mode mode, BinaryReader rdr) { Int64 initPos = rdr.BaseStream.Position; VersionItem item = new VersionItem(); item.wLength = rdr.ReadUInt16(); item.wValueLength = rdr.ReadUInt16(); item.wType = rdr.ReadUInt16(); item.szKey = GetKey(mode, rdr, out item.Mode); item.padding = Pad(rdr); mode = item.Mode; List <Object> children = new List <Object>(); // 1 2 3 4 5 Int32 bytesRead = 2 + 2 + 2 + ((item.szKey.Length * 2) + 2) + item.padding.Length; _bytesRead += bytesRead; while (bytesRead < item.wLength) { switch (mode) { case Mode.String: Byte[] bytes = rdr.ReadBytes(item.wValueLength * 2); String s = Encoding.Unicode.GetString(bytes.SubArray(0, bytes.Length - 2)); // miss out the null terminator children.Add(s); bytesRead += item.wValueLength * 2; _bytesRead += item.wValueLength * 2; if (bytesRead != item.wLength) { throw new InvalidOperationException("More bytes left over?"); } break; case Mode.Var: Byte[] data = rdr.ReadBytes(item.wValueLength); // wValueLength = size in bytes children.Add(data); // I'll figure out what to do with the data later bytesRead += item.wValueLength; _bytesRead += item.wValueLength; if (bytesRead != item.wLength) { throw new InvalidOperationException("More bytes left over?"); } break; default: VersionItem child = RecurseItem(GetNextMode(mode), rdr); children.Add(child); bytesRead += child.wLength; // after here (this breakpoint being triggered when children.count == 8) the while() loop continues, it's as if bytesRead isn't set properly such that it thinks VarFileInfo is a member of the Strings in the StringTable rather than a new section entirely break; } // the reader was corrupted before entering the third String of the first StringTable of the StringFileInfo // so let's see if padding here helps Int32 padding = Pad(rdr).Length; bytesRead += padding; _bytesRead += padding; } Int64 currentPos = rdr.BaseStream.Position; if (bytesRead > item.wLength) { // seek backwards so that it lines up Int64 goBack = bytesRead - item.wLength; rdr.BaseStream.Seek(-goBack, SeekOrigin.Current); } item.children = children.ToArray(); return(item); }