1 /** 2 * Support for Windows PE VersionInfo resources. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <ae@cy.md> 12 */ 13 14 module ae.sys.windows.pe.versioninfo; 15 16 import std.algorithm.searching; 17 import std.conv; 18 import std.exception; 19 import std..string; 20 21 /// Parses PE VersionInfo resources. 22 struct VersionInfoParser 23 { 24 ubyte[] data; /// All data. 25 26 this(void[] data) 27 { 28 enforce((cast(size_t)data.ptr) % 4 == 0, "Data must be DWORD-aligned"); 29 this.data = cast(ubyte[])data; 30 root = readNode(); 31 } /// 32 33 /// A `VersionInfo` node. 34 struct Node 35 { 36 string key; /// 37 bool isText; /// 38 void[] value; /// 39 Node[] children; /// 40 41 /// Return the string contents of a text node. 42 @property string valueText() 43 { 44 if (!value.length) 45 return null; 46 auto str = cast(wchar[])value; 47 enforce(str.endsWith("\0"w), "Not null-terminated"); 48 return str[0..$-1].to!string; 49 } 50 } 51 Node root; /// The root node. 52 53 Node readNode() 54 { 55 auto size = read!ushort() - ushort.sizeof; 56 auto remainingData = data[size..$]; 57 scope(success) data = remainingData; 58 data = data[0..size]; 59 60 auto valueLength = read!ushort(); 61 auto type = read!ushort(); 62 if (type) 63 valueLength *= 2; 64 65 wchar[] key; 66 ubyte[] value; 67 debug (verparse) scope(failure) stderr.writefln("wLength=%d wValueLength=%d remainder=%d wType=%d key=%(%s%) [error]", size, valueLength, data.length, type, [key]); 68 if (valueLength < data.length && (cast(wchar[])data[0..$-valueLength]).indexOf('\0') < 0) 69 { 70 // Work around resource compiler bug 71 debug (verparse) stderr.writeln("Resource compiler bug detected"); 72 valueLength += 2; // Make up for the lost null terminator 73 auto wdata = cast(wchar[])data; 74 while (wdata.length > 1 && wdata[$-1] == 0 && wdata[$-2] == 0) 75 wdata = wdata[0..$-1]; 76 auto point = wdata.length - valueLength/wchar.sizeof; 77 key = wdata[0..point]; 78 value = cast(ubyte[])wdata[point..$]; 79 data = null; 80 } 81 else 82 { 83 key = readWStringz(); 84 readAlign(); 85 if (valueLength > data.length) 86 valueLength = data.length.to!ushort; // Work around Borland linker bug (madCHook.dll) 87 value = readBytes(valueLength); 88 readAlign(); 89 } 90 91 debug (verparse) 92 { 93 stderr.writefln("wLength=%d wValueLength=%d remainder=%d wType=%d key=%(%s%)", size, valueLength, data.length, type, [key]); 94 if (value.length) 95 stderr.writeln(hexDump(value)); 96 } 97 98 Node node; 99 node.key = to!string(key); 100 node.isText = type > 0; 101 node.value = value; 102 103 while (data.length) 104 { 105 node.children ~= readNode(); 106 readAlign(); 107 } 108 109 return node; 110 } 111 112 T read(T)() 113 { 114 T value = *cast(T*)data.ptr; 115 data = data[T.sizeof..$]; 116 return value; 117 } 118 119 wchar[] readWStringz() 120 { 121 auto start = cast(wchar*)data.ptr; 122 size_t count = 0; 123 while (read!wchar()) 124 count++; 125 return start[0..count]; 126 } 127 128 ubyte[] readBytes(size_t count) 129 { 130 scope(success) data = data[count..$]; 131 return data[0..count]; 132 } 133 134 void readAlign() 135 { 136 while (data.length && (cast(size_t)data.ptr) % 4 != 0) 137 read!ubyte(); 138 } 139 } 140