xoreos  0.0.5
pe_exe.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cassert>
26 #include <cstdio>
27 
28 #include "src/common/pe_exe.h"
29 #include "src/common/encoding.h"
31 
32 namespace Common {
33 
34 PEResourceID::PEResourceID() : _idType(kIDTypeNull) {
35 }
36 
37 PEResourceID::PEResourceID(UString x) : _idType(kIDTypeString), _name(x) {
38 }
39 
40 PEResourceID::PEResourceID(uint32 x) : _idType(kIDTypeNumerical), _id(x) {
41 }
42 
44  _name = string;
46  return *this;
47 }
48 
50  _id = x;
52  return *this;
53 }
54 
55 bool PEResourceID::operator==(const UString &x) const {
57 }
58 
59 bool PEResourceID::operator==(const uint32 &x) const {
60  return _idType == kIDTypeNumerical && _id == x;
61 }
62 
63 bool PEResourceID::operator==(const PEResourceID &x) const {
64  if (_idType != x._idType)
65  return false;
66  if (_idType == kIDTypeString)
67  return _name.equalsIgnoreCase(x._name);
69  return _id == x._id;
70  return true;
71 }
72 
73 bool PEResourceID::operator<(const PEResourceID &x) const {
74  return toString() < x.toString();
75 }
76 
78  if (_idType != kIDTypeString)
79  return "";
80 
81  return _name;
82 }
83 
86  return 0xffffffff;
87 
88  return _id;
89 }
90 
92  if (_idType == kIDTypeString)
93  return _name;
94  else if (_idType == kIDTypeNumerical) {
95  static char name[9];
96  std::sprintf(name, "%08x", _id);
97  name[8] = 0;
98  return name;
99  }
100 
101  return "";
102 }
103 
105  assert(_exe);
106 
107  if (!loadFromEXE(*_exe))
108  throw Exception("Failed to parse exe");
109 }
110 
112 }
113 
115  if (exe.readUint16BE() != MKTAG_16('M', 'Z'))
116  return false;
117 
118  exe.skip(58);
119 
120  uint32 peOffset = exe.readUint32LE();
121 
122  if (!peOffset || peOffset >= (uint32)exe.size())
123  return false;
124 
125  exe.seek(peOffset);
126 
127  if (exe.readUint32BE() != MKTAG('P', 'E', '\0', '\0'))
128  return false;
129 
130  exe.skip(2);
131  uint16 sectionCount = exe.readUint16LE();
132  exe.skip(12);
133  uint16 optionalHeaderSize = exe.readUint16LE();
134  exe.skip(optionalHeaderSize + 2);
135 
136  // Read in all the sections
137  for (uint16 i = 0; i < sectionCount; i++) {
138  char sectionName[9];
139  exe.read(sectionName, 8);
140  sectionName[8] = 0;
141 
142  Section section;
143  exe.skip(4);
144  section.virtualAddress = exe.readUint32LE();
145  section.size = exe.readUint32LE();
146  section.offset = exe.readUint32LE();
147  exe.skip(16);
148 
149  _sections[sectionName] = section;
150  }
151 
152  // Currently, we require loading a resource section
153  if (_sections.find(".rsrc") == _sections.end())
154  return false;
155 
156  Section &resSection = _sections[".rsrc"];
157  parseResourceLevel(exe, resSection, resSection.offset, 0);
158 
159  return true;
160 }
161 
163  Section &section, uint32 offset, int level) {
164  exe.seek(offset + 12);
165 
166  uint16 entryCount = exe.readUint16LE(); // named entry count
167  entryCount += exe.readUint16LE(); // id entry count
168 
169  for (uint32 i = 0; i < entryCount; i++) {
170  uint32 value = exe.readUint32LE();
171 
172  PEResourceID id;
173 
174  if (value & 0x80000000) {
175  value &= 0x7fffffff;
176 
177  uint32 startPos = exe.pos();
178  exe.seek(section.offset + (value & 0x7fffffff));
179 
180  // Read in the name, UTF-16LE
181  uint16 nameLength = exe.readUint16LE() * 2;
182  UString name = readStringFixed(exe, kEncodingUTF16LE, nameLength);
183 
184  exe.seek(startPos);
185 
186  id = name;
187  } else {
188  id = value;
189  }
190 
191  uint32 nextOffset = exe.readUint32LE();
192  uint32 lastOffset = exe.pos();
193 
194  if (level == 0)
195  _curType = id;
196  else if (level == 1)
197  _curName = id;
198  else if (level == 2)
199  _curLang = id;
200 
201  if (level < 2) {
202  // Time to dive down further
203  parseResourceLevel(exe, section, section.offset + (nextOffset & 0x7fffffff), level + 1);
204  } else {
205  exe.seek(section.offset + nextOffset);
206 
207  Resource resource;
208  resource.offset = exe.readUint32LE() + section.offset - section.virtualAddress;
209  resource.size = exe.readUint32LE();
210 
211  //status("Found resource '%s' '%s' '%s' at %d of size %d", _curType.toString().c_str(),
212  // _curName.toString().c_str(), _curLang.toString().c_str(), resource.offset, resource.size);
213 
214  _resources[_curType][_curName][_curLang] = resource;
215  }
216 
217  exe.seek(lastOffset);
218  }
219 }
220 
221 const std::vector<PEResourceID> PEResources::getTypeList() const {
222  std::vector<PEResourceID> array;
223 
224  for (TypeMap::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
225  array.push_back(it->first);
226 
227  return array;
228 }
229 
230 const std::vector<PEResourceID> PEResources::getNameList(const PEResourceID &type) const {
231  std::vector<PEResourceID> array;
232 
233  if (_resources.find(type) == _resources.end())
234  return array;
235 
236  const NameMap &nameMap = _resources.find(type)->second;
237 
238  for (NameMap::const_iterator it = nameMap.begin(); it != nameMap.end(); ++it)
239  array.push_back(it->first);
240 
241  return array;
242 }
243 
244 const std::vector<PEResourceID> PEResources::getLangList(const PEResourceID &type, const PEResourceID &name) const {
245  std::vector<PEResourceID> array;
246 
247  if (_resources.find(type) == _resources.end())
248  return array;
249 
250  const NameMap &nameMap = _resources.find(type)->second;
251 
252  if (nameMap.find(name) == nameMap.end())
253  return array;
254 
255  const LangMap &langMap = nameMap.find(name)->second;
256 
257  for (LangMap::const_iterator it = langMap.begin(); it != langMap.end(); ++it)
258  array.push_back(it->first);
259 
260  return array;
261 }
262 
264  std::vector<PEResourceID> langList = getLangList(type, name);
265 
266  if (langList.empty())
267  return 0;
268 
269  const Resource &resource = _resources.find(type)->second.find(name)->second.find(langList[0])->second; // fun stuff
270  _exe->seek(resource.offset);
271  return _exe->readStream(resource.size);
272 }
273 
275  const PEResourceID &lang) {
276 
277  if (_resources.find(type) == _resources.end())
278  return 0;
279 
280  const NameMap &nameMap = _resources.find(type)->second;
281 
282  if (nameMap.find(name) == nameMap.end())
283  return 0;
284 
285  const LangMap &langMap = nameMap.find(name)->second;
286 
287  if (langMap.find(lang) == langMap.end())
288  return 0;
289 
290  const Resource &resource = langMap.find(lang)->second;
291  _exe->seek(resource.offset);
292  return _exe->readStream(resource.size);
293 }
294 
295 } // End of namespace Common
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
const std::vector< PEResourceID > getTypeList() const
Return a list of resource types.
Definition: pe_exe.cpp:221
uint16 readUint16LE()
Read an unsigned 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:122
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:133
Definition: 2dafile.h:39
A class holding an UTF-8 string.
Definition: ustring.h:48
PEResourceID _curLang
Definition: pe_exe.h:146
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
const std::vector< PEResourceID > getNameList(const PEResourceID &type) const
Return a list of names for a given type.
Definition: pe_exe.cpp:230
PEResourceID & operator=(UString string)
Definition: pe_exe.cpp:43
bool equalsIgnoreCase(const UString &str) const
Definition: ustring.cpp:218
Implementing the reading stream interfaces for plain memory blocks.
ScopedPtr< SeekableReadStream > _exe
Definition: pe_exe.h:142
SeekableReadStream * getResource(const PEResourceID &type, const PEResourceID &name)
Return a stream to the specified resource, taking the first language found (or 0 if non-existent)...
Definition: pe_exe.cpp:263
UTF-16 LE (little endian).
Definition: encoding.h:44
bool operator==(const UString &x) const
Definition: pe_exe.cpp:55
bool operator<(const PEResourceID &x) const
Definition: pe_exe.cpp:73
TypeMap _resources
Definition: pe_exe.h:148
UString getString() const
Definition: pe_exe.cpp:77
uint16_t uint16
Definition: types.h:202
uint16 readUint16BE()
Read an unsigned 16-bit word stored in big endian (MSB first) order from the stream and return it...
Definition: readstream.h:155
std::map< UString, Section > _sections
Definition: pe_exe.h:139
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Definition: readstream.h:317
PEResourceID _curType
Definition: pe_exe.h:144
PEResources(SeekableReadStream *exe)
Definition: pe_exe.cpp:104
virtual size_t read(void *dataPtr, size_t dataSize)=0
Read data from the stream.
PEResourceID _curName
Definition: pe_exe.h:145
Utility functions for working with differing string encodings.
UString _name
The resource&#39;s string ID.
Definition: pe_exe.h:69
bool loadFromEXE(SeekableReadStream &exe)
Definition: pe_exe.cpp:114
StackException Exception
Definition: error.h:59
const std::vector< PEResourceID > getLangList(const PEResourceID &type, const PEResourceID &name) const
Return a list of languages for a given type and name.
Definition: pe_exe.cpp:244
virtual size_t size() const =0
Obtains the total size of the stream, measured in bytes.
std::map< PEResourceID, Resource > LangMap
Definition: pe_exe.h:135
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
uint32 readUint32BE()
Read an unsigned 32-bit word stored in big endian (MSB first) order from the stream and return it...
Definition: readstream.h:166
Portable executable parsing.
uint32_t uint32
Definition: types.h:204
UString toString() const
Definition: pe_exe.cpp:91
enum Common::PEResourceID::IDType _idType
#define MKTAG_16(a0, a1)
A wrapper macro used around two character constants, like &#39;MZ&#39;.
Definition: endianness.h:143
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
Definition: encoding.cpp:297
void parseResourceLevel(SeekableReadStream &exe, Section &section, uint32 offset, int level)
Definition: pe_exe.cpp:162
uint32 getID() const
Definition: pe_exe.cpp:84
std::map< PEResourceID, LangMap > NameMap
Definition: pe_exe.h:136
Interface for a seekable & readable data stream.
Definition: readstream.h:265
uint32 _id
The resource&#39;s numerical ID.
Definition: pe_exe.h:70