1 module kafkad.utils.snappy; 2 3 import std.bitmanip; 4 5 nothrow extern(C): 6 7 enum { 8 SNAPPY_OK = 0, 9 SNAPPY_INVALID_INPUT = 1, 10 SNAPPY_BUFFER_TOO_SMALL = 2 11 } 12 13 int snappy_compress(const ubyte* input, 14 size_t input_length, 15 ubyte* compressed, 16 size_t* compressed_length); 17 18 int snappy_uncompress(const ubyte* compressed, 19 size_t compressed_length, 20 ubyte* uncompressed, 21 size_t* uncompressed_length); 22 23 int snappy_uncompressed_length(const ubyte* compressed, 24 size_t compressed_length, 25 size_t* result); 26 27 int snappy_java_uncompress(const ubyte* compressed, 28 size_t compressed_length, 29 ubyte* uncompressed, 30 size_t* uncompressed_length) 31 { 32 // Snappy-Java adds its own framing: Header [ChunkLen Chunk] 33 // Header = Magic (8 bytes) Version (4 bytes) Compatible (4 bytes) 34 enum headerLen = 8 + 4 + 4; 35 if (compressed_length < headerLen + 4) // header + chunk length 36 return SNAPPY_INVALID_INPUT; 37 // check magic value 38 enum ubyte[8] magic = [0x82, 'S', 'N', 'A', 'P', 'P', 'Y', 0]; 39 ubyte* p = cast(ubyte*)compressed; 40 auto cmagic = cast(ubyte[8]*)p; 41 if (*cmagic != magic) 42 return SNAPPY_INVALID_INPUT; 43 p += headerLen; 44 compressed_length -= headerLen; 45 if (!compressed_length) 46 return SNAPPY_INVALID_INPUT; 47 size_t wholeUncompressedLen = 0, chunkCount = 0; 48 while (compressed_length) { 49 if (compressed_length < 4) 50 return SNAPPY_INVALID_INPUT; 51 auto chunkLen = bigEndianToNative!uint(p[0 .. 4]); 52 if (!chunkLen) 53 return SNAPPY_INVALID_INPUT; 54 p += 4; 55 compressed_length -= 4; 56 if (chunkLen > compressed_length) 57 return SNAPPY_INVALID_INPUT; 58 size_t chunkUncompressedLen; 59 if (snappy_uncompressed_length(p, chunkLen, &chunkUncompressedLen) != SNAPPY_OK || !chunkUncompressedLen) 60 return SNAPPY_INVALID_INPUT; 61 wholeUncompressedLen += chunkUncompressedLen; 62 p += chunkLen; 63 compressed_length -= chunkLen; 64 ++chunkCount; 65 } 66 if (wholeUncompressedLen > *uncompressed_length) 67 return SNAPPY_BUFFER_TOO_SMALL; 68 p = cast(ubyte*)compressed + headerLen; 69 while (chunkCount--) { 70 auto chunkLen = bigEndianToNative!uint(p[0 .. 4]); 71 p += 4; 72 size_t rem = *uncompressed_length; 73 if (snappy_uncompress(p, chunkLen, uncompressed, &rem) != SNAPPY_OK) 74 return SNAPPY_INVALID_INPUT; 75 p += chunkLen; 76 uncompressed += rem; 77 *uncompressed_length -= rem; 78 } 79 *uncompressed_length = wholeUncompressedLen; 80 return SNAPPY_OK; 81 }