add wraparound support to C2 physics
[openc2e.git] / peFile.cpp
blob0589a1639c1b15fb0959660c170af7860cf0f631
1 /*
2 * peFile.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Mon Apr 28 2008.
6 * Copyright (c) 2008 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
20 #include "peFile.h"
21 #include "exceptions.h"
22 #include "streamutils.h"
24 // debug helper
25 std::string nameForType(uint32 t) {
26 switch (t) {
27 case 1: return "Cursor";
28 case 2: return "Bitmap";
29 case 3: return "Icon";
30 case 4: return "Menu";
31 case 5: return "Dialog";
32 case 6: return "String";
33 case 7: return "Fontdir";
34 case 8: return "Font";
35 case 9: return "Accelerator";
36 case 10: return "RCData";
37 case 11: return "MessageTable";
38 case 16: return "Version";
41 return "Unknown";
45 * This isn't a full PE parser, but it manages to extract resources from the
46 * .exe files included with both Creatures and Creatures 2.
49 peFile::peFile(fs::path filepath) {
50 path = filepath;
51 file.open(path.native_directory_string().c_str(), std::ios::binary);
53 if (!file.is_open())
54 throw creaturesException(std::string("couldn't open PE file \"") + path.native_directory_string() + "\"");
56 // check the signature of the file
57 char majic[2];
58 file.read(majic, 2);
59 if (strncmp(majic, "MZ", 2) != 0)
60 throw creaturesException(std::string("couldn't understand PE file \"") + path.native_directory_string() + "\" (not a PE file?)");
62 // skip the rest of the DOS header
63 file.seekg(58, std::ios::cur);
65 // read the location of the PE header
66 uint32 e_lfanew = read32(file);
67 if (e_lfanew == 0)
68 throw creaturesException(std::string("couldn't understand PE file \"") + path.native_directory_string() + "\" (DOS program?)");
70 // seek to the PE header and check the signature
71 file.seekg(e_lfanew, std::ios::beg);
72 char pemajic[4];
73 file.read(pemajic, 4);
74 if (memcmp(pemajic, "PE\0\0", 4) != 0)
75 throw creaturesException(std::string("couldn't understand PE file \"") + path.native_directory_string() + "\" (corrupt?)");
77 // read the necessary data from the PE file header
78 file.seekg(2, std::ios::cur);
79 uint16 nosections = read16(file);
80 file.seekg(12, std::ios::cur);
81 uint16 optionalheadersize = read16(file);
82 file.seekg(2, std::ios::cur);
84 // skip the optional header
85 file.seekg(optionalheadersize, std::ios::cur);
87 for (unsigned int i = 0; i < nosections; i++) {
88 char section_name[9]; section_name[8] = 0;
89 file.read(section_name, 8);
91 file.seekg(4, std::ios::cur);
93 peSection section;
94 section.vaddr = read32(file);
95 section.size = read32(file);
96 section.offset = read32(file);
97 sections[std::string(section_name)] = section;
99 file.seekg(16, std::ios::cur);
102 parseResources();
105 void peFile::parseResources() {
106 std::map<std::string, peSection>::iterator si = sections.find(std::string(".rsrc"));
107 if (si == sections.end()) return;
108 peSection &s = si->second;
110 parseResourcesLevel(s, s.offset, 0);
113 unsigned int currtype, currname, currlang;
115 void peFile::parseResourcesLevel(peSection &s, unsigned int off, unsigned int level) {
116 file.seekg(off, std::ios::beg);
118 file.seekg(12, std::ios::cur);
120 uint16 nonamedentries = read16(file);
121 uint16 noidentries = read16(file);
123 for (unsigned int i = 0; i < nonamedentries + noidentries; i++) {
124 uint32 name = read32(file);
125 uint32 offset = read32(file);
127 unsigned int here = file.tellg();
129 if (level == 0) {
130 currtype = name;
131 } else if (level == 1) {
132 /* we don't check for strings here because we don't care :) */
133 currname = name;
134 } else if (level == 2) {
135 currlang = name;
138 if (level < 2) {
139 /* another level, more horror */
141 parseResourcesLevel(s, s.offset + offset & 0x7fffffff, level + 1);
142 } else {
143 /* bottom level, file data is here */
145 file.seekg(s.offset + offset, std::ios::beg);
147 uint32 offset = read32(file);
148 offset += s.offset;
149 offset -= s.vaddr;
150 uint32 size = read32(file);
152 /*if ((currlang & 0xff) == 0x09) { // LANG_ENGLISH
153 file.seekg(offset, std::ios::beg);
155 char *data = (char*)malloc(size);
156 file.read(data, size);
158 char buf[500];
159 sprintf(buf, "/tmp/oh/%s_%d_%d_%d", nameForType(currtype).c_str(), currname, currlang, offset);
160 std::ofstream f(buf);
161 f.write(data, size);
163 free(data);
167 file.seekg(here, std::ios::beg);
171 peFile::~peFile() {
174 /* vim: set noet: */