Coverage Report

Created: 2025-10-13 06:21

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
10.9k
static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
44
10.9k
  if (config->input.has_animation) {
45
0
    fprintf(stderr,
46
0
            "Error! Decoding of an animated WebP file is not supported.\n"
47
0
            "       Use webpmux to extract the individual frames or\n"
48
0
            "       vwebp to view this image.\n");
49
0
  }
50
10.9k
}
51
52
7.67k
void PrintWebPError(const char* const in_file, int status) {
53
7.67k
  WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file);
54
7.67k
  fprintf(stderr, "Status: %d", status);
55
7.67k
  if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
56
7.67k
    fprintf(stderr, "(%s)", kStatusMessages[status]);
57
7.67k
  }
58
7.67k
  fprintf(stderr, "\n");
59
7.67k
}
60
61
int LoadWebP(const char* const in_file, const uint8_t** data, size_t* data_size,
62
0
             WebPBitstreamFeatures* bitstream) {
63
0
  VP8StatusCode status;
64
0
  WebPBitstreamFeatures local_features;
65
0
  if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0;
66
67
0
  if (bitstream == NULL) {
68
0
    bitstream = &local_features;
69
0
  }
70
71
0
  status = WebPGetFeatures(*data, *data_size, bitstream);
72
0
  if (status != VP8_STATUS_OK) {
73
0
    WebPFree((void*)*data);
74
0
    *data = NULL;
75
0
    *data_size = 0;
76
0
    PrintWebPError(in_file, status);
77
0
    return 0;
78
0
  }
79
0
  return 1;
80
0
}
81
82
//------------------------------------------------------------------------------
83
84
VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size,
85
10.9k
                         WebPDecoderConfig* const config) {
86
10.9k
  if (config == NULL) return VP8_STATUS_INVALID_PARAM;
87
10.9k
  PrintAnimationWarning(config);
88
10.9k
  return WebPDecode(data, data_size, config);
89
10.9k
}
90
91
VP8StatusCode DecodeWebPIncremental(const uint8_t* const data, size_t data_size,
92
0
                                    WebPDecoderConfig* const config) {
93
0
  VP8StatusCode status = VP8_STATUS_OK;
94
0
  if (config == NULL) return VP8_STATUS_INVALID_PARAM;
95
96
0
  PrintAnimationWarning(config);
97
98
  // Decoding call.
99
0
  {
100
0
    WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
101
0
    if (idec == NULL) {
102
0
      fprintf(stderr, "Failed during WebPIDecode().\n");
103
0
      return VP8_STATUS_OUT_OF_MEMORY;
104
0
    } else {
105
0
      status = WebPIUpdate(idec, data, data_size);
106
0
      WebPIDelete(idec);
107
0
    }
108
0
  }
109
0
  return status;
110
0
}
111
112
// -----------------------------------------------------------------------------
113
// Metadata
114
115
static int ExtractMetadata(const uint8_t* const data, size_t data_size,
116
1.37k
                           Metadata* const metadata) {
117
1.37k
  WebPData webp_data = {data, data_size};
118
1.37k
  WebPDemuxer* const demux = WebPDemux(&webp_data);
119
1.37k
  WebPChunkIterator chunk_iter;
120
1.37k
  uint32_t flags;
121
122
1.37k
  if (demux == NULL) return 0;
123
1.37k
  assert(metadata != NULL);
124
125
235
  flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
126
127
235
  if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) {
128
0
    MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
129
0
                 &metadata->iccp);
130
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
131
0
  }
132
235
  if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) {
133
0
    MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
134
0
                 &metadata->exif);
135
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
136
0
  }
137
235
  if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) {
138
0
    MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size,
139
0
                 &metadata->xmp);
140
0
    WebPDemuxReleaseChunkIterator(&chunk_iter);
141
0
  }
142
235
  WebPDemuxDelete(demux);
143
235
  return 1;
144
1.37k
}
145
146
// -----------------------------------------------------------------------------
147
148
int ReadWebP(const uint8_t* const data, size_t data_size,
149
12.0k
             WebPPicture* const pic, int keep_alpha, Metadata* const metadata) {
150
12.0k
  int ok = 0;
151
12.0k
  VP8StatusCode status = VP8_STATUS_OK;
152
12.0k
  WebPDecoderConfig config;
153
12.0k
  WebPDecBuffer* const output_buffer = &config.output;
154
12.0k
  WebPBitstreamFeatures* const bitstream = &config.input;
155
156
12.0k
  if (data == NULL || data_size == 0 || pic == NULL) return 0;
157
158
12.0k
  if (!WebPInitDecoderConfig(&config)) {
159
0
    fprintf(stderr, "Library version mismatch!\n");
160
0
    return 0;
161
0
  }
162
163
12.0k
  status = WebPGetFeatures(data, data_size, bitstream);
164
12.0k
  if (status != VP8_STATUS_OK) {
165
186
    PrintWebPError("input data", status);
166
186
    return 0;
167
186
  }
168
169
11.8k
  do {
170
11.8k
    const int has_alpha = keep_alpha && bitstream->has_alpha;
171
11.8k
    uint64_t stride;
172
11.8k
    pic->width = bitstream->width;
173
11.8k
    pic->height = bitstream->height;
174
11.8k
    if (pic->use_argb) {
175
5.86k
      stride = (uint64_t)bitstream->width * 4;
176
5.96k
    } else {
177
5.96k
      stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2;
178
5.96k
      pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
179
5.96k
    }
180
181
11.8k
    if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) {
182
5
      status = VP8_STATUS_OUT_OF_MEMORY;
183
5
      break;
184
5
    }
185
186
11.8k
    ok = WebPPictureAlloc(pic);
187
11.8k
    if (!ok) {
188
865
      status = VP8_STATUS_OUT_OF_MEMORY;
189
865
      break;
190
865
    }
191
10.9k
    if (pic->use_argb) {
192
#ifdef WORDS_BIGENDIAN
193
      output_buffer->colorspace = MODE_ARGB;
194
#else
195
5.44k
      output_buffer->colorspace = MODE_BGRA;
196
5.44k
#endif
197
5.44k
      output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb;
198
5.44k
      output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t);
199
5.44k
      output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height;
200
5.51k
    } else {
201
5.51k
      output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV;
202
5.51k
      output_buffer->u.YUVA.y = pic->y;
203
5.51k
      output_buffer->u.YUVA.u = pic->u;
204
5.51k
      output_buffer->u.YUVA.v = pic->v;
205
5.51k
      output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL;
206
5.51k
      output_buffer->u.YUVA.y_stride = pic->y_stride;
207
5.51k
      output_buffer->u.YUVA.u_stride = pic->uv_stride;
208
5.51k
      output_buffer->u.YUVA.v_stride = pic->uv_stride;
209
5.51k
      output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0;
210
5.51k
      output_buffer->u.YUVA.y_size = pic->height * pic->y_stride;
211
5.51k
      output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride;
212
5.51k
      output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride;
213
5.51k
      output_buffer->u.YUVA.a_size = pic->height * pic->a_stride;
214
5.51k
    }
215
10.9k
    output_buffer->is_external_memory = 1;
216
217
10.9k
    status = DecodeWebP(data, data_size, &config);
218
10.9k
    ok = (status == VP8_STATUS_OK);
219
10.9k
    if (ok && !keep_alpha && pic->use_argb) {
220
      // Need to wipe out the alpha value, as requested.
221
286
      int x, y;
222
286
      uint32_t* argb = pic->argb;
223
227k
      for (y = 0; y < pic->height; ++y) {
224
339M
        for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u;
225
227k
        argb += pic->argb_stride;
226
227k
      }
227
286
    }
228
10.9k
  } while (0);  // <- so we can 'break' out of the loop
229
230
11.8k
  if (status != VP8_STATUS_OK) {
231
6.34k
    PrintWebPError("input data", status);
232
6.34k
    ok = 0;
233
6.34k
  }
234
235
11.8k
  WebPFreeDecBuffer(output_buffer);
236
237
11.8k
  if (ok && metadata != NULL) {
238
1.37k
    ok = ExtractMetadata(data, data_size, metadata);
239
1.37k
    if (!ok) {
240
1.14k
      PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR);
241
1.14k
    }
242
1.37k
  }
243
11.8k
  if (!ok) WebPPictureFree(pic);
244
11.8k
  return ok;
245
12.0k
}
246
247
// -----------------------------------------------------------------------------