4 * LZMS decompression routines.
8 * Copyright (C) 2013 Eric Biggers
10 * This file is part of wimlib, a library for working with WIM files.
12 * wimlib is free software; you can redistribute it and/or modify it under the
13 * terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your option)
17 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
19 * A PARTICULAR PURPOSE. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with wimlib; if not, see http://www.gnu.org/licenses/.
26 #include "wimlib/win32_common.h"
27 #include "wimlib/lzms.h"
28 #include "wimlib/error.h"
31 typedef HANDLE DECOMPRESSOR_HANDLE;
32 typedef PVOID PCOMPRESS_ALLOCATION_ROUTINES;
33 typedef DECOMPRESSOR_HANDLE *PDECOMPRESSOR_HANDLE;
36 COMPRESS_INFORMATION_CLASS_INVALID = 0,
37 COMPRESS_INFORMATION_CLASS_LEVEL,
38 COMPRESS_INFORMATION_CLASS_BLOCK_SIZE
39 } COMPRESS_INFORMATION_CLASS;
41 #define COMPRESS_ALGORITHM_LZMS 0x00000005
42 #define COMPRESS_RAW 0x20000000 /* Not documented */
44 static HMODULE hCabinetDll;
45 static pthread_mutex_t cabinetDllMutex = PTHREAD_MUTEX_INITIALIZER;
47 static BOOL (WINAPI *CreateDecompressor)
49 PCOMPRESS_ALLOCATION_ROUTINES AllocationRoutines,
50 PDECOMPRESSOR_HANDLE DecompressorHandle);
52 static BOOL (WINAPI *CloseDecompressor)
53 (DECOMPRESSOR_HANDLE DecompressorHandle);
55 static BOOL (WINAPI *Decompress)
56 (DECOMPRESSOR_HANDLE DecompressorHandle,
58 SIZE_T CompressedDataSize,
59 PVOID UncompressedBuffer,
60 SIZE_T UncompressedBufferSize,
61 PSIZE_T UncompressedDataSize);
64 lzms_decompress(const void *cbuf, unsigned clen, void *ubuf, unsigned ulen,
68 DECOMPRESSOR_HANDLE h;
70 ERROR("clen=%u, ulen=%u, window_size=%u", clen, ulen, window_size);
72 if (hCabinetDll == NULL) {
73 pthread_mutex_lock(&cabinetDllMutex);
75 if (hCabinetDll == NULL) {
76 hCabinetDll = LoadLibrary(L"Cabinet.dll");
78 if (hCabinetDll == NULL) {
79 ERROR("Can't load Cabinet.dll");
84 CreateDecompressor = (void*)GetProcAddress(hCabinetDll, "CreateDecompressor");
85 Decompress = (void*)GetProcAddress(hCabinetDll, "Decompress");
86 CloseDecompressor = (void*)GetProcAddress(hCabinetDll, "CloseDecompressor");
88 if (CreateDecompressor == NULL ||
90 CloseDecompressor == NULL)
92 ERROR("Can't find LZMS compression routines in Cabinet.dll");
99 pthread_mutex_unlock(&cabinetDllMutex);
105 if (!CreateDecompressor(COMPRESS_ALGORITHM_LZMS | COMPRESS_RAW, NULL, &h)) {
106 ERROR("Failed to create LZMS decompressor (err %d)!", GetLastError());
112 /* TODO: Some sort of chunk header? */
114 if (clen <= window_size) {
117 const unsigned *p = cbuf;
118 ERROR("%08x(%u) %08x %08x %08x %08x(%u)",
119 p[0], p[0], p[1], p[2], p[3], p[4], p[4]);
122 SIZE_T actual_ulen = -1;
123 if (!Decompress(h, (void*)cbuf + offset, clen - offset, ubuf, ulen, &actual_ulen)) {
124 ERROR("Failed to decompress LZMS-compressed data (err %d)!", GetLastError());
126 goto out_close_decompressor;
129 if (actual_ulen != ulen) {
130 ERROR("Unexpected actual uncompressed length (got %u, expected %u)",
133 goto out_close_decompressor;
136 ERROR("Successfully decompressed data.");
138 out_close_decompressor:
139 CloseDecompressor(h);