1#include "mupdf/fitz.h"
2
3#include <zlib.h>
4
5#include <limits.h>
6
7/*
8 Compress source_length bytes of data starting
9 at source, into a buffer of length *destLen, starting at dest.
10 *compressed_length will be updated on exit to contain the size
11 actually used.
12 */
13void fz_deflate(fz_context *ctx, unsigned char *dest, size_t *destLen, const unsigned char *source, size_t sourceLen, fz_deflate_level level)
14{
15 z_stream stream;
16 int err;
17 size_t left;
18
19 left = *destLen;
20 *destLen = 0;
21
22 stream.zalloc = fz_zlib_alloc;
23 stream.zfree = fz_zlib_free;
24 stream.opaque = ctx;
25
26 err = deflateInit(&stream, (int)level);
27 if (err != Z_OK)
28 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib compression failed: %d", err);
29
30 stream.next_out = dest;
31 stream.avail_out = 0;
32 stream.next_in = (z_const Bytef *)source;
33 stream.avail_in = 0;
34
35 do {
36 if (stream.avail_out == 0) {
37 stream.avail_out = left > UINT_MAX ? UINT_MAX : (uInt)left;
38 left -= stream.avail_out;
39 }
40 if (stream.avail_in == 0) {
41 stream.avail_in = sourceLen > UINT_MAX ? UINT_MAX : (uInt)sourceLen;
42 sourceLen -= stream.avail_in;
43 }
44 err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
45 } while (err == Z_OK);
46
47 /* We might have problems if the compressed length > uLong sized. Tough, for now. */
48 *destLen = stream.total_out;
49 deflateEnd(&stream);
50 if (err != Z_STREAM_END)
51 fz_throw(ctx, FZ_ERROR_GENERIC, "Zlib failure: %d", err);
52}
53
54/*
55 Compress source_length bytes of data starting
56 at source, into a new memory block malloced for that purpose.
57 *compressed_length is updated on exit to contain the size used.
58 Ownership of the block is returned from this function, and the
59 caller is therefore responsible for freeing it. The block may be
60 considerably larger than is actually required. The caller is
61 free to fz_realloc it down if it wants to.
62*/
63unsigned char *fz_new_deflated_data(fz_context *ctx, size_t *compressed_length, const unsigned char *source, size_t source_length, fz_deflate_level level)
64{
65 size_t bound = fz_deflate_bound(ctx, source_length);
66 unsigned char *cdata = fz_malloc(ctx, bound);
67 *compressed_length = 0;
68
69 fz_try(ctx)
70 fz_deflate(ctx, cdata, &bound, source, source_length, level);
71 fz_catch(ctx)
72 {
73 fz_free(ctx, cdata);
74 fz_rethrow(ctx);
75 }
76
77 *compressed_length = bound;
78 return cdata;
79}
80
81/*
82 Compress the contents of a fz_buffer into a
83 new block malloced for that purpose. *compressed_length is updated
84 on exit to contain the size used. Ownership of the block is
85 returned from this function, and the caller is therefore responsible
86 for freeing it. The block may be considerably larger than is
87 actually required. The caller is free to fz_realloc it down if it
88 wants to.
89*/
90unsigned char *fz_new_deflated_data_from_buffer(fz_context *ctx, size_t *compressed_length, fz_buffer *buffer, fz_deflate_level level)
91{
92 unsigned char *data;
93 size_t size = fz_buffer_storage(ctx, buffer, &data);
94
95 if (size == 0 || data == NULL)
96 {
97 *compressed_length = 0;
98 return NULL;
99 }
100
101 return fz_new_deflated_data(ctx, compressed_length, data, size, level);
102}
103
104/*
105 Returns the upper bound on the
106 size of flated data of length size.
107 */
108size_t fz_deflate_bound(fz_context *ctx, size_t size)
109{
110 /* Copied from zlib to account for size_t vs uLong */
111 return size + (size >> 12) + (size >> 14) + (size >> 25) + 13;
112}
113