Coverage Report

Created: 2025-12-31 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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