/src/mupdf/source/fitz/brotli.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2025 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #if FZ_ENABLE_BROTLI |
26 | | |
27 | | #include "brotli/encode.h" |
28 | | |
29 | | #include <limits.h> |
30 | | |
31 | | static void * |
32 | | my_brotli_alloc(void *opaque, size_t size) |
33 | 0 | { |
34 | 0 | return fz_malloc_no_throw((fz_context *)opaque, size); |
35 | 0 | } |
36 | | |
37 | | static void |
38 | | my_brotli_free(void *opaque, void *ptr) |
39 | 0 | { |
40 | 0 | fz_free((fz_context *)opaque, ptr); |
41 | 0 | } |
42 | | |
43 | | void fz_compress_brotli(fz_context *ctx, unsigned char *dest, size_t *dest_len, const unsigned char *source, size_t source_len, fz_brotli_level level) |
44 | 0 | { |
45 | 0 | int ok; |
46 | 0 | BrotliEncoderState *enc_state; |
47 | 0 | unsigned char *outp = dest; |
48 | 0 | size_t avail_out = *dest_len; |
49 | |
|
50 | 0 | enc_state = BrotliEncoderCreateInstance(my_brotli_alloc, my_brotli_free, ctx); |
51 | |
|
52 | 0 | if (!BrotliEncoderSetParameter(enc_state, BROTLI_PARAM_QUALITY, level)) |
53 | 0 | { |
54 | 0 | BrotliEncoderDestroyInstance(enc_state); |
55 | 0 | fz_throw(ctx, FZ_ERROR_LIBRARY, "Brotli compression failed"); |
56 | 0 | } |
57 | | |
58 | 0 | do { |
59 | 0 | ok = BrotliEncoderCompressStream(enc_state, |
60 | 0 | (source_len > 0 ? BROTLI_OPERATION_PROCESS : BROTLI_OPERATION_FINISH), |
61 | 0 | &source_len, |
62 | 0 | &source, |
63 | 0 | &avail_out, |
64 | 0 | &outp, |
65 | 0 | NULL); |
66 | 0 | } while (ok && !BrotliEncoderIsFinished(enc_state)); |
67 | |
|
68 | 0 | if (!ok) |
69 | 0 | { |
70 | 0 | BrotliEncoderDestroyInstance(enc_state); |
71 | 0 | fz_throw(ctx, FZ_ERROR_LIBRARY, "Brotli compression failed"); |
72 | 0 | } |
73 | 0 | *dest_len = outp - dest; |
74 | |
|
75 | 0 | BrotliEncoderDestroyInstance(enc_state); |
76 | 0 | } |
77 | | |
78 | | unsigned char *fz_new_brotli_data(fz_context *ctx, size_t *compressed_length, const unsigned char *source, size_t source_length, fz_brotli_level level) |
79 | 0 | { |
80 | 0 | size_t bound = fz_brotli_bound(ctx, source_length); |
81 | 0 | unsigned char *cdata = Memento_label(fz_malloc(ctx, bound), "brotli_data"); |
82 | 0 | *compressed_length = 0; |
83 | |
|
84 | 0 | fz_try(ctx) |
85 | 0 | fz_compress_brotli(ctx, cdata, &bound, source, source_length, level); |
86 | 0 | fz_catch(ctx) |
87 | 0 | { |
88 | 0 | fz_free(ctx, cdata); |
89 | 0 | fz_rethrow(ctx); |
90 | 0 | } |
91 | | |
92 | 0 | *compressed_length = bound; |
93 | 0 | return cdata; |
94 | 0 | } |
95 | | |
96 | | unsigned char *fz_new_brotli_data_from_buffer(fz_context *ctx, size_t *compressed_length, fz_buffer *buffer, fz_brotli_level level) |
97 | 0 | { |
98 | 0 | unsigned char *data; |
99 | 0 | size_t size = fz_buffer_storage(ctx, buffer, &data); |
100 | |
|
101 | 0 | if (size == 0 || data == NULL) |
102 | 0 | { |
103 | 0 | *compressed_length = 0; |
104 | 0 | return NULL; |
105 | 0 | } |
106 | | |
107 | 0 | return fz_new_brotli_data(ctx, compressed_length, data, size, level); |
108 | 0 | } |
109 | | |
110 | | size_t fz_brotli_bound(fz_context *ctx, size_t size) |
111 | 0 | { |
112 | 0 | return BrotliEncoderMaxCompressedSize(size); |
113 | 0 | } |
114 | | |
115 | | #else |
116 | | |
117 | | size_t fz_brotli_bound(fz_context *ctx, size_t size) |
118 | | { |
119 | | return size; |
120 | | } |
121 | | |
122 | | void fz_compress_brotli(fz_context *ctx, unsigned char *dest, size_t *dest_len, const unsigned char *source, size_t source_len, fz_brotli_level level) |
123 | | { |
124 | | fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "brotli compression not enabled"); |
125 | | } |
126 | | |
127 | | unsigned char *fz_new_brotli_data_from_buffer(fz_context *ctx, size_t *compressed_length, fz_buffer *buffer, fz_brotli_level level) |
128 | | { |
129 | | fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "brotli compression not enabled"); |
130 | | return NULL; |
131 | | } |
132 | | |
133 | | unsigned char *fz_new_brotli_data(fz_context *ctx, size_t *compressed_length, const unsigned char *source, size_t source_length, fz_brotli_level level) |
134 | | { |
135 | | fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "brotli compression not enabled"); |
136 | | return NULL; |
137 | | } |
138 | | |
139 | | #endif |