add support to SDLBackend for rendering 24bit data
[openc2e.git] / cobFile.cpp
blobdcca8361182b7c0ffcdd554e0fea69a0e681d17f
1 /*
2 * cobFile.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Fri Jan 18 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 "cobFile.h"
21 #include "exceptions.h"
22 #include "endianlove.h"
24 cobFile::cobFile(fs::path filepath) {
25 path = filepath;
26 file.open(path.native_directory_string().c_str(), std::ios::binary);
28 if (!file.is_open())
29 throw creaturesException(std::string("couldn't open COB file \"") + path.native_directory_string() + "\"");
31 // TODO: c1 cob support
32 char majic[4];
33 file.read(majic, 4);
34 if (strncmp(majic, "cob2", 4) != 0)
35 throw creaturesException(std::string("bad magic of C2 COB file \"") + path.native_directory_string() + "\"");
37 while (!file.eof()) {
38 // TODO: catch exceptions, and free all blocks before passing it up the stack
39 cobBlock *b = new cobBlock(this);
40 blocks.push_back(b);
42 file.peek(); // make sure eof() gets set
46 cobFile::~cobFile() {
47 for (std::vector<cobBlock *>::iterator i = blocks.begin(); i != blocks.end(); i++) {
48 delete *i;
52 cobBlock::cobBlock(cobFile *p) {
53 std::istream &file = p->getStream();
55 char cobtype[4];
56 file.read(cobtype, 4);
57 type = std::string(cobtype, 4);
59 file.read((char *)&size, 4); size = swapEndianLong(size);
61 offset = file.tellg();
62 file.seekg(size, std::ios::cur);
64 loaded = false;
65 buffer = 0;
66 parent = p;
69 cobBlock::~cobBlock() {
70 if (loaded)
71 free();
74 void cobBlock::load() {
75 assert(!loaded);
76 std::istream &file = parent->getStream();
78 file.clear();
79 file.seekg(offset);
80 if (!file.good())
81 throw creaturesException("Failed to seek to block offset.");
83 loaded = true;
85 buffer = new unsigned char[size];
86 file.read((char *)buffer, size);
87 if (!file.good()) {
88 free();
89 throw creaturesException("Failed to read block.");
93 void cobBlock::free() {
94 assert(loaded);
96 loaded = false;
98 delete[] buffer;
99 buffer = 0;
102 // TODO: argh, isn't there a better way to do this?
103 std::string readstring(std::istream &file) {
104 unsigned int i = 0, n = 4096;
105 char *buf = (char *)malloc(n);
107 while (true) {
108 file.read(&buf[i], 1);
109 if (!file.good())
110 throw creaturesException("Failed to read string.");
112 // found null terminator
113 if (buf[i] == 0) {
114 std::string s = buf;
115 free(buf);
116 return s;
119 i++;
121 // out of space?
122 if (i == n) {
123 n = n * 2;
124 buf = (char *)realloc(buf, n);
129 cobAgentBlock::cobAgentBlock(cobBlock *p) {
130 parent = p;
131 std::istream &file = p->getParent()->getStream();
133 file.clear();
134 file.seekg(p->getOffset());
135 if (!file.good())
136 throw creaturesException("Failed to seek to block offset.");
138 file.read((char *)&quantityremaining, 2); quantityremaining = swapEndianShort(quantityremaining);
139 file.read((char *)&lastusage, 4); lastusage = swapEndianLong(lastusage);
140 file.read((char *)&reuseinterval, 4); reuseinterval = swapEndianLong(reuseinterval);
141 file.read((char *)&usebyday, 1);
142 file.read((char *)&usebymonth, 1);
143 file.read((char *)&usebyyear, 2); usebyyear = swapEndianShort(usebyyear);
145 file.seekg(12, std::ios::cur); // unused
147 name = readstring(file);
148 description = readstring(file);
149 installscript = readstring(file);
150 removescript = readstring(file);
152 unsigned short noevents;
153 file.read((char *)&noevents, 2); noevents = swapEndianShort(noevents);
154 for (unsigned int i = 0; i < noevents; i++) {
155 scripts.push_back(readstring(file));
158 unsigned short nodeps;
159 file.read((char *)&nodeps, 2); nodeps = swapEndianShort(nodeps);
160 for (unsigned int i = 0; i < nodeps; i++) {
161 unsigned short deptype;
162 file.read((char *)&deptype, 2); deptype = swapEndianShort(deptype);
163 deptypes.push_back(deptype);
165 // depnames should be read as lower-case to ease comparison
166 std::string depname = readstring(file);
167 std::transform(depname.begin(), depname.end(), depname.begin(), (int(*)(int))tolower);
168 depnames.push_back(depname);
171 file.read((char *)&thumbnailwidth, 2); thumbnailwidth = swapEndianShort(thumbnailwidth);
172 file.read((char *)&thumbnailheight, 2); thumbnailheight = swapEndianShort(thumbnailheight);
173 thumbnail = new unsigned short[thumbnailwidth * thumbnailheight];
174 file.read((char *)thumbnail, 2 * thumbnailwidth * thumbnailheight);
177 cobAgentBlock::~cobAgentBlock() {
178 delete[] thumbnail;
181 cobFileBlock::cobFileBlock(cobBlock *p) {
182 parent = p;
183 std::istream &file = p->getParent()->getStream();
185 file.clear();
186 file.seekg(p->getOffset());
187 if (!file.good())
188 throw creaturesException("Failed to seek to block offset.");
190 file.read((char *)&filetype, 2); filetype = swapEndianShort(filetype);
191 file.seekg(4, std::ios::cur); // unused
192 file.read((char *)&filesize, 4); filesize = swapEndianLong(filesize);
194 // filenames should be read as lower-case to ease comparison
195 filename = readstring(file);
196 std::transform(filename.begin(), filename.end(), filename.begin(), (int(*)(int))tolower);
199 cobFileBlock::~cobFileBlock() {
202 unsigned char *cobFileBlock::getFileContents() {
203 if (!parent->isLoaded())
204 parent->load();
206 return parent->getBuffer() + 10 + filename.size() + 1;
209 /* vim: set noet: */