d3d8: Do not specify WINED3D_TEXTURE_CREATE_MAPPABLE in d3d8_device_CreateDepthStenci...
[wine.git] / dlls / opcservices / compress.c
blobcf49f17aaacfb5af4a9c0534c7b0d92980776cba
1 /*
2 * Copyright 2018 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "config.h"
23 #include <stdarg.h>
24 #ifdef HAVE_ZLIB
25 # include <zlib.h>
26 #endif
28 #include "windef.h"
29 #include "winternl.h"
30 #include "msopc.h"
32 #include "opc_private.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msopc);
39 #include <pshpack2.h>
40 struct local_file_header
42 DWORD signature;
43 WORD version;
44 WORD flags;
45 WORD method;
46 DWORD mtime;
47 DWORD crc32;
48 DWORD compressed_size;
49 DWORD uncompressed_size;
50 WORD name_length;
51 WORD extra_length;
54 struct data_descriptor
56 DWORD signature;
57 DWORD crc32;
58 DWORD compressed_size;
59 DWORD uncompressed_size;
62 struct central_directory_header
64 DWORD signature;
65 WORD version;
66 WORD min_version;
67 WORD flags;
68 WORD method;
69 DWORD mtime;
70 DWORD crc32;
71 DWORD compressed_size;
72 DWORD uncompressed_size;
73 WORD name_length;
74 WORD extra_length;
75 WORD comment_length;
76 WORD diskid;
77 WORD internal_attributes;
78 DWORD external_attributes;
79 DWORD local_file_offset;
82 struct central_directory_end
84 DWORD signature;
85 WORD diskid;
86 WORD firstdisk;
87 WORD records_num;
88 WORD records_total;
89 DWORD directory_size;
90 DWORD directory_offset;
91 WORD comment_length;
93 #include <poppack.h>
95 #define CENTRAL_DIR_SIGNATURE 0x02014b50
96 #define LOCAL_HEADER_SIGNATURE 0x04034b50
97 #define DIRECTORY_END_SIGNATURE 0x06054b50
98 #define DATA_DESCRIPTOR_SIGNATURE 0x08074b50
99 #define VERSION 20
101 enum entry_flags
103 USE_DATA_DESCRIPTOR = 0x8,
106 struct zip_archive
108 struct central_directory_header **files;
109 size_t file_count;
110 size_t file_size;
112 DWORD mtime;
113 IStream *output;
114 DWORD position;
115 HRESULT write_result;
117 unsigned char input_buffer[0x8000];
118 unsigned char output_buffer[0x8000];
121 HRESULT compress_create_archive(IStream *output, struct zip_archive **out)
123 struct zip_archive *archive;
124 WORD date, time;
125 FILETIME ft;
127 if (!(archive = heap_alloc(sizeof(*archive))))
128 return E_OUTOFMEMORY;
130 archive->files = NULL;
131 archive->file_size = 0;
132 archive->file_count = 0;
133 archive->write_result = S_OK;
135 archive->output = output;
136 IStream_AddRef(archive->output);
137 archive->position = 0;
139 GetSystemTimeAsFileTime(&ft);
140 FileTimeToDosDateTime(&ft, &date, &time);
141 archive->mtime = date << 16 | time;
143 *out = archive;
145 return S_OK;
148 static void compress_write(struct zip_archive *archive, void *data, ULONG size)
150 ULONG written;
152 archive->write_result = IStream_Write(archive->output, data, size, &written);
153 if (written != size)
154 archive->write_result = E_FAIL;
155 else
156 archive->position += written;
158 if (FAILED(archive->write_result))
159 WARN("Failed to write output %p, size %u, written %u, hr %#x.\n", data, size, written, archive->write_result);
162 void compress_finalize_archive(struct zip_archive *archive)
164 struct central_directory_end dir_end = { 0 };
165 size_t i;
167 dir_end.directory_offset = archive->position;
168 dir_end.records_num = archive->file_count;
169 dir_end.records_total = archive->file_count;
171 /* Directory entries */
172 for (i = 0; i < archive->file_count; ++i)
174 compress_write(archive, archive->files[i], sizeof(*archive->files[i]));
175 compress_write(archive, archive->files[i] + 1, archive->files[i]->name_length);
176 dir_end.directory_size += archive->files[i]->name_length + sizeof(*archive->files[i]);
179 /* End record */
180 dir_end.signature = DIRECTORY_END_SIGNATURE;
181 compress_write(archive, &dir_end, sizeof(dir_end));
183 IStream_Release(archive->output);
185 for (i = 0; i < archive->file_count; i++)
186 heap_free(archive->files[i]);
187 heap_free(archive->files);
188 heap_free(archive);
191 static void compress_write_content(struct zip_archive *archive, IStream *content,
192 OPC_COMPRESSION_OPTIONS options, struct data_descriptor *data_desc)
194 #ifdef HAVE_ZLIB
195 int level, flush;
196 z_stream z_str;
197 #endif
198 LARGE_INTEGER move;
199 ULONG num_read;
200 HRESULT hr;
202 data_desc->crc32 = RtlComputeCrc32(0, NULL, 0);
203 move.QuadPart = 0;
204 IStream_Seek(content, move, STREAM_SEEK_SET, NULL);
206 #ifdef HAVE_ZLIB
208 switch (options)
210 case OPC_COMPRESSION_NONE:
211 level = Z_NO_COMPRESSION;
212 break;
213 case OPC_COMPRESSION_NORMAL:
214 level = Z_DEFAULT_COMPRESSION;
215 break;
216 case OPC_COMPRESSION_MAXIMUM:
217 level = Z_BEST_COMPRESSION;
218 break;
219 case OPC_COMPRESSION_FAST:
220 level = 2;
221 break;
222 case OPC_COMPRESSION_SUPERFAST:
223 level = Z_BEST_SPEED;
224 break;
225 default:
226 WARN("Unsupported compression options %d.\n", options);
227 level = Z_DEFAULT_COMPRESSION;
230 memset(&z_str, 0, sizeof(z_str));
231 deflateInit2(&z_str, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
235 int ret;
237 if (FAILED(hr = IStream_Read(content, archive->input_buffer, sizeof(archive->input_buffer), &num_read)))
239 archive->write_result = hr;
240 break;
243 z_str.avail_in = num_read;
244 z_str.next_in = archive->input_buffer;
245 data_desc->crc32 = RtlComputeCrc32(data_desc->crc32, archive->input_buffer, num_read);
247 flush = sizeof(archive->input_buffer) > num_read ? Z_FINISH : Z_NO_FLUSH;
251 ULONG have;
253 z_str.avail_out = sizeof(archive->output_buffer);
254 z_str.next_out = archive->output_buffer;
256 if ((ret = deflate(&z_str, flush)))
257 WARN("Failed to deflate, ret %d.\n", ret);
258 have = sizeof(archive->output_buffer) - z_str.avail_out;
259 compress_write(archive, archive->output_buffer, have);
260 } while (z_str.avail_out == 0);
261 } while (flush != Z_FINISH);
263 deflateEnd(&z_str);
265 data_desc->compressed_size = z_str.total_out;
266 data_desc->uncompressed_size = z_str.total_in;
268 #else
270 if (options != OPC_COMPRESSION_NONE)
271 FIXME("Writing without compression.\n");
275 if (FAILED(hr = IStream_Read(content, archive->input_buffer, sizeof(archive->input_buffer), &num_read)))
277 archive->write_result = hr;
278 break;
281 if (num_read == 0)
282 break;
284 data_desc->uncompressed_size += num_read;
285 data_desc->crc32 = RtlComputeCrc32(data_desc->crc32, archive->input_buffer, num_read);
286 compress_write(archive, archive->input_buffer, num_read);
287 } while (num_read != 0 && archive->write_result == S_OK);
289 data_desc->compressed_size = data_desc->uncompressed_size;
291 #endif /* HAVE_ZLIB */
294 HRESULT compress_add_file(struct zip_archive *archive, const WCHAR *path,
295 IStream *content, OPC_COMPRESSION_OPTIONS options)
297 struct central_directory_header *entry;
298 struct local_file_header local_header;
299 struct data_descriptor data_desc;
300 DWORD local_header_pos;
301 char *name;
302 DWORD len;
304 len = WideCharToMultiByte(CP_ACP, 0, path, -1, NULL, 0, NULL, NULL);
305 if (!(name = heap_alloc(len)))
306 return E_OUTOFMEMORY;
307 WideCharToMultiByte(CP_ACP, 0, path, -1, name, len, NULL, NULL);
309 /* Local header */
310 local_header.signature = LOCAL_HEADER_SIGNATURE;
311 local_header.version = VERSION;
312 local_header.flags = USE_DATA_DESCRIPTOR;
313 local_header.method = 8; /* Z_DEFLATED */
314 local_header.mtime = archive->mtime;
315 local_header.crc32 = 0;
316 local_header.compressed_size = 0;
317 local_header.uncompressed_size = 0;
318 local_header.name_length = len - 1;
319 local_header.extra_length = 0;
321 local_header_pos = archive->position;
323 compress_write(archive, &local_header, sizeof(local_header));
324 compress_write(archive, name, local_header.name_length);
326 /* Content */
327 compress_write_content(archive, content, options, &data_desc);
329 /* Data descriptor */
330 data_desc.signature = DATA_DESCRIPTOR_SIGNATURE;
331 compress_write(archive, &data_desc, sizeof(data_desc));
333 if (FAILED(archive->write_result))
334 return archive->write_result;
336 /* Set directory entry */
337 if (!(entry = heap_alloc_zero(sizeof(*entry) + local_header.name_length)))
339 heap_free(name);
340 return E_OUTOFMEMORY;
343 entry->signature = CENTRAL_DIR_SIGNATURE;
344 entry->version = local_header.version;
345 entry->min_version = local_header.version;
346 entry->flags = local_header.flags;
347 entry->method = local_header.method;
348 entry->mtime = local_header.mtime;
349 entry->crc32 = data_desc.crc32;
350 entry->compressed_size = data_desc.compressed_size;
351 entry->uncompressed_size = data_desc.uncompressed_size;
352 entry->name_length = local_header.name_length;
353 entry->local_file_offset = local_header_pos;
354 memcpy(entry + 1, name, entry->name_length);
355 heap_free(name);
357 if (!opc_array_reserve((void **)&archive->files, &archive->file_size, archive->file_count + 1,
358 sizeof(*archive->files)))
360 heap_free(entry);
361 return E_OUTOFMEMORY;
364 archive->files[archive->file_count++] = entry;
366 return S_OK;