diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index 855bdb96c51..8bbb6104456 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -1234,19 +1234,61 @@ NTSTATUS WINAPI RtlGetCompressionWorkSpaceSize(USHORT CompressionFormatAndEngine return STATUS_NOT_IMPLEMENTED; } +/* compress data using LZNT1, currently only a stub */ +static NTSTATUS lznt1_compress(UCHAR *src, ULONG src_size, UCHAR *dst, ULONG dst_size, + ULONG chunk_size, ULONG *final_size, UCHAR *workspace) +{ + UCHAR *src_cur = src, *src_end = src + src_size; + UCHAR *dst_cur = dst, *dst_end = dst + dst_size; + ULONG block_size; + + while (src_cur < src_end) + { + /* determine size of current chunk */ + block_size = min(0x1000, src_end - src_cur); + if (dst_cur + sizeof(WORD) + block_size > dst_end) + return STATUS_BUFFER_TOO_SMALL; + + /* write (uncompressed) chunk header */ + *(WORD *)dst_cur = 0x3000 | (block_size - 1); + dst_cur += sizeof(WORD); + + /* write chunk content */ + memcpy(dst_cur, src_cur, block_size); + dst_cur += block_size; + src_cur += block_size; + } + + if (final_size) + *final_size = dst_cur - dst; + + return STATUS_SUCCESS; +} + /****************************************************************************** * RtlCompressBuffer [NTDLL.@] */ -NTSTATUS WINAPI RtlCompressBuffer(USHORT CompressionFormatAndEngine, PUCHAR UncompressedBuffer, - ULONG UncompressedBufferSize, PUCHAR CompressedBuffer, - ULONG CompressedBufferSize, ULONG UncompressedChunkSize, - PULONG FinalCompressedSize, PVOID WorkSpace) +NTSTATUS WINAPI RtlCompressBuffer(USHORT format, PUCHAR uncompressed, ULONG uncompressed_size, + PUCHAR compressed, ULONG compressed_size, ULONG chunk_size, + PULONG final_size, PVOID workspace) { - FIXME("0x%04x, %p, %u, %p, %u, %u, %p, %p :stub\n", CompressionFormatAndEngine, UncompressedBuffer, - UncompressedBufferSize, CompressedBuffer, CompressedBufferSize, UncompressedChunkSize, - FinalCompressedSize, WorkSpace); + FIXME("0x%04x, %p, %u, %p, %u, %u, %p, %p: semi-stub\n", format, uncompressed, + uncompressed_size, compressed, compressed_size, chunk_size, final_size, workspace); - return STATUS_NOT_IMPLEMENTED; + switch (format & ~COMPRESSION_ENGINE_MAXIMUM) + { + case COMPRESSION_FORMAT_LZNT1: + return lznt1_compress(uncompressed, uncompressed_size, compressed, + compressed_size, chunk_size, final_size, workspace); + + case COMPRESSION_FORMAT_NONE: + case COMPRESSION_FORMAT_DEFAULT: + return STATUS_INVALID_PARAMETER; + + default: + FIXME("format %u not implemented\n", format); + return STATUS_UNSUPPORTED_COMPRESSION; + } } /****************************************************************************** diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 0b64d955708..755424c044a 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -1636,21 +1636,18 @@ static void test_RtlCompressBuffer(void) final_size = 0xdeadbeef; status = pRtlCompressBuffer(COMPRESSION_FORMAT_NONE, test_buffer, sizeof(test_buffer), buf1, sizeof(buf1) - 1, 4096, &final_size, workspace); - todo_wine ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status); ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size); final_size = 0xdeadbeef; status = pRtlCompressBuffer(COMPRESSION_FORMAT_DEFAULT, test_buffer, sizeof(test_buffer), buf1, sizeof(buf1) - 1, 4096, &final_size, workspace); - todo_wine ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status); ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size); final_size = 0xdeadbeef; status = pRtlCompressBuffer(0xFF, test_buffer, sizeof(test_buffer), buf1, sizeof(buf1) - 1, 4096, &final_size, workspace); - todo_wine ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status); ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size); @@ -1659,9 +1656,7 @@ static void test_RtlCompressBuffer(void) memset(buf1, 0x11, sizeof(buf1)); status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer), buf1, sizeof(buf1), 4096, &final_size, workspace); - todo_wine ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status); - todo_wine ok((*(WORD *)buf1 & 0x7000) == 0x3000, "no chunk signature found %04x\n", *(WORD *)buf1); todo_wine ok(final_size < sizeof(test_buffer), "got wrong final_size %u\n", final_size); @@ -1685,7 +1680,6 @@ static void test_RtlCompressBuffer(void) memset(buf1, 0x11, sizeof(buf1)); status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer), buf1, 4, 4096, &final_size, workspace); - todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "got wrong status 0x%08x\n", status); HeapFree(GetProcessHeap(), 0, workspace);