00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025
00026 #ifdef TARGET // Compiling the main program
00027 #include "crogue.h"
00028 #endif
00029
00030 #include "substdio.h"
00031 #include "config.h"
00032 #include "rle.h"
00033 #include "huffman.h"
00034
00035 #ifdef DISABLE_COMPRESSION
00036 #define DISABLE_RLE
00037 #endif
00038
00039 #define CHECKSUM_INIT 0xF1897134L
00040 #define CHECKSUM_MUL 0xA8159803L
00041 #define CHECKSUM_ADD 0x81340967L
00042 static unsigned short _runlen=0;
00043 static unsigned char _runchar=' ';
00044
00045 static unsigned long _checksum_file(FILE *f);
00046
00047 static unsigned char _rleread_file(void);
00048 static unsigned char _rleread_ptr(void);
00049 static unsigned char _rleread_huffman(void);
00050
00051 static const void *_rlepos;
00052 static unsigned char (*_rleread)(void);
00053 #ifdef CPROTO //HACKHACK - for some reason, cproto's choking
00054 static void *_putc_compress;
00055 #else
00056 static void (*_putc_compress)(unsigned char c, FILE *f) = (void(*)(unsigned char c, FILE *f))&fputc;
00057 #endif
00058
00059 static const unsigned char magic_byte = 0x5F;
00060
00061
00062 unsigned long checksum_bytes(void *data, unsigned int length)
00063 {
00064 unsigned long checksum = CHECKSUM_INIT;
00065 unsigned i;
00066
00067 for(i=0; i<length; i++)
00068 {
00069 checksum += ((unsigned char*)data)[i];
00070 checksum *= CHECKSUM_MUL;
00071 checksum += CHECKSUM_ADD;
00072 }
00073
00074 return checksum;
00075 }
00076
00077
00078 static unsigned long _checksum_file(FILE *f)
00079 {
00080 #ifdef IS_CALCULATOR
00081 return checksum_bytes((char*)f->base+6, peek_w(f->base)-6);
00082 #else
00083 return 0;
00084 #endif
00085 }
00086
00087
00088
00089
00090 int frleverify(FILE *f)
00091 {
00092 #ifdef IS_CALCULATOR
00093 return _checksum_file(f) == peek_l( (char*)f->base + 2 );
00094 #else
00095 return 1;
00096 #endif
00097 }
00098
00099
00100
00101 void frlewrite(void *data, size_t s, size_t granularity, FILE *f)
00102 {
00103 unsigned long i, j;
00104
00105 #ifdef DEBUG_FILES
00106 unsigned long checksum;
00107 #endif
00108
00109 #ifdef DEBUG_FILES
00110 checksum = checksum_bytes(data, s);
00111 # ifdef DISABLE_COMPRESSION
00112 fwrite(&checksum, sizeof(long), 1, f);
00113 # else
00114 frleflush(f);
00115 for(i=0; i<sizeof(checksum); i++)
00116 _putc_compress( (char)(checksum>>(8*i)), f );
00117 # endif
00118 #endif
00119
00120 #ifdef DISABLE_COMPRESSION
00121 fwrite(data, s, 1, f);
00122 #else
00123 # ifdef DISABLE_RLE
00124 for(i=0; i<s; i++)
00125 _putc_compress( ((unsigned char*)data)[i], f );
00126 # else
00127 for(i=0; i<granularity; i++)
00128 for(j=i; j<s; j+=granularity)
00129 frleputc( ((unsigned char*)data)[j], f);
00130 # endif
00131 #endif
00132 }
00133
00134
00135 void frleread(void *data, size_t s, size_t granularity, FILE *f)
00136 {
00137 unsigned long i, j;
00138 #ifdef DEBUG_FILES
00139 unsigned long checksum_read, checksum_validate;
00140 #endif
00141
00142 #ifndef DISABLE_COMPRESSION
00143 rle_set_source(rle_huffman, f);
00144 #endif
00145
00146 #ifdef DEBUG_FILES
00147 # ifdef DISABLE_COMPRESSION
00148 fread(&checksum_read, sizeof(long), 1, f);
00149 # else
00150 checksum_read = 0;
00151 for(i=0; i<sizeof(checksum_read); i++)
00152 checksum_read += rlegetc() << (8*i);
00153 # endif
00154 #endif
00155
00156 #ifdef DISABLE_COMPRESSION
00157 fread(data, s, 1, f);
00158 #else
00159 # ifdef DISABLE_RLE
00160 for(i=0; i<s; i++)
00161 ((unsigned char*)data)[i] = _rleread();
00162 # else
00163 for(i=0; i<granularity; i++)
00164 for(j=i; j<s; j+=granularity)
00165 ((char*)data)[j] = rlegetc();
00166 # endif
00167 #endif
00168
00169 #ifdef DEBUG_FILES
00170 checksum_validate = checksum_bytes(data, s);
00171 if(checksum_read != checksum_validate) {
00172 # ifndef EXTERNAL_TOOL
00173 message( gettext(
00174 "File checksum doesn't match! %lp vs %lp, size=%i, granularity=%i"),
00175 checksum_read, checksum_validate, s, granularity);
00176 # endif
00177 }
00178 #endif
00179 }
00180
00181
00182
00183 void frleinit(void)
00184 {
00185 _runlen=0;
00186 _runchar=0;
00187 }
00188
00189
00190 void frleinit_read(FILE *f)
00191 {
00192 frleinit();
00193 fseek(f, 4, SEEK_SET);
00194 }
00195
00196
00197 void frleinit_write(FILE *f, void (*outfunc)(unsigned char c, FILE *f))
00198 {
00199 unsigned long padding = 0;
00200 frleinit();
00201 _putc_compress = outfunc;
00202
00203
00204 fwrite(&padding, sizeof padding, 1, f);
00205 }
00206
00207
00208 void frleinit_write_nochecksum(void (*outfunc)(unsigned char c, FILE *f))
00209 {
00210 frleinit();
00211 _putc_compress = outfunc;
00212 }
00213
00214
00215 void frlefinalize(FILE *f)
00216 {
00217 unsigned long checksum;
00218
00219 frleflush(f);
00220
00221 checksum = _checksum_file(f);
00222 rewind(f);
00223 fwrite(&checksum, sizeof checksum, 1, f);
00224 }
00225
00226
00227 void frleflush(FILE *fout)
00228 {
00229 if(_runlen > 127)
00230 {
00231 _putc_compress( magic_byte, fout );
00232 _putc_compress( _runchar, fout );
00233 _putc_compress( (unsigned char)((_runlen>>8)|0x80), fout );
00234 _putc_compress( (unsigned char)(_runlen & 0xFF), fout );
00235 }
00236 else if(_runlen>2 || _runchar==magic_byte)
00237
00238
00239 {
00240 _putc_compress( magic_byte, fout );
00241 _putc_compress( _runchar, fout );
00242 _putc_compress( (unsigned char)_runlen, fout );
00243 }
00244 else if(_runlen==2)
00245 {
00246 _putc_compress( _runchar, fout );
00247 _putc_compress( _runchar, fout );
00248 }
00249 else if(_runlen==1)
00250 {
00251 _putc_compress( _runchar, fout );
00252 }
00253
00254 _runlen = 0;
00255 _runchar = 0;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265 void frleputc(unsigned char c, FILE *fout)
00266 {
00267 if( _runlen == 0 )
00268 {
00269 _runlen=1;
00270 _runchar=c;
00271 return;
00272 }
00273
00274 if( _runlen >= 0x7FFF || c != _runchar )
00275 {
00276 frleflush(fout);
00277 _runchar = c;
00278 _runlen = 1;
00279 } else
00280 _runlen++;
00281 }
00282
00283
00284
00285
00286
00287
00288 unsigned char rlegetc(void)
00289 {
00290 unsigned char in;
00291
00292 if( !_runlen ) {
00293 in = _rleread();
00294
00295 if(in!=magic_byte)
00296 return in;
00297
00298 _runchar = _rleread();
00299 _runlen = _rleread();
00300 if(_runlen & 0x80) {
00301 _runlen &= ~0x80;
00302 _runlen <<= 8;
00303 _runlen |= _rleread();
00304 }
00305 }
00306 _runlen--;
00307 return _runchar;
00308 }
00309
00310
00311
00312 void rle_set_source(rle_source_type t, const void *s)
00313 {
00314 _rlepos = s;
00315
00316 switch(t)
00317 {
00318 case rle_huffman:
00319 _rleread = _rleread_huffman;
00320 break;
00321 case rle_file:
00322 _rleread = _rleread_file;
00323 break;
00324 case rle_pointer:
00325 _rleread = _rleread_ptr;
00326 break;
00327 }
00328 }
00329
00330
00331 static unsigned char _rleread_huffman(void)
00332 {
00333 return fhuffmangetc( (FILE*)_rlepos );
00334 }
00335
00336
00337 static unsigned char _rleread_file(void)
00338 {
00339 return fgetc( (FILE*)_rlepos );
00340 }
00341
00342
00343 static unsigned char _rleread_ptr(void)
00344 {
00345 return *( ((const unsigned char*)_rlepos) ++);
00346 }
00347
00348