00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "MiniDeflate.h"
00019
00020
00021
00022 #define EMPTY_KEY 123
00023 #define uchar unsigned char
00024
00025 #ifndef min
00026 #define min(a,b) (((a)<(b))?(a):(b))
00027 #endif
00028
00029 MiniDeflate::MiniDeflate()
00030 {
00031 buffer = new uchar [BUFFER_SIZE + 5];
00032 hash_keys = new uchar [HASH_SIZE];
00033 hash_values = new uchar * [HASH_SIZE * HASH_DEPTH];
00034 }
00035
00036 MiniDeflate::~MiniDeflate()
00037 {
00038 delete [] buffer;
00039 delete [] hash_keys;
00040 delete [] hash_values;
00041 }
00042
00043 void MiniDeflate::EvaluateMatch(unsigned char * in, int len, int hash,
00044 unsigned char * & best_pos, int & best_match)
00045 {
00046 int max = min(len, 0xFFFF + 66);
00047
00048 for (int i = HASH_DEPTH; i > 0; i--)
00049
00050 {
00051 uchar * pos = hash_values[hash * HASH_DEPTH + ((hash_keys[hash] + i) % HASH_DEPTH)];
00052
00053 if (pos == NULL || in - pos >= 0x4001) break;
00054
00055 int match = 0;
00056
00057 while (match < max && pos[match] == in[match])
00058 match++;
00059
00060 if (match > best_match)
00061 {
00062 best_match = match;
00063 best_pos = pos;
00064 }
00065 }
00066
00067
00068 if (best_match < OKAY_MATCH)
00069 {
00070 int delta = hash_keys[hash] = (uchar)((hash_keys[hash] + 1) & 7);
00071 hash_values[hash * 8 + delta] = in;
00072 }
00073 }
00074
00075 void MiniDeflate::QuoteLiterals(unsigned char * & in, int literal,
00076 unsigned char * & out, int & buffer_len,
00077 FILE * output)
00078 {
00079 if (buffer_len < 0)
00080 {
00081 fwrite(buffer, out - buffer, 1, output);
00082 buffer_len = BUFFER_SIZE;
00083 out = buffer;
00084 }
00085
00086 while (buffer_len < literal)
00087 {
00088 literal -= buffer_len;
00089 while (buffer_len--)
00090 {
00091 *out = *in;
00092 in++;
00093 out++;
00094 }
00095 fwrite(buffer, BUFFER_SIZE, 1, output);
00096 buffer_len = BUFFER_SIZE;
00097 out = buffer;
00098 }
00099
00100 while (literal--)
00101 {
00102 *out = *in;
00103 in++;
00104 out++;
00105 buffer_len--;
00106 }
00107 }
00108
00109 void MiniDeflate::OutputLiterals(unsigned char * & in, int literal,
00110 unsigned char * & out, int & buffer_len,
00111 FILE * output)
00112 {
00113 while (literal > 0)
00114 if (literal < 16)
00115 {
00116 *out = (char) literal;
00117 out++;
00118 buffer_len--;
00119 QuoteLiterals(in, literal, out, buffer_len, output);
00120 break;
00121 }
00122 else if (literal < 31)
00123 {
00124 *out = 15;
00125 out++;
00126 buffer_len--;
00127 QuoteLiterals(in, 15, out, buffer_len, output);
00128 *out = (uchar)(literal - 15);
00129 out++;
00130 buffer_len--;
00131 QuoteLiterals(in, literal - 15, out, buffer_len, output);
00132 break;
00133 }
00134 else
00135 {
00136 int length = min(literal, 0xFFFF + 31);
00137 literal -= length;
00138 length -= 31;
00139
00140 *out = 0;
00141 out++;
00142 *out = (uchar)(length >> 8);
00143 out++;
00144 *out = (uchar)(length & 0xFF);
00145 out++;
00146 buffer_len -= 3;
00147
00148 QuoteLiterals(in, length + 31, out, buffer_len, output);
00149 }
00150 }
00151
00152
00153 void MiniDeflate::Deflate(FILE * output, void * void_input, size_t len)
00154 {
00155 uchar * in = (uchar *) void_input;
00156 uchar * out = (uchar *) buffer;
00157 int buffer_len = BUFFER_SIZE;
00158
00159 for (int i = 0; i < HASH_SIZE; i++) hash_keys[i] = EMPTY_KEY;
00160
00161 uchar * in2 = in;
00162
00163 while (len > 2)
00164 {
00165
00166 int hash = ((in[0] << 16) | (in[1] << 8) | in[2]) % HASH_SIZE;
00167
00168 if (hash_keys[hash] != EMPTY_KEY)
00169
00170 {
00171 int best_match = 0;
00172 uchar * best_pos = NULL;
00173
00174 EvaluateMatch(in, len, hash, best_pos, best_match);
00175
00176
00177 if (best_match < 3)
00178 {
00179 in++;
00180 len--;
00181 continue;
00182 }
00183
00184
00185 while (best_match < OKAY_MATCH && len > 3)
00186 {
00187
00188 int next_hash = ((in[1] << 16) | (in[2] << 8) | in[3]) % HASH_SIZE;
00189
00190 if (hash_keys[next_hash] == EMPTY_KEY) break;
00191
00192 int next_match = 0;
00193 uchar * next_pos = NULL;
00194
00195 EvaluateMatch(in + 1, len - 1, next_hash, next_pos, next_match);
00196
00197
00198 if (next_match <= best_match + 1) break;
00199
00200
00201 in++;
00202 len--;
00203 best_match = next_match;
00204 best_pos = next_pos;
00205 }
00206
00207 int best_offset = in - best_pos - 1;
00208
00209
00210
00211 OutputLiterals(in2, in - in2, out, buffer_len, output);
00212
00213 in2 = in += best_match;
00214 len -= best_match;
00215
00216 if (best_match < 17 && best_offset < 0x1000)
00217 {
00218 *out = (uchar)(((best_match - 1) << 4) | (best_offset >> 8));
00219 out++;
00220 *out = (uchar)(best_offset & 0xFF);
00221 out++;
00222 buffer_len -= 2;
00223 }
00224 else if (best_match < 66)
00225 {
00226 *out = (uchar)(16 | (best_offset >> 10));
00227 out++;
00228 *out = (uchar)((best_offset >> 2) & 0xFF);
00229 out++;
00230 *out = (uchar)((best_offset << 6) | (best_match - 2));
00231 out++;
00232 buffer_len -= 3;
00233 }
00234 else
00235 {
00236 *out = (uchar)(16 | (best_offset >> 10));
00237 out++;
00238 *out = (uchar)((best_offset >> 2) & 0xFF);
00239 out++;
00240 *out = (uchar)(best_offset << 6);
00241 out++;
00242 best_match -= 66;
00243 *out = (uchar)(best_match >> 8);
00244 out++;
00245 *out = (uchar)(best_match & 0xFF);
00246 out++;
00247 buffer_len -= 5;
00248 }
00249
00250 if (buffer_len <= 0)
00251 {
00252 fwrite(buffer, out - buffer, 1, output);
00253 buffer_len = BUFFER_SIZE;
00254 out = buffer;
00255 }
00256 }
00257
00258 else
00259 {
00260 hash_keys[hash] = 0;
00261 for (int i = 1; i < HASH_DEPTH; i++) hash_values[hash * 8 + i] = NULL;
00262 hash_values[hash * 8] = in;
00263 in++;
00264 len--;
00265 }
00266 }
00267
00268
00269 in += len;
00270 OutputLiterals(in2, in - in2, out, buffer_len, output);
00271
00272
00273 if (out != buffer) fwrite(buffer, out - buffer, 1, output);
00274 }
00275
00276 void MiniDeflate::CiteLiteral(unsigned char * & out, int literal,
00277 unsigned char * & in, int & buffer_len,
00278 FILE * input)
00279 {
00280 while (buffer_len < literal)
00281 {
00282 literal -= buffer_len;
00283 while (buffer_len--)
00284 {
00285 *out = *in;
00286 in++;
00287 out++;
00288 }
00289 buffer_len = fread(buffer + 5, 1, BUFFER_SIZE, input);
00290 in = buffer + 5;
00291 }
00292
00293 while (literal--)
00294 {
00295 *out = *in;
00296 in++;
00297 out++;
00298 buffer_len--;
00299 }
00300 }
00301
00302
00303 void MiniDeflate::Inflate(FILE * input, void * void_output, size_t len)
00304 {
00305 uchar * out = (uchar *) void_output;
00306 uchar * in = (uchar *) buffer + 5;
00307 int buffer_len = BUFFER_SIZE;
00308
00309 buffer_len = fread(buffer + 5, 1, BUFFER_SIZE, input);
00310
00311 while (len)
00312 {
00313 int match_len = *in >> 4;
00314
00315
00316 if (match_len == 0)
00317 {
00318 match_len = *in & 0x0F;
00319 in++, buffer_len--;
00320
00321
00322
00323 if (match_len == 0)
00324 {
00325 match_len = (in[0] << 8) + in[1] + 31;
00326 in += 2;
00327 buffer_len -= 2;
00328 }
00329
00330 CiteLiteral(out, match_len, in, buffer_len, input);
00331 len -= match_len;
00332 }
00333
00334 else if (match_len == 1)
00335 {
00336 int offset = (((in[0] & 0x0F) << 10) | (in[1] << 2) | (in[2] >> 6)) + 1;
00337 match_len = (in[2] & 0x3F) + 2;
00338 in += 3;
00339 buffer_len -= 3;
00340
00341 if (match_len == 2)
00342 {
00343 match_len = ((in[0] << 8) | in[1]) + 66;
00344 in += 2;
00345 buffer_len -= 2;
00346 }
00347
00348 uchar * match_pos = out - offset;
00349 len -= match_len;
00350 while (match_len--)
00351 {
00352 *out = *match_pos;
00353 out++, match_pos++;
00354 }
00355 }
00356
00357 else
00358 {
00359 int offset = (((in[0] & 0x0F) << 8) | in[1]) + 1;
00360 in += 2;
00361 buffer_len -= 2;
00362
00363 uchar * match_pos = out - offset;
00364 len -= ++match_len;
00365 while (match_len--)
00366 {
00367 *out = *match_pos;
00368 out++, match_pos++;
00369 }
00370 }
00371
00372 if (buffer_len < 5)
00373 {
00374 uchar * in2 = (uchar *) buffer + 5 - buffer_len;
00375 while (in2 != buffer + 5)
00376 {
00377 *in2 = *in;
00378 in2++;
00379 in++;
00380 }
00381
00382 in = buffer + 5 - buffer_len;
00383 buffer_len += fread(buffer + 5, 1, BUFFER_SIZE, input);
00384 }
00385 }
00386
00387 if (buffer_len) fseek(input, -buffer_len, SEEK_CUR);
00388 }
00389
00390
00391