* 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 <pthread.h>
+
+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;
}
if (size == 0)
return 0;
+ if (rspec->ctype == WIMLIB_COMPRESSION_TYPE_LZMS) {
+ /* TODO */
+
+ unsigned clen = rspec->size_in_wim;
+ unsigned ulen = rspec->uncompressed_size;
+
+ fprintf(stderr, "clen=%u, ulen=%u, offset=%lu\n", clen, ulen,
+ rspec->offset_in_wim);
+
+ u8 *cbuf = MALLOC(clen);
+ u8 *ubuf = MALLOC(ulen);
+
+ ret = full_pread(&rspec->wim->in_fd,
+ cbuf, clen, rspec->offset_in_wim);
+ if (ret) {
+ ERROR_WITH_ERRNO("Can't read compressed data");
+ goto out_free_bufs;
+ }
+
+ ret = lzms_decompress(cbuf, clen, ubuf, ulen,
+ orig_chunk_size);
+ if (ret) {
+ ERROR("LZMS decompression error.");
+ errno = EINVAL;
+ ret = WIMLIB_ERR_DECOMPRESSION;
+ goto out_free_bufs;
+ }
+ if (cb) {
+ u32 chunk_size;
+ for (u64 i = offset; i < offset + size; i += chunk_size) {
+ chunk_size = min(offset + size - i, cb_chunk_size);
+ ret = cb(&ubuf[i], chunk_size, ctx_or_buf);
+ if (ret)
+ goto out_free_bufs;
+ }
+ } else {
+ memcpy(ctx_or_buf, &ubuf[offset], size);
+ }
+ ret = 0;
+ out_free_bufs:
+ FREE(ubuf);
+ FREE(cbuf);
+ return ret;
+ }
+
u64 *chunk_offsets = NULL;
u8 *out_buf = NULL;
u8 *tmp_buf = NULL;
} else {
/* Normal mode: read must not overrun end of original size. */
wimlib_assert(offset + size >= size &&
- offset + size <= rspec->uncompressed_size);
+ lte->offset_in_res + offset + size <= rspec->uncompressed_size);
}
DEBUG("Reading WIM resource: %"PRIu64" @ +%"PRIu64"[+%"PRIu64"] "