1 /* 2 Copyright (C) 2005-2007 Tom Beaumont 3 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. 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 <stdint.h> 20 #include <SDL_endian.h> 21 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 29 30 struct PackFile1 31 { 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. 34 * 35 * It works on: i386, amd64, mips o32 ABI, powerPC 36 * Maybe it's also compiler dependent ... 37 * 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]; 49 GetNextPackFile150 Entry* GetNext() 51 { 52 return (Entry*)((char*)name + len); 53 } 54 DataPackFile155 void* Data() 56 { 57 char* pos = name; 58 while (*pos!=0) 59 pos++; 60 return pos+1; 61 } 62 DataLenPackFile163 int DataLen() 64 { 65 return len - strlen(name) - 1; 66 } 67 } 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 74 75 int numfiles; 76 Entry** e; 77 void* data; 78 PackFile1PackFile179 PackFile1() : numfiles(0), e(0), data(0) 80 {} 81 FindPackFile182 Entry* Find(const char* name) 83 { 84 if (numfiles==0) return 0; 85 int a=0, b=numfiles; 86 while (b>a) 87 { 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; 96 } 97 return 0; 98 } 99 ReadPackFile1100 void Read(FILE* f) 101 { 102 if (numfiles || e || data) 103 FATAL("Calling Packfile1::Read when already initialised."); 104 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); 111 112 data = malloc(size); 113 char* data_end = (char*)data + size; 114 fread(data, 1, size, f); 115 116 numfiles=0; 117 Entry* i = (Entry*)data; 118 while ((void*)i < data_end) 119 { 120 numfiles++; 121 int32_t *data_length = (int32_t*)i; 122 *data_length = SWAP32(*data_length); 123 i = i->GetNext(); 124 } 125 126 e = new Entry* [numfiles]; // CHECKME: where to delete? 127 128 i = (Entry*)data; 129 for (int j=0; j<numfiles; j++, i = i->GetNext()) 130 e[j] = i; 131 } 132 ~PackFile1PackFile1133 ~PackFile1() 134 { 135 free(data); 136 } 137 138 }; 139