1 /* Tower Toppler - Nebulus
2  * Copyright (C) 2000-2012  Andreas R�ver
3  *
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.
8 
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.
13 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 
19 #include "archi.h"
20 #include "decl.h"
21 #include <zlib.h>
22 #include <string.h>
23 #include <stdlib.h>
24 
25 /* this value is used as a sanity check for filnename lengths
26  */
27 #define FNAMELEN 250
28 
archive(FILE * stream)29 archive::archive(FILE *stream) : f(stream) {
30 
31   assert_msg(f, "Data file not found");
32 
33   /* find out the number of files inside the archive
34    * alloce the neccessary memory
35    */
36   fread(&filecount, 1, 1, f);
37   files = new fileindex[filecount];
38   assert_msg(files, "Failed to alloc memory for archive index.");
39 
40   /* read the information for each file */
41   for (Uint8 file = 0; file < filecount; file++) {
42 
43     Uint8 strlen = 0;
44 
45     /* find ut the length of the name string */
46     {
47       char c;
48       long currentpos = ftell(f);
49 
50       do {
51         strlen++;
52         assert_msg(strlen <= FNAMELEN, "Filename too long, datafile corrupt?");
53         fread(&c, 1, 1, f);
54       } while (c);
55 
56       fseek(f, currentpos, SEEK_SET);
57     }
58 
59     /* alloc memory for string and read it */
60     files[file].name = new char[strlen];
61     for (int pos = 0; pos < strlen; pos++)
62       fread(&files[file].name[pos], 1, 1, f);
63 
64     Uint8 tmp;
65 
66     /* load start from archive */
67     fread(&tmp, 1, 1, f);
68     files[file].start = ((Uint32)(tmp)) << 0;
69     fread(&tmp, 1, 1, f);
70     files[file].start |= ((Uint32)(tmp)) << 8;
71     fread(&tmp, 1, 1, f);
72     files[file].start |= ((Uint32)(tmp)) << 16;
73     fread(&tmp, 1, 1, f);
74     files[file].start |= ((Uint32)(tmp)) << 24;
75 
76     /* load filesize from archive */
77     fread(&tmp, 1, 1, f);
78     files[file].size = ((Uint32)(tmp)) << 0;
79     fread(&tmp, 1, 1, f);
80     files[file].size |= ((Uint32)(tmp)) << 8;
81     fread(&tmp, 1, 1, f);
82     files[file].size |= ((Uint32)(tmp)) << 16;
83     fread(&tmp, 1, 1, f);
84     files[file].size |= ((Uint32)(tmp)) << 24;
85 
86     /* load compressed size from archive */
87     fread(&tmp, 1, 1, f);
88     files[file].compress = ((Uint32)(tmp)) << 0;
89     fread(&tmp, 1, 1, f);
90     files[file].compress |= ((Uint32)(tmp)) << 8;
91     fread(&tmp, 1, 1, f);
92     files[file].compress |= ((Uint32)(tmp)) << 16;
93     fread(&tmp, 1, 1, f);
94     files[file].compress |= ((Uint32)(tmp)) << 24;
95   }
96 }
97 
~archive()98 archive::~archive() {
99 
100   /* free memory allocated for filenames */
101   for (int i = 0; i < filecount; i++)
102     delete [] files[i].name;
103 
104   /* free the file header array */
105   delete [] files;
106 
107   fclose(f);
108 }
109 
file(const archive * arc,const char * name)110 file::file(const archive *arc, const char *name) : bufferpos(0) {
111 
112   for (Uint8 i = 0; i < arc->filecount; i++) {
113     if (strncmp(name, arc->files[i].name, FNAMELEN) == 0) {
114 
115       /* allocate buffer for compressed data */
116       Uint8 *b = new Uint8[arc->files[i].compress];
117 
118       /* allocate buffer for uncompressed data */
119       fsize = arc->files[i].size;
120       buffer = new Uint8[fsize];
121 
122       /* read the compressed data */
123       fseek(arc->f, arc->files[i].start, SEEK_SET);
124       fread(b, arc->files[i].compress, 1, arc->f);
125 
126       /* decompress it and check results */
127       assert_msg(uncompress(buffer, &fsize, b, arc->files[i].compress) == Z_OK, "Decompression problem, data file corrupt?");
128       assert_msg(fsize == arc->files[i].size, "Data file corrupt.");
129 
130       /* free temporary buffer */
131       delete [] b;
132 
133       return;
134     }
135   }
136 
137   /* if we arrive here we couldn't find the file we looked for */
138   assert_msg(0, "File not found in archive!");
139 }
140 
~file()141 file::~file() { delete [] buffer; }
142 
read(void * buf,Uint32 size)143 Uint32 file::read(void *buf, Uint32 size) {
144   memcpy(buf, &buffer[bufferpos], size);
145   bufferpos += size;
146   return size;
147 }
148 
getbyte(void)149 Uint8 file::getbyte(void) {
150   return buffer[bufferpos++];
151 }
152 
getword(void)153 Uint16 file::getword(void) {
154   Uint16 w = (Uint16)buffer[bufferpos] + ((Uint16)buffer[bufferpos+1] << 8);
155   bufferpos+=2;
156   return w;
157 }
158 
rwOps(void)159 SDL_RWops *file::rwOps(void) {
160   return SDL_RWFromMem(buffer, fsize);
161 }
162 
163 
164 archive * dataarchive;
165