2 * Generate test vectorsa for Windows LZ77 Huffman compression.
\r
4 * Copyright (c) 2022 Douglas Bagnall <dbagnall@samba.org>
\r
8 * Can be compiled on Windows 2012r2 under Cygwin
\r
10 * gcc -o generate-windows-test-vectors \
\r
11 * generate-windows-test-vectors.c \
\r
12 * C:\Windows\SysWOW64\cabinet.dll \
\r
15 * There might be better ways.
\r
17 * See https://learn.microsoft.com/en-us/windows/win32/cmpapi/-compression-portal
\r
24 #include <stdbool.h>
\r
26 #include <sys/types.h>
\r
27 #include <sys/stat.h>
\r
30 /* compressapi.h is in the Windows API. mingw-w64 has a copy. */
\r
31 #include <compressapi.h>
\r
32 #include <errhandlingapi.h>
\r
39 /* Windows size_t is different than Cygwin size_t (though still 64 bit) */
\r
40 typedef unsigned long long wsize_t;
\r
43 #define compression_flags (COMPRESS_ALGORITHM_XPRESS_HUFF | COMPRESS_RAW)
\r
45 int32_t compression_level = 0;
\r
47 static struct blob compress(struct blob input)
\r
49 COMPRESSOR_HANDLE handle;
\r
54 ok = CreateCompressor(compression_flags, NULL, &handle);
\r
57 fprintf(stderr, "CreateCompressor failed\n");
\r
61 output.length = input.length * 3 + 256;
\r
62 output.data = malloc(output.length);
\r
63 if (output.data == NULL) {
\r
64 fprintf(stderr, "output allocation failed (estimated %zu)\n",
\r
70 ok = SetCompressorInformation(handle,
\r
71 COMPRESS_INFORMATION_CLASS_LEVEL,
\r
73 sizeof(compression_level));
\r
76 fprintf(stderr, "SetCompressorInformation failed: %d\n",
\r
81 ok = Compress(handle,
\r
88 fprintf(stderr, "Compress failed\n");
\r
91 output.data = realloc(output.data, used);
\r
92 if (output.data == NULL) {
\r
94 "failed to shrinkwrap output! (from %zu to %llu)\n",
\r
95 output.length, used);
\r
98 output.length = used;
\r
99 CloseCompressor(handle);
\r
104 struct blob decompress(struct blob input,
\r
105 size_t expected_size)
\r
107 DECOMPRESSOR_HANDLE handle;
\r
108 struct blob output;
\r
112 ok = CreateDecompressor(compression_flags, NULL, &handle);
\r
115 fprintf(stderr, "CreateDecompressor failed\n");
\r
119 output.length = expected_size;
\r
120 output.data = malloc(output.length);
\r
121 if (output.data == NULL) {
\r
122 fprintf(stderr, "output allocation failed (%zu)\n",
\r
127 ok = Decompress(handle,
\r
134 fprintf(stderr, "Decompress failed\n");
\r
137 CloseDecompressor(handle);
\r
142 static void __attribute__((noreturn)) usage(int ret)
\r
145 "USAGE: test-win-vectors {c,d} filename [length|level] > DEST\n\n");
\r
146 fprintf(stderr, "c for< compression, d for decompression\n");
\r
147 fprintf(stderr, "decompressed length is required for decompression\n");
\r
148 fprintf(stderr, "compression level flag is optional [default 0]\n");
\r
152 int main(int argc, const char *argv[])
\r
155 const char *filename;
\r
158 struct blob input = {0};
\r
159 struct blob output = {0};
\r
161 if (argc < 3 || argc > 4) {
\r
164 filename = argv[2];
\r
166 fh = fopen(filename, "rb");
\r
168 fprintf(stderr, "Could not open %s\n", filename);
\r
172 ret = fstat(fileno(fh), &s);
\r
174 fprintf(stderr, "Could not stat %s: %d\n", filename, ret);
\r
177 input.length = s.st_size;
\r
178 input.data = malloc(input.length);
\r
179 if (input.data == NULL) {
\r
180 fprintf(stderr, "input too big for memory?! (%zu)\n",
\r
185 fread(input.data, 1, input.length, fh);
\r
187 if (strcmp(argv[1], "c") == 0) {
\r
188 if (argc == 4 && strcmp(argv[3], "0")) {
\r
189 compression_level = 1;
\r
191 output = compress(input);
\r
192 } else if (strcmp(argv[1], "d") == 0) {
\r
193 size_t decomp_size;
\r
195 fprintf(stderr, "no length given\n");
\r
198 decomp_size = atoi(argv[3]);
\r
199 output = decompress(input, decomp_size);
\r
203 fwrite(output.data, 1, output.length, stdout);
\r