blob: 70ffdbecf3747d3df2a263396091a0c3729dba97 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2018 MediaTek Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <aee.h>
25#include <assert.h>
26#include <kdump.h>
27#include <lib/mempool.h>
28#include <lib/zlib.h>
29#include <lib/zutil.h>
30#include <malloc.h>
31#include <platform.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <string.h>
35#include "lib/cksum.h"
36
37#ifdef MTK_3LEVEL_PAGETABLE
38#include <stdlib.h>
39#include <err.h>
40#endif
41
42#define KZIP_DEBUG(x...)
43
44#define KDUMP_SIZE_REPORT 0x1000000
45#define KDUMP_TICK_WDT 0x10000
46
47#ifdef MRDUMP_USB_DUMP_NO_COMPRESSION
48#define KDUMP_ZLIB_LEVEL Z_NO_COMPRESSION
49#else
50#define KDUMP_ZLIB_LEVEL Z_BEST_SPEED
51#endif
52
53#define ZIPVERSION_NEEDED 45UL
54
55static void putvalue(void *dest, uint64_t x, int nbByte)
56{
57 uint8_t *buf = (uint8_t *)dest;
58 int n;
59 for (n = 0; n < nbByte; n++) {
60 buf[n] = (unsigned char)(x & 0xff);
61 x >>= 8;
62 }
63#if 0
64 if (x != 0) {
65 /* data overflow - hack for ZIP64 */
66 for (n = 0; n < nbByte; n++) {
67 buf[n] = 0xff;
68 }
69 }
70#endif
71}
72
73static int put_zip64_eoc_directory_record(uint8_t *buf, int record_num, uint64_t zip_centralheader_offset, int zip_centralheader_size)
74{
75 uint8_t *oldbuf = buf;
76 putvalue(buf, ZIP64ENDOFCENTRALDIRMAGIC, 4);
77 buf += 4;
78 putvalue(buf, 44, 8); /* zip64 eoc size */
79 buf += 8;
80 putvalue(buf, ZIPVERSION_NEEDED, 2); /* version made by */
81 buf += 2;
82 putvalue(buf, ZIPVERSION_NEEDED, 2); /* version needed to extract */
83 buf += 2;
84 putvalue(buf, 0, 4); /* number of this disk */
85 buf += 4;
86 putvalue(buf, 0, 4); /* number of the disk with the start of the central directory */
87 buf += 4;
88 putvalue(buf, record_num, 8); /* total number of entries in the central directory on this disk */
89 buf += 8;
90 putvalue(buf, record_num, 8); /* total number of entries in the central directory */
91 buf += 8;
92 putvalue(buf, zip_centralheader_size, 8); /* size of the central directory */
93 buf += 8;
94 putvalue(buf, zip_centralheader_offset, 8); /* offset of start of central directory with respect to the starting disk number */
95 buf += 8;
96 return buf - oldbuf;
97}
98
99static int put_zip64_eoc_directory_locator(uint8_t *buf, uint64_t zip64_eoc_offset)
100{
101 uint8_t *oldbuf = buf;
102 putvalue(buf, ZIP64ENDOFCENTRALDIRLOCATORMAGIC, 4);
103 buf += 4;
104 putvalue(buf, 0, 4); /* number of the disk with the start of the zip64 end of central directory */
105 buf += 4;
106 putvalue(buf, zip64_eoc_offset, 8); /* relative offset of the zip64 end of central directory record */
107 buf += 8;
108 putvalue(buf, 1, 4); /* total number of disks */
109 buf += 4;
110 return buf - oldbuf;
111}
112
113static int put_eoc_directory_record(uint8_t *buf, int record_num, uint64_t zip_centralheader_offset, int zip_centralheader_size)
114{
115 uint8_t *oldbuf = buf;
116 putvalue(buf, ENDOFCENTRALDIRMAGIC, 4);
117 buf += 4;
118 putvalue(buf, 0, 2); /* Number of this disk */
119 buf += 2;
120 putvalue(buf, 0, 2); /* Disk where central directory starts */
121 buf += 2;
122 putvalue(buf, record_num, 2); /* Number of central directory records on this disk */
123 buf += 2;
124 putvalue(buf, record_num, 2); /* Total number of central directory records */
125 buf += 2;
126 putvalue(buf, zip_centralheader_size, 4);
127 buf += 4;
128 putvalue(buf, 0xffffffff, 4);
129 buf += 4;
130 putvalue(buf, 0, 2); /* Comment length (n) */
131 buf += 2;
132 return buf - oldbuf;
133}
134
135static int put_localheader(uint8_t *buf, const char *filename, int level)
136{
137 uint8_t *oldbuf = buf;
138 putvalue(buf, LOCALHEADERMAGIC, 4);
139 buf += 4;
140 putvalue(buf, ZIPVERSION_NEEDED, 2);
141 buf += 2;
142
143 uint16_t flag = 0;
144 if ((level==8) || (level == 9))
145 flag |= 2;
146 if (level == 2)
147 flag |= 4;
148 if (level == 1)
149 flag |= 6;
150#if 0
151 if (password != NULL)
152 flag |= 1;
153#endif
154
155 putvalue(buf, flag | 0x8, 2);
156 buf += 2;
157
158 putvalue(buf, Z_DEFLATED, 2);
159 buf += 2;
160
161 putvalue(buf,0UL, 4);
162 buf += 4;
163
164 // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
165 putvalue(buf, 0UL, 4); /* crc 32, unknown */
166 buf += 4;
167 putvalue(buf, 0xFFFFFFFFUL, 4); /* compressed size, unknown */
168 buf += 4;
169 putvalue(buf, 0xFFFFFFFFUL, 4); /* uncompressed size, unknown */
170 buf += 4;
171 putvalue(buf, strlen(filename), 2); /* size of filename */
172 buf += 2;
173 putvalue(buf, 4 + 8 + 8, 2); /* size of extra field */
174 buf += 2;
175
176 memcpy(buf, filename, strlen(filename));
177 buf += strlen(filename);
178
179 /* ZIP64 extension */
180 putvalue(buf, 0x0001, 2); /* ZIP64_EXTENSION */
181 buf += 2;
182 putvalue(buf, 8 + 8, 2);
183 buf += 2;
184 putvalue(buf, 0UL, 8);
185 buf += 8;
186 putvalue(buf, 0UL, 8);
187 buf += 8;
188
189 return buf - oldbuf;
190}
191
192static int put_centralheader(uint8_t *buf, const char *filename, int level, uint64_t zip_localheader_offset, uint64_t size, uint64_t uncomp_size, uint32_t crc32_value)
193{
194 uint8_t *oldbuf = buf;
195
196 putvalue(buf, CENTRALHEADERMAGIC, 4);
197 buf += 4;
198 putvalue(buf, ZIPVERSION_NEEDED, 2);
199 buf += 2;
200 putvalue(buf, ZIPVERSION_NEEDED, 2);
201 buf += 2;
202
203 uint16_t flag = 0;
204 if ((level==8) || (level == 9))
205 flag |= 2;
206 if (level == 2)
207 flag |= 4;
208 if (level == 1)
209 flag |= 6;
210#if 0
211 if (password != NULL)
212 flag |= 1;
213#endif
214
215 putvalue(buf, flag | 0x8, 2);
216 buf += 2;
217
218 putvalue(buf, Z_DEFLATED, 2);
219 buf += 2;
220
221 putvalue(buf,0UL, 4);
222 buf += 4;
223
224 // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
225 putvalue(buf, crc32_value, 4); /* crc 32 */
226 buf += 4;
227 putvalue(buf, 0xffffffffUL, 4); /* compressed size */
228 buf += 4;
229 putvalue(buf, 0xffffffffUL, 4); /* uncompressed size */
230 buf += 4;
231 putvalue(buf, strlen(filename), 2);
232 buf += 2;
233 putvalue(buf, 4 + 8 + 8 + 8, 2); /* size of extra field */
234 buf += 2;
235 putvalue(buf, 0UL, 2); /* size of comment field */
236 buf += 2;
237 putvalue(buf, 0UL, 2); /* disk number */
238 buf += 2;
239 putvalue(buf, 0UL, 2); /* internal attributes */
240 buf += 2;
241 putvalue(buf, 0UL, 4); /* external file attributes */
242 buf += 4;
243 putvalue(buf, 0xffffffffUL, 4); /* Relative offset */
244 buf += 4;
245 memcpy(buf, filename, strlen(filename));
246 buf += strlen(filename);
247
248 /* ZIP64 extension */
249 putvalue(buf, 0x0001, 2); /* ZIP64_EXTENSION */
250 buf += 2;
251 putvalue(buf, 8 + 8 + 8, 2);
252 buf += 2;
253 putvalue(buf, uncomp_size, 8);
254 buf += 8;
255 putvalue(buf, size, 8);
256 buf += 8;
257 putvalue(buf, zip_localheader_offset, 8);
258 buf += 8;
259
260 return buf - oldbuf;
261}
262
263static int kzip_write_current(struct kzip_file *zfile, void *buf, int len)
264{
265 KZIP_DEBUG("%s: write_cb %p len %d\n", __func__, zfile->write_cb, len);
266 int retval = zfile->write_cb(zfile->handle, buf, len);
267 if (retval > 0) {
268 zfile->current_size += retval;
269 }
270 if ((zfile->current_size - zfile->reported_size) >= KDUMP_SIZE_REPORT) {
271 vo_show_progress(zfile->current_size / 0x100000);
272 zfile->reported_size = zfile->current_size;
273 }
274 if ((zfile->current_size - zfile->wdk_kick_size) >= KDUMP_TICK_WDT) {
275 mtk_wdt_restart();
276 zfile->wdk_kick_size = zfile->current_size;
277 }
278 return retval;
279}
280
281struct kzip_file *kzip_open(void *handle, int (*write_cb)(void *handle, void *p, int size))
282{
283 struct kzip_file *zf = mempool_alloc(sizeof(struct kzip_file), MEMPOOL_ANY);
284 memset(zf, 0, sizeof(struct kzip_file));
285 zf->handle = handle;
286 zf->write_cb = write_cb;
287 KZIP_DEBUG("%s: handle zf %p %p write_cb %p\n", __func__, zf, zf->handle, zf->write_cb);
288
289 vo_show_progress(0);
290 return zf;
291}
292
293bool kzip_close(struct kzip_file *zf)
294{
295 uint64_t central_header_offset = zf->current_size;
296 struct kzip_entry *zentries = zf->zentries;
297 int num = zf->entries_num;
298
299 int i, hsize = 0, local_hsize;
300 uint8_t databuf[128];
301 for (i = 0; i < num; i++) {
302 local_hsize = put_centralheader(databuf, zentries[i].filename, zentries[i].level,
303 zentries[i].localheader_offset,
304 zentries[i].comp_size,
305 zentries[i].uncomp_size,
306 zentries[i].crc32);
307 if (kzip_write_current(zf, databuf, local_hsize) != local_hsize) {
308 return false;
309 }
310 hsize += local_hsize;
311 }
312 voprintf_debug("%s: current_size %lld hoffset %lld\n", __func__, zf->current_size, central_header_offset);
313
314 uint64_t zip64_eoc_offset = zf->current_size;
315 local_hsize = put_zip64_eoc_directory_record(databuf, num, central_header_offset, hsize);
316 if ((local_hsize > 0) && (kzip_write_current(zf, databuf, local_hsize) != local_hsize)) {
317 return false;
318 }
319
320 local_hsize = put_zip64_eoc_directory_locator(databuf, zip64_eoc_offset);
321 if ((local_hsize > 0) && (kzip_write_current(zf, databuf, local_hsize) != local_hsize)) {
322 return false;
323 }
324
325 local_hsize = put_eoc_directory_record(databuf, num, central_header_offset, hsize);
326 if (kzip_write_current(zf, databuf, local_hsize) != local_hsize) {
327 return false;
328 }
329 mempool_free(zf);
330 return true;
331}
332
333#define CHUNK 65536
334
335/* Compress from file source to file dest until EOF on source.
336 def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
337 allocated for processing, Z_STREAM_ERROR if an invalid compression
338 level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
339 version of the library linked do not match, or Z_ERRNO if there is
340 an error reading or writing the files. */
341
342static bool kzip_add_file_no_mapped(struct kzip_file *zfile, const struct kzip_addlist *memlist,
343 int *flush, int *ret, uint8_t *in, uint8_t *out,
344 struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
345{
346 lk_time_t t = current_time();
347 uint64_t mem_size = memlist->size;
348 uint8_t *memsrc = (uint8_t *)(uintptr_t)memlist->address;
349 *flush = (memlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
350 voprintf_debug("-- Compress memory %llx, size %llu\n",
351 memlist->address, memlist->size);
352
353 do {
354 int in_size = mem_size > CHUNK ? CHUNK : mem_size;
355 if ((current_time() - t)/1000 > 10) {
356 voprintf_debug("-- I am working(interval to 10s) --\n");
357 t = current_time();
358 }
359 memcpy(in, memsrc, in_size);
360 zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
361 memsrc += in_size;
362 mem_size -= in_size;
363 strm->avail_in = in_size;
364 strm->next_in = in;
365
366 /* run deflate() on input until output buffer not full, finish
367 compression if all of source has been read in */
368 do {
369 strm->avail_out = CHUNK;
370 strm->next_out = out;
371 *ret = deflate(strm, *flush); /* no bad return value */
372 assert(*ret != Z_STREAM_ERROR); /* state not clobbered */
373 int have = CHUNK - strm->avail_out;
374 if (have > 0) {
375 aee_timer_stop(zip_time);
376 if (kzip_write_current(zfile, out, have) != have) {
377 voprintf_debug("-- Compress memory %llx, error. surplus size: %u\n",
378 memlist->address, mem_size);
379 return false;
380 }
381 aee_timer_start(zip_time);
382 }
383 } while (strm->avail_out == 0);
384 assert(strm->avail_in == 0); /* all input will be used */
385 } while (mem_size > 0);
386
387 voprintf_debug("-- Compress memory %llx, done. surplus size: %u\n",
388 memlist->address, mem_size);
389 return true;
390}
391
392#ifndef MTK_3LEVEL_PAGETABLE
393/* full mapping at LK, only one function is needed. kzip_add_file_no_mapped() */
394#define kzip_add_file_do_mapped kzip_add_file_no_mapped
395#else
396/* LPAE, map before accessing the address of memory */
397#define MAX_MAP_CNT (SECTION_SIZE/CHUNK)
398#define mapflags (MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA)
399static bool kzip_add_file_do_mapped(struct kzip_file *zfile, const struct kzip_addlist *memlist,
400 int *flush, int *ret, uint8_t *in, uint8_t *out,
401 struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
402{
403 /* multiple physical address mapped onto static 2MB address space. (scratch_addr) */
404 int cnt = 0;
405 uint64_t paddr = memlist->address;
406 vaddr_t vaddr = ROUNDUP(scratch_addr(), SECTION_SIZE);
407 voprintf_debug("-- map: paddr=0x%016llx, vaddr=0x%08x\n", paddr, vaddr);
408
409 uint64_t mem_size = memlist->size;
410 uint8_t *memsrc;
411 *flush = (memlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
412 voprintf_debug("-- Compress memory %llx, size %llu\n", memlist->address, memlist->size);
413
414 do {
415 /* arch_mmu_map by each 2MB size */
416 if (cnt == 0) {
417 int map_ok = arch_mmu_map(paddr, vaddr, mapflags, SECTION_SIZE);
418 if (map_ok != NO_ERROR) {
419 voprintf_debug("-- arch_mmu_map map error: map_ok=%d, paddr=0x%016llx, vaddr=0x%08x\n",
420 map_ok, paddr, vaddr);
421 return false;
422 }
423 memsrc = (uint8_t *)vaddr;
424 }
425
426 int in_size = mem_size > CHUNK ? CHUNK : mem_size;
427 memcpy(in, memsrc, in_size);
428 zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
429 memsrc += in_size;
430 mem_size -= in_size;
431 strm->avail_in = in_size;
432 strm->next_in = in;
433
434 /* run deflate() on input until output buffer not full, finish
435 compression if all of source has been read in */
436 do {
437 strm->avail_out = CHUNK;
438 strm->next_out = out;
439 *ret = deflate(strm, *flush); /* no bad return value */
440 assert(*ret != Z_STREAM_ERROR); /* state not clobbered */
441 int have = CHUNK - strm->avail_out;
442 if (have > 0) {
443 aee_timer_stop(zip_time);
444 if (kzip_write_current(zfile, out, have) != have) {
445 voprintf_debug("-- Compress memory %llx, error. surplus size: %u\n",
446 memlist->address, mem_size);
447 return false;
448 }
449 aee_timer_start(zip_time);
450 }
451 } while (strm->avail_out == 0);
452 assert(strm->avail_in == 0); /* all input will be used */
453
454 /* mod by 2MB (SECTION_SIZE) */
455 cnt++;
456 cnt %= MAX_MAP_CNT;
457 if (cnt == 0)
458 paddr += SECTION_SIZE;
459
460 } while (mem_size > 0);
461
462 voprintf_debug("-- Compress memory %llx, done. surplus size: %u\n", memlist->address, mem_size);
463 return true;
464}
465#endif
466
467static bool kzip_add_file_from_expdb(struct kzip_file *zfile, const struct kzip_addlist *addlist,
468 int *flush, int *ret, uint8_t *in, uint8_t *out,
469 struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
470{
471 uint64_t offset_src = addlist->address;
472 int64_t mem_size = addlist->size;
473
474 *flush = (addlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
475 voprintf_debug("-- Compress expdb offset %llx, size %llu\n", offset_src, mem_size);
476
477 do {
478 /* read from expdb to memsrc */
479 if (mem_size > CHUNK) {
480 //mrdump_read_expdb(in, CHUNK, offset_src);
481 } else {
482 //mrdump_read_expdb(in, (int)mem_size, offset_src);
483 }
484
485 int in_size = mem_size > CHUNK ? CHUNK : mem_size;
486 zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
487 mem_size -= in_size;
488 strm->avail_in = in_size;
489 strm->next_in = in;
490
491 /* run deflate() on input until output buffer not full, finish
492 compression if all of source has been read in */
493 do {
494 strm->avail_out = CHUNK;
495 strm->next_out = out;
496 *ret = deflate(strm, *flush); /* no bad return value */
497 assert(*ret != Z_STREAM_ERROR); /* state not clobbered */
498 int have = CHUNK - strm->avail_out;
499 if (have > 0) {
500 aee_timer_stop(zip_time);
501 if (kzip_write_current(zfile, out, have) != have) {
502 voprintf_debug("-- Compress expdb offset %llx, error. surplus size: %u\n",
503 offset_src, mem_size);
504 return false;
505 }
506 aee_timer_start(zip_time);
507 }
508 } while (strm->avail_out == 0);
509 assert(strm->avail_in == 0); /* all input will be used */
510
511 offset_src += in_size;
512
513 } while (mem_size > 0);
514
515 voprintf_debug("-- Compress expdb offset %llx, done. surplus size: %u\n", offset_src, mem_size);
516 return true;
517}
518
519bool kzip_add_file(struct kzip_file *zfile, const struct kzip_addlist *addlist, const char *zfilename)
520{
521 int ret, flush;
522 z_stream strm;
523 struct aee_timer zip_time;
524
525 if (zfile->entries_num >= KZIP_ENTRY_MAX) {
526 voprintf_error("Too many zip entry %d\n", zfile->entries_num);
527 return false;
528 }
529
530 voprintf_debug("%s: zf %p(%p) %s\n", __func__, zfile, zfile->write_cb, zfilename);
531 struct kzip_entry *zentry = &zfile->zentries[zfile->entries_num++];
532 zentry->filename = strdup(zfilename);
533 zentry->localheader_offset = zfile->current_size;
534 zentry->level = KDUMP_ZLIB_LEVEL;
535 zentry->crc32 = 0xffffffffUL;
536
537 KZIP_DEBUG("%s: write local header\n", __func__);
538 uint8_t zip_localheader[128];
539 int hsize = put_localheader(zip_localheader, zfilename, zentry->level);
540 if (kzip_write_current(zfile, zip_localheader, hsize) != hsize) {
541 return false;
542 }
543
544 /* allocate deflate state */
545 memset(&strm, 0, sizeof(z_stream));
546 ret = deflateInit2(&strm, zentry->level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
547 if (ret != Z_OK) {
548 voprintf_error("zlib compress init failed\n");
549 return false;
550 }
551
552 uint8_t *out = mempool_alloc(CHUNK, MEMPOOL_ANY);
553 uint8_t *in = mempool_alloc(CHUNK, MEMPOOL_ANY);
554 if ((out == NULL) || (in == NULL)) {
555 voprintf_error("%s: malloc failed.\n", __func__);
556 goto error;
557 }
558
559 aee_timer_init(&zip_time);
560 aee_timer_start(&zip_time);
561
562 uint64_t start = zfile->current_size, uncomp_size = 0;
563 do {
564 switch (addlist->type) {
565 case MEM_NO_MAP:
566 if (kzip_add_file_no_mapped(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
567 goto error;
568 break;
569 case MEM_DO_MAP:
570 if (kzip_add_file_do_mapped(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
571 goto error;
572 break;
573 case EXPDB_FILE:
574 if (kzip_add_file_from_expdb(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
575 goto error;
576 break;
577 default:
578 goto error;
579 break;
580 }
581 uncomp_size += addlist->size;
582 addlist++;
583 /* done when last data in file processed */
584 } while (flush != Z_FINISH);
585 assert(ret == Z_STREAM_END); /* stream will be complete */
586
587 deflateEnd(&strm);
588 mempool_free(out);
589 mempool_free(in);
590 aee_timer_stop(&zip_time);
591 voprintf_info("Zip time: %d sec\n", zip_time.acc_ms / 1000);
592
593 zentry->comp_size = zfile->current_size - start;
594 zentry->uncomp_size = uncomp_size;
595 zentry->crc32 = zentry->crc32 ^ 0xffffffffUL;
596
597 return true;
598
599error:
600 mempool_free(out);
601 mempool_free(in);
602 deflateEnd(&strm);
603 return false;
604}