Coverage Report

Created: 2026-10-10 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/imageio/webpdec.c
Line
Count
Source
1
// Copyright 2014 Google Inc. All Rights Reserved.
2
//
3
// Use of this source code is governed by a BSD-style license
4
// that can be found in the COPYING file in the root of the source
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// WebP decode.
11
12
#ifdef HAVE_CONFIG_H
13
#include "webp/config.h"
14
#endif
15
16
#include <assert.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
20
#include "../examples/unicode.h"
21
#include "./imageio_util.h"
22
#include "./metadata.h"
23
#include "./webpdec.h"
24
#include "webp/decode.h"
25
#include "webp/demux.h"
26
#include "webp/encode.h"
27
#include "webp/mux_types.h"
28
#include "webp/types.h"
29
30
//------------------------------------------------------------------------------
31
// WebP decoding
32
33
static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
34
    "OK",
35
    "OUT_OF_MEMORY",
36
    "INVALID_PARAM",
37
    "BITSTREAM_ERROR",
38
    "UNSUPPORTED_FEATURE",
39
    "SUSPENDED",
40
    "USER_ABORT",
41
    "NOT_ENOUGH_DATA"};
42
43
5.12k
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
44
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
45
  if (config->input.has_animation) {
46
    fprintf(stderr,
47
            "Error! Decoding of an animated WebP file is not supported.\n"
48
            "       Use webpmux to extract the individual frames or\n"
49
            "       vwebp to view this image.\n");
50
  }
51
#else
52
5.12k
  (void)config;
53
5.12k
#endif
54
5.12k
}
55
56
5.60k
void PrintWebPError(const char* const in_file, int status) {
57
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
58
  WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file);
59
  fprintf(stderr, "Status: %d", status);
60
  if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
61
    fprintf(stderr, "(%s)", kStatusMessages[status]);
62
  }
63
  fprintf(stderr, "\n");
64
#else
65
5.60k
  (void)in_file;
66
5.60k
  (void)status;
67
5.60k
#endif
68
5.60k
}
69
70
int LoadWebP(const char* const in_file, const uint8_t** data, size_t* data_size,
71
0
             WebPBitstreamFeatures* bitstream) {
72
0
  VP8StatusCode status;
73
0
  WebPBitstreamFeatures local_features;
74
0
  if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
75
76
0
  if (bitstream == NULL) {
77
0
    bitstream = &local_features;
78
0
  }
79
80
0
  status = WebPGetFeatures(*data, *data_size, bitstream);
81
0
  if (status != VP8_STATUS_OK) {
82
0
    WebPFree((void*)*data);
83
0
    *data = NULL;
84
0
    *data_size = 0;
85
0
    PrintWebPError(in_file, status);
86
0
    return 0;
87
0
  }
88
0
  return 1;
89
0
}
90
91
//------------------------------------------------------------------------------
92
93
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
94
5.12k
                         WebPDecoderConfig* const config) {
95
5.12k
  if (config == NULL) return VP8_STATUS_INVALID_PARAM;
96
5.12k
  PrintAnimationWarning(config);
97
5.12k
  return WebPDecode(data, data_size, config);
98
5.12k
}
99
100
VP8StatusCode DecodeWebPIncremental(const uint8_t* const data, size_t data_size,
101
0
                                    WebPDecoderConfig* const config) {
102
0
  VP8StatusCode status = VP8_STATUS_OK;
103
0
  if (config == NULL) return VP8_STATUS_INVALID_PARAM;
104
105
0
  PrintAnimationWarning(config);
106
107
  // Decoding call.
108
0
  {
109
0
    WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
110
0
    if (idec == NULL) {
111
0
      fprintf(stderr, "Failed during WebPIDecode().\n");
112
0
      return VP8_STATUS_OUT_OF_MEMORY;
113
0
    } else {
114
0
      status = WebPIUpdate(idec, data, data_size);
115
0
      WebPIDelete(idec);
116
0
    }
117
0
  }
118
0
  return status;
119
0
}
120
121
// -----------------------------------------------------------------------------
122
// Metadata
123
124
static int ExtractMetadata(const uint8_t* const data, size_t data_size,
125
1.26k
                           Metadata* const metadata) {
126
1.26k
  WebPData webp_data = {data, data_size};
127
1.26k
  WebPDemuxer* const demux = WebPDemux(&webp_data);
128
1.26k
  WebPChunkIterator chunk_iter;
129
1.26k
  uint32_t flags;
130
1.26k
  int ok = 1;
131
132
1.26k
  if (demux == NULL) return 0;
133
1.26k
  assert(metadata != NULL);
134
135
319
  flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
136
137
319
  if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
138
0
    ok = ok && MetadataCopy((const char*)chunk_iter.chunk.bytes,
139
0
                            chunk_iter.chunk.size, &metadata->iccp);
140
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
141
0
  }
142
319
  if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
143
0
    ok = ok && MetadataCopy((const char*)chunk_iter.chunk.bytes,
144
0
                            chunk_iter.chunk.size, &metadata->exif);
145
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
146
0
  }
147
319
  if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
148
0
    ok = ok && MetadataCopy((const char*)chunk_iter.chunk.bytes,
149
0
                            chunk_iter.chunk.size, &metadata->xmp);
150
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
151
0
  }
152
319
  WebPDemuxDelete(demux);
153
319
  return ok;
154
1.26k
}
155
156
// -----------------------------------------------------------------------------
157
158
int ReadWebP(const uint8_t* const data, size_t data_size,
159
5.92k
             WebPPicture* const pic, int keep_alpha, Metadata* const metadata) {
160
5.92k
  int ok = 0;
161
5.92k
  VP8StatusCode status = VP8_STATUS_OK;
162
5.92k
  WebPDecoderConfig config;
163
5.92k
  WebPDecBuffer* const output_buffer = &config.output;
164
5.92k
  WebPBitstreamFeatures* const bitstream = &config.input;
165
166
5.92k
  if (data == NULL || data_size == 0 || pic == NULL) return 0;
167
168
5.92k
  if (!WebPInitDecoderConfig(&config)) {
169
0
    fprintf(stderr, "Library version mismatch!\n");
170
0
    return 0;
171
0
  }
172
173
5.92k
  status = WebPGetFeatures(data, data_size, bitstream);
174
5.92k
  if (status != VP8_STATUS_OK) {
175
370
    PrintWebPError("input data", status);
176
370
    return 0;
177
370
  }
178
179
5.55k
  do {
180
5.55k
    const int has_alpha = keep_alpha && bitstream->has_alpha;
181
5.55k
    uint64_t stride;
182
5.55k
    pic->width = bitstream->width;
183
5.55k
    pic->height = bitstream->height;
184
5.55k
    if (pic->use_argb) {
185
2.81k
      stride = (uint64_t)bitstream->width * 4;
186
2.81k
    } else {
187
2.73k
      stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
188
2.73k
      pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
189
2.73k
    }
190
191
5.55k
    if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
192
0
      status = VP8_STATUS_OUT_OF_MEMORY;
193
0
      break;
194
0
    }
195
196
5.55k
    ok = WebPPictureAlloc(pic);
197
5.55k
    if (!ok) {
198
428
      status = VP8_STATUS_OUT_OF_MEMORY;
199
428
      break;
200
428
    }
201
5.12k
    if (pic->use_argb) {
202
#ifdef WORDS_BIGENDIAN
203
      output_buffer->colorspace = MODE_ARGB;
204
#else
205
2.61k
      output_buffer->colorspace = MODE_BGRA;
206
2.61k
#endif
207
2.61k
      output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
208
2.61k
      output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
209
2.61k
      output_buffer->u.RGBA.size =
210
2.61k
          (size_t)output_buffer->u.RGBA.stride * pic->height;
211
2.61k
    } else {
212
2.50k
      output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
213
2.50k
      output_buffer->u.YUVA.y = pic->y;
214
2.50k
      output_buffer->u.YUVA.u = pic->u;
215
2.50k
      output_buffer->u.YUVA.v = pic->v;
216
2.50k
      output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL;
217
2.50k
      output_buffer->u.YUVA.y_stride = pic->y_stride;
218
2.50k
      output_buffer->u.YUVA.u_stride = pic->uv_stride;
219
2.50k
      output_buffer->u.YUVA.v_stride = pic->uv_stride;
220
2.50k
      output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0;
221
2.50k
      output_buffer->u.YUVA.y_size = (size_t)pic->height * pic->y_stride;
222
2.50k
      output_buffer->u.YUVA.u_size =
223
2.50k
          (size_t)(pic->height + 1) / 2 * pic->uv_stride;
224
2.50k
      output_buffer->u.YUVA.v_size =
225
2.50k
          (size_t)(pic->height + 1) / 2 * pic->uv_stride;
226
2.50k
      output_buffer->u.YUVA.a_size = (size_t)pic->height * pic->a_stride;
227
2.50k
    }
228
5.12k
    output_buffer->is_external_memory = 1;
229
230
5.12k
    status = DecodeWebP(data, data_size, &config);
231
5.12k
    ok = (status == VP8_STATUS_OK);
232
5.12k
    if (ok && !keep_alpha && pic->use_argb) {
233
      // Need to wipe out the alpha value, as requested.
234
286
      int x, y;
235
286
      uint32_t* argb = pic->argb;
236
264k
      for (y = 0; y < pic->height; ++y) {
237
4.98M
        for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
238
264k
        argb += pic->argb_stride;
239
264k
      }
240
286
    }
241
5.12k
  } while (0);  // <- so we can 'break' out of the loop
242
243
5.55k
  if (status != VP8_STATUS_OK) {
244
4.28k
    PrintWebPError("input data", status);
245
4.28k
    ok = 0;
246
4.28k
  }
247
248
5.55k
  WebPFreeDecBuffer(output_buffer);
249
250
5.55k
  if (ok && metadata != NULL) {
251
1.26k
    ok = ExtractMetadata(data, data_size, metadata);
252
1.26k
    if (!ok) {
253
943
      PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
254
943
    }
255
1.26k
  }
256
5.55k
  if (!ok) WebPPictureFree(pic);
257
5.55k
  return ok;
258
5.92k
}
259
260
// -----------------------------------------------------------------------------