Merge branch 'i18n'
[hex-a-hop.git] / packfile.h
blob9e5d5f91b6a299b452ff6e26bf28fec67802399c
1 /*
2 Copyright (C) 2005-2007 Tom Beaumont
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
19 #include <stdint.h>
20 #include <SDL/SDL_endian.h>
22 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
23 #define SWAP16(X) (X)
24 #define SWAP32(X) (X)
25 #else
26 #define SWAP16(X) SDL_Swap16(X)
27 #define SWAP32(X) SDL_Swap32(X)
28 #endif
30 struct PackFile1
32 /* Is it *NOT* save to interpret a byte stream as list of Entries!
33 * The alignment could increase the Entry size on some systems without attribute.
35 * It works on: i386, amd64, mips o32 ABI, powerPC
36 * Maybe it's also compiler dependent ...
38 * See also http://c-faq.com/struct/padding.html,
39 * http://c-faq.com/strangeprob/ptralign.html and Debian bug #442854
40 * (Need to refer to a C FAQ in a (so called) C++ program, argh ...)
41 * */
42 class Entry {
43 int32_t len;
44 public:
45 // an array of size 1 (no char* pointer!) is saved after len,
46 // accessing name[0] should (but doesn't always) fit the first byte after len
47 // See e.g. http://c-faq.com/aryptr/index.html
48 char name[1];
50 Entry* GetNext()
52 return (Entry*)((char*)name + len);
55 void* Data()
57 char* pos = name;
58 while (*pos!=0)
59 pos++;
60 return pos+1;
63 int DataLen()
65 return len - strlen(name) - 1;
68 #ifdef __GNUC__
69 __attribute__ ((__packed__));
70 int static_assert1[sizeof(Entry)==5 ? 0 : -1];
71 #else
72 int static_assert1[sizeof(Entry)<=8 ? 0 : -1];
73 #endif
75 int numfiles;
76 Entry** e;
77 void* data;
79 PackFile1() : numfiles(0), e(0), data(0)
80 {}
82 Entry* Find(const char* name)
84 if (numfiles==0) return 0;
85 int a=0, b=numfiles;
86 while (b>a)
88 const int mid = (a+b)>>1;
89 int diff = strcmp(name, e[mid]->name);
90 if (diff==0)
91 return e[mid];
92 else if (diff < 0)
93 b=mid;
94 else
95 a=mid+1;
97 return 0;
100 void Read(FILE* f)
102 if (numfiles || e || data)
103 FATAL("Calling Packfile1::Read when already initialised.");
105 int32_t size;
106 fseek(f, -(int)sizeof(size), SEEK_END);
107 int end_offset = ftell(f);
108 fread(&size, sizeof(size), 1, f);
109 size = SWAP32(size);
110 fseek(f, end_offset - size, SEEK_SET);
112 data = malloc(size);
113 char* data_end = (char*)data + size;
114 fread(data, 1, size, f);
116 numfiles=0;
117 Entry* i = (Entry*)data;
118 while ((void*)i < data_end)
120 numfiles++;
121 int32_t *data_length = (int32_t*)i;
122 *data_length = SWAP32(*data_length);
123 i = i->GetNext();
126 e = new Entry* [numfiles]; // CHECKME: where to delete?
128 i = (Entry*)data;
129 for (int j=0; j<numfiles; j++, i = i->GetNext())
130 e[j] = i;
133 ~PackFile1()
135 free(data);