1 module zstd.compress; 2 3 import zstd.c.zstd; 4 import zstd.common; 5 6 enum Level : int 7 { 8 base = 3, 9 mix = 1, 10 max = 22, 11 speed = 1, 12 size = 22, 13 } 14 15 ubyte[] compress(const(void)[] src, int level = Level.base) 16 { 17 auto destCap = ZSTD_compressBound(src.length); 18 auto destBuf = new ubyte[destCap]; 19 auto result = ZSTD_compress(destBuf.ptr, destCap, src.ptr, src.length, level); 20 if (ZSTD_isError(result)) { 21 destBuf = null; 22 throw new ZstdException(result); 23 } 24 25 return destBuf[0..result]; 26 } 27 28 class Compressor 29 { 30 private: 31 ZSTD_CStream* cstream; 32 ubyte[] buffer; 33 34 public: 35 @property @trusted static 36 { 37 size_t recommendedInSize() 38 { 39 return ZSTD_CStreamInSize(); 40 } 41 42 size_t recommendedOutSize() 43 { 44 return ZSTD_CStreamOutSize(); 45 } 46 } 47 48 this(int level = Level.base) 49 in 50 { 51 assert(Level.min <= level && level <= Level.max); 52 } 53 body 54 { 55 cstream = ZSTD_createCStream(); 56 buffer = new ubyte[](recommendedOutSize); 57 size_t result = ZSTD_initCStream(cstream, level); 58 if (ZSTD_isError(result)) 59 throw new ZstdException(result); 60 } 61 62 ~this() 63 { 64 closeStream(); 65 } 66 67 ubyte[] compress(const(void)[] src) 68 { 69 ubyte[] result; 70 ZSTD_inBuffer input = {src.ptr, src.length, 0}; 71 ZSTD_outBuffer output = {buffer.ptr, buffer.length, 0}; 72 73 while (input.pos < input.size) { 74 output.pos = 0; 75 size_t code = ZSTD_compressStream(cstream, &output, &input); 76 if (ZSTD_isError(code)) 77 throw new ZstdException(code); 78 result ~= buffer[0..output.pos]; 79 } 80 81 return result; 82 } 83 84 ubyte[] flush() 85 { 86 ZSTD_outBuffer output = {buffer.ptr, buffer.length, 0}; 87 88 size_t code = ZSTD_flushStream(cstream, &output); 89 if (ZSTD_isError(code)) 90 throw new ZstdException(code); 91 92 return buffer[0..output.pos]; 93 } 94 95 ubyte[] finish() 96 { 97 ZSTD_outBuffer output = {buffer.ptr, buffer.length, 0}; 98 99 size_t remainingToFlush = ZSTD_endStream(cstream, &output); 100 // TODO: Provide finish(ref size_t remainingToFlush) version? 101 if (remainingToFlush > 0) 102 throw new ZstdException("not fully flushed."); 103 closeStream(); 104 105 return buffer[0..output.pos]; 106 } 107 108 private: 109 void closeStream() 110 { 111 if (cstream) { 112 ZSTD_freeCStream(cstream); 113 cstream = null; 114 } 115 } 116 }