Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
pithy.c
00001 // 00002 // pithy.c 00003 // http://github.com/johnezang/pithy 00004 // Licensed under the terms of the BSD License, as specified below. 00005 // 00006 00007 /* 00008 Copyright (c) 2011, John Engelhart 00009 00010 All rights reserved. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 00015 * Redistributions of source code must retain the above copyright 00016 notice, this list of conditions and the following disclaimer. 00017 00018 * Redistributions in binary form must reproduce the above copyright 00019 notice, this list of conditions and the following disclaimer in the 00020 documentation and/or other materials provided with the distribution. 00021 00022 * Neither the name of the Zang Industries nor the names of its 00023 contributors may be used to endorse or promote products derived from 00024 this software without specific prior written permission. 00025 00026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00027 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00028 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00029 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00030 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00031 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00032 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00033 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00034 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00035 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00036 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00037 */ 00038 00039 #include <stdio.h> 00040 #include <stdint.h> 00041 #include <stdlib.h> 00042 #include <string.h> 00043 00044 #if defined(__arm__) && defined(__ARM_NEON__) 00045 #include <arm_neon.h> 00046 #endif 00047 00048 #include "pithy.h" 00049 00050 #define kBlockLog 20ul 00051 #define kBlockSize ((size_t)(1 << kBlockLog)) 00052 00053 // The maximum size that can be compressed while still allowing for the worst case compression expansion. 00054 #define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes. 00055 00056 typedef const char *pithy_hashOffset_t; 00057 00058 enum { 00059 PITHY_LITERAL = 0, 00060 PITHY_COPY_1_BYTE_OFFSET = 1, 00061 PITHY_COPY_2_BYTE_OFFSET = 2, 00062 PITHY_COPY_3_BYTE_OFFSET = 3 00063 }; 00064 00065 00066 #if defined (__GNUC__) && (__GNUC__ >= 3) 00067 #define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__)) 00068 #define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect)) 00069 #define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u) 00070 #define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u) 00071 #define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr) 00072 #else // defined (__GNUC__) && (__GNUC__ >= 3) 00073 #define PITHY_ATTRIBUTES(attr, ...) 00074 #define PITHY_EXPECTED(cond, expect) (cond) 00075 #define PITHY_EXPECT_T(cond) (cond) 00076 #define PITHY_EXPECT_F(cond) (cond) 00077 #define PITHY_PREFETCH(ptr) 00078 #endif // defined (__GNUC__) && (__GNUC__ >= 3) 00079 00080 #define PITHY_STATIC_INLINE static inline PITHY_ATTRIBUTES(always_inline) 00081 #define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x)) 00082 00083 #if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG) 00084 #define NDEBUG 00085 #endif 00086 00087 #ifdef NDEBUG 00088 #define DCHECK(condition) 00089 #else 00090 #define DCHECK(condition) do { \ 00091 if(PITHY_EXPECT_F(!(condition))) { \ 00092 fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", \ 00093 __FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \ 00094 abort(); \ 00095 } \ 00096 } while(0) 00097 #endif 00098 00099 PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT); 00100 PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v); 00101 00102 PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset); 00103 PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift); 00104 PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit); 00105 PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path); 00106 PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len); 00107 PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len); 00108 PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len); 00109 00110 PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); } 00111 PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); } 00112 PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); } 00113 PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); } 00114 PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); } 00115 PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); } 00116 00117 #define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src)); 00118 #define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul); 00119 00120 #ifdef __BIG_ENDIAN__ 00121 00122 #ifdef _MSC_VER 00123 #include <stdlib.h> 00124 #define pithy_bswap_16(x) _byteswap_ushort(x) 00125 #define pithy_bswap_32(x) _byteswap_ulong(x) 00126 #define pithy_bswap_64(x) _byteswap_uint64(x) 00127 00128 #elif defined(__APPLE__) 00129 00130 // Mac OS X / Darwin features 00131 #include <libkern/OSByteOrder.h> 00132 #define pithy_bswap_16(x) OSSwapInt16(x) 00133 #define pithy_bswap_32(x) OSSwapInt32(x) 00134 #define pithy_bswap_64(x) OSSwapInt64(x) 00135 #else 00136 #include <byteswap.h> 00137 #endif 00138 00139 #endif // __BIG_ENDIAN__ 00140 00141 // Conversion functions. 00142 #ifdef __BIG_ENDIAN__ 00143 #define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x)) 00144 #define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x)) 00145 #define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x)) 00146 #define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x)) 00147 #define pithy_IsLittleEndian() (0) 00148 00149 #else // !defined(__BIG_ENDIAN__) 00150 #define pithy_FromHost16(x) ((uint16_t)(x)) 00151 #define pithy_ToHost16(x) ((uint16_t)(x)) 00152 #define pithy_FromHost32(x) ((uint32_t)(x)) 00153 #define pithy_ToHost32(x) ((uint32_t)(x)) 00154 #define pithy_IsLittleEndian() (1) 00155 00156 #endif // !defined(__BIG_ENDIAN__) 00157 00158 #define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p))) 00159 #define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v)) 00160 #define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p))) 00161 #define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v)) 00162 00163 PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v) 00164 { 00165 *p++ = (v & 0xffu); 00166 *p++ = ((v >> 8) & 0xffu); 00167 *p++ = ((v >> 16) & 0xffu); 00168 } 00169 00170 #if defined (__GNUC__) && (__GNUC__ >= 3) 00171 00172 #define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));}) 00173 #define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n))) 00174 #define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n))) 00175 #define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n))) 00176 #define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n))) 00177 00178 #else // Portable versions, !GNUC || GNUC < 3 00179 00180 PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n) 00181 { 00182 if (n == 0u) { 00183 return (-1); 00184 } 00185 int i = 0, log = 0; 00186 uint32_t value = n; 00187 for (i = 4; i >= 0; --i) { 00188 int shift = (1 << i); 00189 uint32_t x = value >> shift; 00190 if (x != 0u) { 00191 value = x; 00192 log += shift; 00193 } 00194 } 00195 DCHECK(value == 1); 00196 return (log); 00197 } 00198 00199 PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n) 00200 { 00201 int i = 0, rc = 31, shift = 0; 00202 for (i = 4, shift = 1 << 4; i >= 0; --i) { 00203 const uint32_t x = n << shift; 00204 if (x != 0u) { 00205 n = x; 00206 rc -= shift; 00207 } 00208 shift >>= 1; 00209 } 00210 return (rc); 00211 } 00212 00213 PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n) 00214 { 00215 const uint32_t bottomBits = n; 00216 if (bottomBits == 0u) { 00217 return (32 + pithy_FindLSBSetNonZero32((n >> 32))); 00218 } else { 00219 return (pithy_FindLSBSetNonZero32(bottomBits)); 00220 } 00221 } 00222 00223 PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n) 00224 { 00225 int i; 00226 uint32_t x, rc = 32, shift = 1 << 4; 00227 for (i = 3; i >= 0; --i) { 00228 x = n >> shift; 00229 if (x != 0) { 00230 rc -= shift; 00231 n = x; 00232 } 00233 shift >>= 1; 00234 } 00235 x = n >> shift; 00236 return (rc - ((x != 0) ? 2 : n)); 00237 } 00238 00239 PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n) 00240 { 00241 const uint32_t upperBits = n >> 32; 00242 if (upperBits == 0u) { 00243 return (32 + pithy_FindMSBSetNonZero32((n))); 00244 } else { 00245 return (pithy_FindMSBSetNonZero32(upperBits)); 00246 } 00247 } 00248 00249 #endif // End portable versions. 00250 00251 PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut) 00252 { 00253 const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l; 00254 size_t resultShift = 0ul, result = 0ul; 00255 uint32_t encodedByte = 0u; 00256 00257 for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) { 00258 if (ptr >= limit) { 00259 return (NULL); 00260 } 00261 encodedByte = *(ptr++); 00262 result |= (encodedByte & 127u) << resultShift; 00263 if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) { 00264 goto done; 00265 } 00266 } 00267 return (NULL); 00268 done: 00269 *resultOut = result; 00270 return ((const char *)ptr); 00271 } 00272 00273 PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v) 00274 { 00275 unsigned char *ptr = (unsigned char *)sptr; 00276 if (v < (1u << 7)) { 00277 *(ptr++) = v; 00278 } else if (v < (1u << 14)) { 00279 *(ptr++) = v | 0x80u; 00280 *(ptr++) = (v >> 7); 00281 } else if (v < (1u << 21)) { 00282 *(ptr++) = v | 0x80u; 00283 *(ptr++) = (v >> 7) | 0x80u; 00284 *(ptr++) = (v >> 14); 00285 } else if (v < (1u << 28)) { 00286 *(ptr++) = v | 0x80u; 00287 *(ptr++) = (v >> 7) | 0x80u; 00288 *(ptr++) = (v >> 14) | 0x80u; 00289 *(ptr++) = (v >> 21); 00290 } else { 00291 *(ptr++) = v | 0x80u; 00292 *(ptr++) = (v >> 7) | 0x80u; 00293 *(ptr++) = (v >> 14) | 0x80u; 00294 *(ptr++) = (v >> 21) | 0x80u; 00295 *(ptr++) = (v >> 28); 00296 } 00297 return ((char *)ptr); 00298 } 00299 00300 00301 PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset) 00302 { 00303 DCHECK(offset <= 4); 00304 return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset)))); 00305 } 00306 00307 00308 PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift) 00309 { 00310 uint32_t kMul = 0x1e35a7bdU; 00311 return ((bytes * kMul) >> shift); 00312 } 00313 00314 00315 PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit) 00316 { 00317 DCHECK(s2_limit >= s2); 00318 const char *ms1 = s1, *ms2 = s2; 00319 00320 #if defined(__LP64__) 00321 while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) { 00322 uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2); 00323 if (PITHY_EXPECT_F(x == 0ul)) { 00324 ms1 += 8ul; 00325 ms2 += 8ul; 00326 } else { 00327 return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) : 00328 (pithy_FindMSBSetNonZero64(x) >> 3)))); 00329 } 00330 } 00331 #else 00332 while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) { 00333 uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2); 00334 if (PITHY_EXPECT_F(x == 0u)) { 00335 ms1 += 4u; 00336 ms2 += 4u; 00337 } else { 00338 return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? 00339 (pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3)))); 00340 } 00341 } 00342 #endif 00343 while (PITHY_EXPECT_T(ms2 < s2_limit)) { 00344 if (PITHY_EXPECT_T(*ms1 == *ms2)) { 00345 ms1++; 00346 ms2++; 00347 } else { 00348 return (ms1 - s1); 00349 } 00350 } 00351 return (ms1 - s1); 00352 } 00353 00354 00355 PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path) 00356 { 00357 int n = len - 1l; 00358 if (PITHY_EXPECT_T(n < 60l)) { 00359 *op++ = PITHY_LITERAL | (n << 2); 00360 if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) { 00361 pithy_Move128(op, literal); 00362 return (op + len); 00363 } 00364 } else { 00365 char *base = op; 00366 int count = 0; 00367 op++; 00368 while (n > 0l) { 00369 *op++ = n & 0xff; 00370 n >>= 8; 00371 count++; 00372 } 00373 DCHECK((count >= 1) && (count <= 4)); 00374 *base = PITHY_LITERAL | ((59 + count) << 2); 00375 } 00376 memcpy(op, literal, len); 00377 return (op + len); 00378 } 00379 00380 PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len) 00381 { 00382 DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize)); 00383 if (PITHY_EXPECT_T(offset < 65536ul)) { 00384 if (PITHY_EXPECT_T(len < (256ul + 63ul))) { 00385 *op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2); 00386 pithy_StoreHost16(op, offset); 00387 op += 2ul; 00388 *op++ = (len - 63ul); 00389 } else { 00390 *op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2); 00391 pithy_StoreHost16(op, offset); 00392 op += 2ul; 00393 pithy_StoreHost16(op, len); 00394 op += 2ul; 00395 } 00396 } else { 00397 if (PITHY_EXPECT_T(len < (256ul + 63ul))) { 00398 *op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2); 00399 pithy_StoreHost24(op, offset); 00400 op += 3ul; 00401 *op++ = (len - 63ul); 00402 } else { 00403 *op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2); 00404 pithy_StoreHost24(op, offset); 00405 op += 3ul; 00406 pithy_StoreHost16(op, len); 00407 op += 2ul; 00408 } 00409 } 00410 return (op); 00411 } 00412 00413 PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len) 00414 { 00415 DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize)); 00416 if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) { 00417 int lenMinus4 = len - 4l; 00418 DCHECK(lenMinus4 < 8l); 00419 *op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5); 00420 *op++ = offset & 0xff; 00421 } else { 00422 if (PITHY_EXPECT_T(offset < 65536ul)) { 00423 *op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2); 00424 pithy_StoreHost16(op, offset); 00425 op += 2ul; 00426 } else { 00427 *op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2); 00428 pithy_StoreHost24(op, offset); 00429 op += 3ul; 00430 } 00431 } 00432 return (op); 00433 } 00434 00435 PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len) 00436 { 00437 while (PITHY_EXPECT_F(len >= 63ul)) { 00438 op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len); 00439 len -= (len >= 65539ul) ? 65535ul : len; 00440 } 00441 DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1); 00442 if ( PITHY_EXPECT_T(len > 0ul)) { 00443 op = pithy_EmitCopyLessThan63(op, offset, len); 00444 len -= len; 00445 } 00446 return (op); 00447 } 00448 00449 size_t pithy_MaxCompressedLength(size_t inputLength) 00450 { 00451 return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul)); 00452 } 00453 00454 size_t pithy_Compress(const char *uncompressed, 00455 size_t uncompressedLength, 00456 char *compressedOut, 00457 size_t compressedOutLength, 00458 int compressionLevel) 00459 { 00460 00461 if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) || 00462 (uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) || 00463 (uncompressedLength == 0ul)) { 00464 return (0ul); 00465 } 00466 00467 char *compressedPtr = compressedOut; 00468 00469 size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 : 00470 (compressionLevel > 9) ? 9 : compressionLevel) / 2ul)); 00471 while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) { 00472 hashTableSize <<= 1; 00473 } 00474 pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable; 00475 if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) { 00476 if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) { 00477 return (0ul); 00478 } 00479 hashTable = heapHashTable; 00480 } 00481 size_t x = 0ul; 00482 for (x = 0ul; x < hashTableSize; x++) { 00483 hashTable[x] = uncompressed; 00484 } 00485 00486 #ifndef NDEBUG 00487 char *const compressedOutEnd = compressedOut + compressedOutLength; 00488 #endif 00489 compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength); 00490 DCHECK(compressedPtr <= compressedOutEnd); 00491 { 00492 const char *uncompressedPtr = uncompressed; 00493 const char *uncompressedEnd = uncompressed + uncompressedLength; 00494 const char *nextEmitUncompressedPtr = uncompressedPtr; 00495 DCHECK((hashTableSize & (hashTableSize - 1l)) == 0); 00496 const int shift = 32 - pithy_Log2Floor(hashTableSize); 00497 DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l)); 00498 size_t skip = 32ul; 00499 00500 if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) { 00501 const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul; 00502 uint32_t uncompressedBytes; 00503 uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr); 00504 uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); 00505 00506 while (1) { 00507 DCHECK(nextEmitUncompressedPtr < uncompressedPtr); 00508 const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL; 00509 00510 skip = (((skip - 32ul) * 184ul) >> 8) + 32ul; 00511 00512 do { 00513 uncompressedPtr = nextUncompressedPtr; 00514 uncompressedBytes = nextUncompressedBytes; 00515 uint32_t uncompressedBytesHash = nextUncompressedBytesHash; 00516 DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift)); 00517 size_t skipBytesBetweenHashLookups = skip >> 5; 00518 skip += ((skip * 7ul) >> 11) + 1ul; 00519 nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups; 00520 if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) { 00521 goto emit_remainder; 00522 } 00523 nextUncompressedBytes = pithy_Load32(nextUncompressedPtr); 00524 nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); 00525 matchCandidatePtr = hashTable[uncompressedBytesHash]; 00526 DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); 00527 hashTable[uncompressedBytesHash] = uncompressedPtr; 00528 } while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) || 00529 PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((int)(kBlockSize - 2ul)))); 00530 00531 DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd); 00532 compressedPtr = pithy_EmitLiteral(compressedPtr, 00533 nextEmitUncompressedPtr, 00534 uncompressedPtr - nextEmitUncompressedPtr, 00535 1); 00536 DCHECK(compressedPtr <= compressedOutEnd); 00537 uint64_t uncompressedBytes64 = 0ul; 00538 00539 do { 00540 if (compressionLevel > 2) { 00541 DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd); 00542 uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr + 1ul); 00543 hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = 00544 uncompressedPtr + 1ul; 00545 if (compressionLevel > 4) { 00546 hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = 00547 uncompressedPtr + 2ul; 00548 } 00549 } 00550 00551 DCHECK((matchCandidatePtr >= uncompressed) && 00552 (matchCandidatePtr <= uncompressedPtr) && 00553 ((matchCandidatePtr + 4ul) <= uncompressedEnd) && 00554 ((uncompressedPtr + 4ul) <= uncompressedEnd)); 00555 00556 size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul, 00557 uncompressedPtr + 4ul, 00558 uncompressedEnd); 00559 DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) && 00560 ((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd)); 00561 DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength)); 00562 compressedPtr = pithy_EmitCopy(compressedPtr, 00563 uncompressedPtr - matchCandidatePtr, 00564 matchCandidateLength); 00565 DCHECK(compressedPtr <= compressedOutEnd); 00566 uncompressedPtr += matchCandidateLength; 00567 DCHECK(uncompressedPtr <= uncompressedEnd); 00568 nextEmitUncompressedPtr = uncompressedPtr; 00569 if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) { 00570 goto emit_remainder; 00571 } 00572 00573 DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd)); 00574 00575 uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr - 3ul); 00576 00577 if (compressionLevel > 0) { 00578 if (compressionLevel > 8) { 00579 hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = 00580 uncompressedPtr - 3ul; 00581 } 00582 if (compressionLevel > 6) { 00583 hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = 00584 uncompressedPtr - 2ul; 00585 } 00586 hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] = 00587 uncompressedPtr - 1ul; 00588 } 00589 00590 uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u); 00591 uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift); 00592 matchCandidatePtr = hashTable[uncompressedBytesHash]; 00593 DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); 00594 hashTable[uncompressedBytesHash] = uncompressedPtr; 00595 } while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) && 00596 PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((int)(kBlockSize - 2ul)))); 00597 00598 nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u); 00599 nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); 00600 uncompressedPtr++; 00601 } 00602 } 00603 00604 emit_remainder: 00605 if (nextEmitUncompressedPtr < uncompressedEnd) { 00606 compressedPtr = pithy_EmitLiteral(compressedPtr, 00607 nextEmitUncompressedPtr, 00608 uncompressedEnd - nextEmitUncompressedPtr, 00609 0); 00610 } 00611 } 00612 00613 pithy_Store32(compressedPtr, 0); 00614 compressedPtr += 4; 00615 00616 DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength); 00617 if (heapHashTable != NULL) { 00618 free(heapHashTable); 00619 heapHashTable = NULL; 00620 hashTable = NULL; 00621 } 00622 return (compressedPtr - compressedOut); 00623 } 00624 00625 00626 static const uint32_t pithy_wordmask[] = { 00627 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu 00628 }; 00629 00630 00631 static const uint16_t pithy_charTable[256] = { 00632 0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802, 00633 0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804, 00634 0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806, 00635 0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808, 00636 0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a, 00637 0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c, 00638 0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e, 00639 0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810, 00640 0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812, 00641 0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814, 00642 0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816, 00643 0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818, 00644 0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a, 00645 0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c, 00646 0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e, 00647 0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820, 00648 0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822, 00649 0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824, 00650 0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826, 00651 0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828, 00652 0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a, 00653 0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c, 00654 0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e, 00655 0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830, 00656 0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832, 00657 0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834, 00658 0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836, 00659 0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838, 00660 0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a, 00661 0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c, 00662 0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e, 00663 0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840 00664 }; 00665 00666 00667 int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult) 00668 { 00669 const char *compressedEnd = compressed + compressedLength; 00670 size_t decompressedLength = 0ul; 00671 if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) { 00672 *decompressedOutLengthResult = decompressedLength; 00673 return (1); 00674 } else { 00675 return (0); 00676 } 00677 } 00678 00679 00680 int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, 00681 size_t decompressedOutLength) 00682 { 00683 const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength); 00684 size_t parsedDecompressedLength = 0ul; 00685 if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) || 00686 (parsedDecompressedLength > decompressedOutLength)) { 00687 return (0); 00688 } 00689 00690 char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength; 00691 00692 while (1) { 00693 const char *compressedPtr = nextCompressedPtr; 00694 DCHECK(compressedPtr <= compressedEnd); 00695 if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) { 00696 break; 00697 } 00698 00699 const unsigned char c = *((const unsigned char *)(compressedPtr++)); 00700 const unsigned char cLowerBits = (c & 0x3u); 00701 const int spaceLeft = (decompressedEnd - decompressedPtr); 00702 00703 if ((cLowerBits == PITHY_LITERAL)) { 00704 size_t literalLength = (c >> 2) + 1; 00705 if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) && 00706 PITHY_EXPECT_T(spaceLeft >= 16l)) { 00707 pithy_Move128(decompressedPtr, compressedPtr); 00708 } else { 00709 if (PITHY_EXPECT_F(literalLength > 60)) { 00710 if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) { 00711 break; 00712 } 00713 size_t literalLengthBytes = literalLength - 60; 00714 literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1; 00715 compressedPtr += literalLengthBytes; 00716 } 00717 if (PITHY_EXPECT_F(spaceLeft < (int)literalLength) || 00718 PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) { 00719 break; 00720 } 00721 memcpy(decompressedPtr, compressedPtr, literalLength); 00722 } 00723 nextCompressedPtr = compressedPtr + literalLength; 00724 decompressedPtr += literalLength; 00725 } else { 00726 const uint32_t entry = pithy_charTable[c]; 00727 const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits]; 00728 size_t length = entry & 0xffu; 00729 const size_t copyOffset = ((entry & 0x700u) + trailer); 00730 00731 compressedPtr += cLowerBits; 00732 00733 DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul)); 00734 00735 if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((int)copyOffset - 1l))) { 00736 break; 00737 } 00738 if (PITHY_EXPECT_T(length <= 16ul) && 00739 PITHY_EXPECT_T(copyOffset >= 16ul) && 00740 PITHY_EXPECT_T(spaceLeft >= 16l)) { 00741 pithy_Move128(decompressedPtr, decompressedPtr - copyOffset); 00742 } else { 00743 if (PITHY_EXPECT_F(length >= 63ul)) { 00744 if (PITHY_EXPECT_T(length == 63ul)) { 00745 if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) { 00746 break; 00747 } 00748 length = (*((unsigned char *)compressedPtr++)) + 63ul; 00749 } else { 00750 if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) { 00751 break; 00752 } 00753 length = pithy_LoadHost16(compressedPtr); 00754 compressedPtr += 2ul; 00755 } 00756 } 00757 00758 char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr; 00759 int copyLength = (int)length; 00760 00761 if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) { 00762 if (PITHY_EXPECT_F(spaceLeft < copyLength)) { 00763 break; 00764 } 00765 memcpy(copyTo, copyFrom, copyLength); 00766 } else { 00767 if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) { 00768 while ((copyTo - copyFrom) < 16l) { 00769 pithy_Move128(copyTo, copyFrom); 00770 copyLength -= copyTo - copyFrom; 00771 copyTo += copyTo - copyFrom; 00772 } 00773 while (copyLength > 0l) { 00774 pithy_Move128(copyTo, copyFrom); 00775 copyFrom += 16l; 00776 copyTo += 16l; 00777 copyLength -= 16l; 00778 } 00779 } else { 00780 if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) { 00781 break; 00782 } 00783 do { 00784 *copyTo++ = *copyFrom++; 00785 } while (--copyLength > 0l); 00786 } 00787 } 00788 } 00789 nextCompressedPtr = compressedPtr; 00790 decompressedPtr += length; 00791 } 00792 } 00793 00794 return (decompressedPtr == decompressedEnd); 00795 }
Generated on Tue Aug 9 2022 00:37:17 by
1.7.2