X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Flzms-decompress.c;h=c73a3fdd44afc3b2bb53917119ac248693d97d85;hp=9459b0b91cbd3c4d2d731e3a92a3015b2ea9a706;hb=60523d25f34692d6f3a7c8bbda88eead17f23b12;hpb=3ffb2cde078ae8f62d542ab89166e1059c13d758 diff --git a/src/lzms-decompress.c b/src/lzms-decompress.c index 9459b0b9..c73a3fdd 100644 --- a/src/lzms-decompress.c +++ b/src/lzms-decompress.c @@ -23,13 +23,120 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ +#include "wimlib/win32_common.h" #include "wimlib/lzms.h" #include "wimlib/error.h" +#include + +typedef HANDLE DECOMPRESSOR_HANDLE; +typedef PVOID PCOMPRESS_ALLOCATION_ROUTINES; +typedef DECOMPRESSOR_HANDLE *PDECOMPRESSOR_HANDLE; + +typedef enum { + COMPRESS_INFORMATION_CLASS_INVALID = 0, + COMPRESS_INFORMATION_CLASS_LEVEL, + COMPRESS_INFORMATION_CLASS_BLOCK_SIZE +} COMPRESS_INFORMATION_CLASS; + +#define COMPRESS_ALGORITHM_LZMS 0x00000005 +#define COMPRESS_RAW 0x20000000 /* Not documented */ + +static HMODULE hCabinetDll; +static pthread_mutex_t cabinetDllMutex = PTHREAD_MUTEX_INITIALIZER; + +static BOOL (WINAPI *CreateDecompressor) + (DWORD Algorithm, + PCOMPRESS_ALLOCATION_ROUTINES AllocationRoutines, + PDECOMPRESSOR_HANDLE DecompressorHandle); + +static BOOL (WINAPI *CloseDecompressor) + (DECOMPRESSOR_HANDLE DecompressorHandle); + +static BOOL (WINAPI *Decompress) + (DECOMPRESSOR_HANDLE DecompressorHandle, + PVOID CompressedData, + SIZE_T CompressedDataSize, + PVOID UncompressedBuffer, + SIZE_T UncompressedBufferSize, + PSIZE_T UncompressedDataSize); int -lzms_decompress(const void *cdata, unsigned clen, void *udata, unsigned unlen, +lzms_decompress(const void *cbuf, unsigned clen, void *ubuf, unsigned ulen, unsigned window_size) { - ERROR("LZMS decompression stub: not implemented"); - return -1; + int ret; + DECOMPRESSOR_HANDLE h; + + ERROR("clen=%u, ulen=%u, window_size=%u", clen, ulen, window_size); + + if (hCabinetDll == NULL) { + pthread_mutex_lock(&cabinetDllMutex); + + if (hCabinetDll == NULL) { + hCabinetDll = LoadLibrary(L"Cabinet.dll"); + + if (hCabinetDll == NULL) { + ERROR("Can't load Cabinet.dll"); + ret = -1; + goto unlock; + } + + CreateDecompressor = (void*)GetProcAddress(hCabinetDll, "CreateDecompressor"); + Decompress = (void*)GetProcAddress(hCabinetDll, "Decompress"); + CloseDecompressor = (void*)GetProcAddress(hCabinetDll, "CloseDecompressor"); + + if (CreateDecompressor == NULL || + Decompress == NULL || + CloseDecompressor == NULL) + { + ERROR("Can't find LZMS compression routines in Cabinet.dll"); + ret = -1; + goto unlock; + } + } + ret = 0; + unlock: + pthread_mutex_unlock(&cabinetDllMutex); + if (ret) + goto out; + } + + + if (!CreateDecompressor(COMPRESS_ALGORITHM_LZMS | COMPRESS_RAW, NULL, &h)) { + ERROR("Failed to create LZMS decompressor (err %d)!", GetLastError()); + ret = -1; + goto out; + } + + + /* TODO: Some sort of chunk header? */ + unsigned offset; + if (clen <= window_size) { + offset = 0; + } else { + const unsigned *p = cbuf; + ERROR("%08x(%u) %08x %08x %08x %08x(%u)", + p[0], p[0], p[1], p[2], p[3], p[4], p[4]); + offset = 20; + } + SIZE_T actual_ulen = -1; + if (!Decompress(h, (void*)cbuf + offset, clen - offset, ubuf, ulen, &actual_ulen)) { + ERROR("Failed to decompress LZMS-compressed data (err %d)!", GetLastError()); + ret = -1; + goto out_close_decompressor; + } + + if (actual_ulen != ulen) { + ERROR("Unexpected actual uncompressed length (got %u, expected %u)", + actual_ulen, ulen); + ret = -1; + goto out_close_decompressor; + } + + ERROR("Successfully decompressed data."); + ret = 0; +out_close_decompressor: + CloseDecompressor(h); +out: + return ret; }