Move type loops and output feedback from ResourceMgr/BIFImporter to GameData.
[gemrb.git] / gemrb / plugins / BIFImporter / BIFImporter.cpp
blob81273cc84a74edfe1a05f83190efc2cc73f061f5
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "../../includes/win32def.h"
22 #include "../Core/Compressor.h"
23 #include "../Core/FileStream.h"
24 #include "../Core/CachedFileStream.h"
25 #include "BIFImporter.h"
26 #include "../Core/Interface.h"
28 BIFImp::BIFImp(void)
30 stream = NULL;
31 fentries = NULL;
32 tentries = NULL;
35 BIFImp::~BIFImp(void)
37 if (stream) {
38 delete( stream );
40 if (fentries) {
41 delete[] fentries;
43 if (tentries) {
44 delete[] tentries;
48 int BIFImp::DecompressSaveGame(DataStream *compressed)
50 char Signature[8];
51 compressed->Read( Signature, 8 );
52 if (strncmp( Signature, "SAV V1.0", 8 ) ) {
53 return GEM_ERROR;
55 int All = compressed->Remains();
56 int Current;
57 if (!All) return GEM_ERROR;
58 do {
59 ieDword fnlen, complen, declen;
60 compressed->ReadDword( &fnlen );
61 char* fname = ( char* ) malloc( fnlen );
62 compressed->Read( fname, fnlen );
63 strlwr(fname);
64 compressed->ReadDword( &declen );
65 compressed->ReadDword( &complen );
66 PathJoin( path, core->CachePath, fname, NULL );
67 printf( "Decompressing %s\n",fname );
68 free( fname );
69 if (!core->IsAvailable( IE_COMPRESSION_CLASS_ID ))
70 return GEM_ERROR;
71 FILE *in_cache = fopen( path, "wb" );
72 if (!in_cache) {
73 printMessage("BIFImporter", " ", RED);
74 printf( "Cannot write %s.\n", path );
75 return GEM_ERROR;
77 Compressor* comp = ( Compressor* )
78 core->GetInterface( IE_COMPRESSION_CLASS_ID );
79 if (comp->Decompress( in_cache, compressed ) != GEM_OK) {
80 return GEM_ERROR;
82 core->FreeInterface( comp );
83 fclose( in_cache );
84 Current = compressed->Remains();
85 //starting at 40% going up to 90%
86 core->LoadProgress( 40+(All-Current)*50/All );
88 while(Current);
89 return GEM_OK;
92 //this one can create .sav files only
93 int BIFImp::CreateArchive(DataStream *compressed)
95 if (stream) {
96 delete( stream );
97 stream = NULL;
99 if (!compressed) {
100 return GEM_ERROR;
102 char Signature[8];
104 memcpy(Signature,"SAV V1.0",8);
105 compressed->Write(Signature, 8);
107 return GEM_OK;
110 int BIFImp::AddToSaveGame(DataStream *str, DataStream *uncompressed)
112 ieDword fnlen, declen, complen;
114 fnlen = strlen(uncompressed->filename)+1;
115 declen = uncompressed->Size();
116 str->WriteDword( &fnlen);
117 str->Write( uncompressed->filename, fnlen);
118 str->WriteDword( &declen);
119 //baaah, we dump output right in the stream, we get the compressed length
120 //only after the compressed data was written
121 complen = 0xcdcdcdcd; //placeholder
122 unsigned long Pos = str->GetPos(); //storing the stream position
123 str->WriteDword( &complen);
125 Compressor* comp = ( Compressor* )
126 core->GetInterface( IE_COMPRESSION_CLASS_ID );
127 comp->Compress( str, uncompressed );
128 core->FreeInterface( comp );
130 //writing compressed length (calculated)
131 unsigned long Pos2 = str->GetPos();
132 complen = Pos2-Pos-sizeof(ieDword); //calculating the compressed stream size
133 str->Seek(Pos, GEM_STREAM_START); //going back to the placeholder
134 str->WriteDword( &complen); //updating size
135 str->Seek(Pos2, GEM_STREAM_START);//resuming work
136 return GEM_OK;
139 int BIFImp::OpenArchive(const char* filename)
141 if (stream) {
142 delete( stream );
143 stream = NULL;
145 FILE* in_cache = fopen( filename, "rb" );
146 if( !in_cache) {
147 return GEM_ERROR;
149 char Signature[8];
150 if (fread( &Signature, 1, 8, in_cache ) != 8) {
151 fclose ( in_cache );
152 return GEM_ERROR;
154 fclose( in_cache );
155 //normal bif, not in cache
156 if (strncmp( Signature, "BIFFV1 ", 8 ) == 0) {
157 stream = new CachedFileStream( filename );
158 stream->Read( Signature, 8 );
159 strcpy( path, filename );
160 ReadBIF();
161 return GEM_OK;
163 //not found as normal bif
164 //checking compression type
165 FileStream* compressed = new FileStream();
166 compressed->Open( filename, true );
167 compressed->Read( Signature, 8 );
168 if (strncmp( Signature, "BIF V1.0", 8 ) == 0) {
169 ieDword fnlen, complen, declen;
170 compressed->ReadDword( &fnlen );
171 char* fname = ( char* ) malloc( fnlen );
172 compressed->Read( fname, fnlen );
173 strlwr(fname);
174 compressed->ReadDword( &declen );
175 compressed->ReadDword( &complen );
176 PathJoin( path, core->CachePath, fname, NULL );
177 free( fname );
178 in_cache = fopen( path, "rb" );
179 if (in_cache) {
180 //printf("Found in Cache\n");
181 fclose( in_cache );
182 delete( compressed );
183 stream = new CachedFileStream( path );
184 stream->Read( Signature, 8 );
185 if (strncmp( Signature, "BIFFV1 ", 8 ) == 0)
186 ReadBIF();
187 else
188 return GEM_ERROR;
189 return GEM_OK;
191 printf( "Decompressing\n" );
192 if (!core->IsAvailable( IE_COMPRESSION_CLASS_ID )) {
193 printMessage("BIFImporter", "No Compression Manager Available.", RED);
194 return GEM_ERROR;
196 in_cache = fopen( path, "wb" );
197 if (!in_cache) {
198 printMessage("BIFImporter", " ", RED);
199 printf( "Cannot write %s.\n", path );
200 return GEM_ERROR;
202 Compressor* comp = ( Compressor* )
203 core->GetInterface( IE_COMPRESSION_CLASS_ID );
204 if (comp->Decompress( in_cache, compressed ) != GEM_OK) {
205 return GEM_ERROR;
207 core->FreeInterface( comp );
208 fclose( in_cache );
209 delete( compressed );
210 stream = new CachedFileStream( path );
211 stream->Read( Signature, 8 );
212 if (strncmp( Signature, "BIFFV1 ", 8 ) == 0)
213 ReadBIF();
214 else
215 return GEM_ERROR;
216 return GEM_OK;
219 if (strncmp( Signature, "BIFCV1.0", 8 ) == 0) {
220 //printf("'BIFCV1.0' Compressed File Found\n");
221 PathJoin( path, core->CachePath, compressed->filename, NULL );
222 in_cache = fopen( path, "rb" );
223 if (in_cache) {
224 //printf("Found in Cache\n");
225 fclose( in_cache );
226 delete( compressed );
227 stream = new CachedFileStream( path );
228 stream->Read( Signature, 8 );
229 if (strncmp( Signature, "BIFFV1 ", 8 ) == 0) {
230 ReadBIF();
231 } else
232 return GEM_ERROR;
233 return GEM_OK;
235 printf( "Decompressing\n" );
236 if (!core->IsAvailable( IE_COMPRESSION_CLASS_ID ))
237 return GEM_ERROR;
238 Compressor* comp = ( Compressor* )
239 core->GetInterface( IE_COMPRESSION_CLASS_ID );
240 ieDword unCompBifSize;
241 compressed->ReadDword( &unCompBifSize );
242 printf( "\nDecompressing file: [..........]" );
243 fflush(stdout);
244 in_cache = fopen( path, "wb" );
245 if (!in_cache) {
246 printMessage("BIFImporter", " ", RED);
247 printf( "Cannot write %s.\n", path );
248 return GEM_ERROR;
250 ieDword finalsize = 0;
251 int laststep = 0;
252 while (finalsize < unCompBifSize) {
253 compressed->Seek( 8, GEM_CURRENT_POS );
254 if (comp->Decompress( in_cache, compressed ) != GEM_OK) {
255 return GEM_ERROR;
257 finalsize = ftell( in_cache );
258 if (( int ) ( finalsize * ( 10.0 / unCompBifSize ) ) != laststep) {
259 laststep++;
260 printf( "\b\b\b\b\b\b\b\b\b\b\b" );
261 int l;
263 for (l = 0; l < laststep; l++)
264 printf( "|" );
265 for (; l < 10; l++)//l starts from laststep
266 printf( "." );
267 printf( "]" );
268 fflush(stdout);
271 printf( "\n" );
272 core->FreeInterface( comp );
273 fclose( in_cache );
274 delete( compressed );
275 stream = new CachedFileStream( path );
276 stream->Read( Signature, 8 );
277 if (strncmp( Signature, "BIFFV1 ", 8 ) == 0)
278 ReadBIF();
279 else
280 return GEM_ERROR;
281 return GEM_OK;
283 delete (compressed);
284 return GEM_ERROR;
287 DataStream* BIFImp::GetStream(unsigned long Resource, unsigned long Type)
289 DataStream* s = NULL;
290 if (Type == IE_TIS_CLASS_ID) {
291 unsigned int srcResLoc = Resource & 0xFC000;
292 for (unsigned int i = 0; i < tentcount; i++) {
293 if (( tentries[i].resLocator & 0xFC000 ) == srcResLoc) {
294 s = new CachedFileStream( stream, tentries[i].dataOffset,
295 tentries[i].tileSize * tentries[i].tilesCount );
296 break;
299 } else {
300 ieDword srcResLoc = Resource & 0x3FFF;
301 for (ieDword i = 0; i < fentcount; i++) {
302 if (( fentries[i].resLocator & 0x3FFF ) == srcResLoc) {
303 s = new CachedFileStream( stream, fentries[i].dataOffset,
304 fentries[i].fileSize );
305 break;
309 return s;
312 void BIFImp::ReadBIF(void)
314 ieDword foffset;
315 stream->ReadDword( &fentcount );
316 stream->ReadDword( &tentcount );
317 stream->ReadDword( &foffset );
318 stream->Seek( foffset, GEM_STREAM_START );
319 fentries = new FileEntry[fentcount];
320 tentries = new TileEntry[tentcount];
321 if (!fentries || !tentries) {
322 if (fentries) {
323 delete fentries;
324 fentries = NULL;
326 if (tentries) {
327 delete tentries;
328 tentries = NULL;
330 return;
332 unsigned int i;
334 for (i=0;i<fentcount;i++) {
335 stream->ReadDword( &fentries[i].resLocator);
336 stream->ReadDword( &fentries[i].dataOffset);
337 stream->ReadDword( &fentries[i].fileSize);
338 stream->ReadWord( &fentries[i].type);
339 stream->ReadWord( &fentries[i].u1);
341 for (i=0;i<tentcount;i++) {
342 stream->ReadDword( &tentries[i].resLocator);
343 stream->ReadDword( &tentries[i].dataOffset);
344 stream->ReadDword( &tentries[i].tilesCount);
345 stream->ReadDword( &tentries[i].tileSize);
346 stream->ReadWord( &tentries[i].type);
347 stream->ReadWord( &tentries[i].u1);
351 #include "../../includes/plugindef.h"
353 GEMRB_PLUGIN(0xC7F133C, "BIF File Importer")
354 PLUGIN_CLASS(IE_BIF_CLASS_ID, BIFImp)
355 END_PLUGIN()