LZ77-encode the data. Return value is error code. The input are raw bytes, the output is in the form of unsigned integers with codes representing for example literal bytes, or length/distance pairs. It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a sliding window (of windowsize) is used, and all past bytes in that window can be used as the "dictionary". A brute fo
| 1429 | this hash technique is one out of several ways to speed this up. |
| 1430 | */ |
| 1431 | static unsigned encodeLZ77(uivector* out, Hash* hash, |
| 1432 | const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, |
| 1433 | unsigned minmatch, unsigned nicematch, unsigned lazymatching) |
| 1434 | { |
| 1435 | unsigned pos, i, error = 0; |
| 1436 | /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ |
| 1437 | unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; |
| 1438 | unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; |
| 1439 | |
| 1440 | unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ |
| 1441 | unsigned numzeros = 0; |
| 1442 | |
| 1443 | unsigned offset; /*the offset represents the distance in LZ77 terminology*/ |
| 1444 | unsigned length; |
| 1445 | unsigned lazy = 0; |
| 1446 | unsigned lazylength = 0, lazyoffset = 0; |
| 1447 | unsigned hashval; |
| 1448 | unsigned current_offset, current_length; |
| 1449 | const unsigned char *lastptr, *foreptr, *backptr; |
| 1450 | unsigned hashpos, prevpos; |
| 1451 | |
| 1452 | if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ |
| 1453 | if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ |
| 1454 | |
| 1455 | if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; |
| 1456 | |
| 1457 | for(pos = inpos; pos < insize; pos++) |
| 1458 | { |
| 1459 | size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ |
| 1460 | unsigned chainlength = 0; |
| 1461 | |
| 1462 | hashval = getHash(in, insize, pos); |
| 1463 | updateHashChain(hash, wpos, hashval); |
| 1464 | |
| 1465 | if(usezeros && hashval == 0) |
| 1466 | { |
| 1467 | if (numzeros == 0) numzeros = countZeros(in, insize, pos); |
| 1468 | else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--; |
| 1469 | hash->zeros[wpos] = numzeros; |
| 1470 | } |
| 1471 | else |
| 1472 | { |
| 1473 | numzeros = 0; |
| 1474 | } |
| 1475 | |
| 1476 | /*the length and offset found for the current position*/ |
| 1477 | length = 0; |
| 1478 | offset = 0; |
| 1479 | |
| 1480 | prevpos = hash->head[hashval]; |
| 1481 | hashpos = hash->chain[prevpos]; |
| 1482 | |
| 1483 | lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; |
| 1484 | |
| 1485 | /*search for the longest string*/ |
| 1486 | for(;;) |
| 1487 | { |
| 1488 | /*stop when went completely around the circular buffer*/ |
no test coverage detected