1 module zgrf.compression; 2 3 import lzma; 4 5 extern (C) private void* szAlloc(void* p, size_t size) 6 { 7 import core.stdc.stdlib : malloc; 8 9 return malloc(size); 10 } 11 12 extern (C) private void szFree(void* p, void* address) 13 { 14 import core.stdc.stdlib : free; 15 16 free(address); 17 } 18 19 private ISzAlloc szAllocLzma = {&szAlloc, &szFree}; 20 21 /** 22 * Uncompresses data. If the first byte of srcbuf is 0 then 23 * LZMA will be used to uncompress the data. Otherwise 24 * uses zlib. 25 * 26 * Params: 27 * srcbuf = The compressed data 28 * destlen = The uncompressed size 29 * 30 * Returns: 31 * The uncompressed data 32 */ 33 ubyte[] uncompress(const(ubyte)[] srcbuf, size_t destlen = 0u) 34 { 35 ubyte[] dst; 36 if (destlen == 0) 37 { 38 destlen = srcbuf.length * 2 + 1; 39 } 40 41 if (srcbuf[0] == 0) 42 { 43 if (srcbuf.length < LZMA_PROPS_SIZE + 1) 44 { 45 return dst; 46 } 47 ELzmaStatus status; 48 SizeT destlen2 = destlen; 49 SizeT pack_size = srcbuf.length - LZMA_PROPS_SIZE - 1; 50 dst = new ubyte[destlen]; 51 int ret = LzmaDecode( 52 dst.ptr, 53 &destlen2, 54 cast(const(Byte*))(&srcbuf[LZMA_PROPS_SIZE + 1]), 55 &pack_size, 56 cast(const(Byte*))(&srcbuf[1]), 57 LZMA_PROPS_SIZE, 58 ELzmaFinishMode.LZMA_FINISH_END, 59 &status, 60 &szAllocLzma 61 ); 62 if (ret != SZ_OK) 63 { 64 } 65 } 66 else 67 { 68 dst = cast(ubyte[]) zlib_uncompress(srcbuf, destlen); 69 } 70 return dst; 71 } 72 73 // Taken directly from std/zlib.d 74 // This implementation does not treat Z_BUF_ERROR as an error that should be thrown 75 private void[] zlib_uncompress(const(void)[] srcbuf, size_t destlen = 0u, int winbits = 15) 76 { 77 import etc.c.zlib; 78 import std.zlib : ZlibException; 79 import std.conv : to; 80 int err; 81 ubyte[] destbuf; 82 83 if (!destlen) 84 destlen = srcbuf.length * 2 + 1; 85 86 etc.c.zlib.z_stream zs; 87 zs.next_in = cast(typeof(zs.next_in)) srcbuf.ptr; 88 zs.avail_in = to!uint(srcbuf.length); 89 err = etc.c.zlib.inflateInit2(&zs, winbits); 90 if (err) 91 { 92 throw new ZlibException(err); 93 } 94 95 size_t olddestlen = 0u; 96 97 loop: 98 while (true) 99 { 100 destbuf.length = destlen; 101 zs.next_out = cast(typeof(zs.next_out)) &destbuf[olddestlen]; 102 zs.avail_out = to!uint(destlen - olddestlen); 103 olddestlen = destlen; 104 105 err = etc.c.zlib.inflate(&zs, Z_NO_FLUSH); 106 switch (err) 107 { 108 case Z_OK: 109 destlen = destbuf.length * 2; 110 continue loop; 111 112 case Z_BUF_ERROR: 113 case Z_STREAM_END: 114 destbuf.length = zs.total_out; 115 err = etc.c.zlib.inflateEnd(&zs); 116 if (err != Z_OK) 117 throw new ZlibException(err); 118 return destbuf; 119 120 default: 121 etc.c.zlib.inflateEnd(&zs); 122 throw new ZlibException(err); 123 } 124 } 125 assert(0, "Unreachable code"); 126 }