Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1177)

Side by Side Diff: third_party/libwebp/demux/demux.c

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/libwebp/dec/webpi.h ('k') | third_party/libwebp/dsp/cpu.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 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 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 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // WebP container demux. 10 // WebP container demux.
11 // 11 //
12 12
13 #ifdef HAVE_CONFIG_H 13 #ifdef HAVE_CONFIG_H
14 #include "config.h" 14 #include "config.h"
15 #endif 15 #endif
16 16
17 #include <assert.h> 17 #include <assert.h>
18 #include <stdlib.h> 18 #include <stdlib.h>
19 #include <string.h> 19 #include <string.h>
20 20
21 #include "../utils/utils.h" 21 #include "../utils/utils.h"
22 #include "../webp/decode.h" // WebPGetFeatures 22 #include "../webp/decode.h" // WebPGetFeatures
23 #include "../webp/demux.h" 23 #include "../webp/demux.h"
24 #include "../webp/format_constants.h" 24 #include "../webp/format_constants.h"
25 25
26 #if defined(__cplusplus) || defined(c_plusplus)
27 extern "C" {
28 #endif
29
30 #define DMUX_MAJ_VERSION 0 26 #define DMUX_MAJ_VERSION 0
31 #define DMUX_MIN_VERSION 1 27 #define DMUX_MIN_VERSION 2
32 #define DMUX_REV_VERSION 1 28 #define DMUX_REV_VERSION 0
33 29
34 typedef struct { 30 typedef struct {
35 size_t start_; // start location of the data 31 size_t start_; // start location of the data
36 size_t end_; // end location 32 size_t end_; // end location
37 size_t riff_end_; // riff chunk end location, can be > end_. 33 size_t riff_end_; // riff chunk end location, can be > end_.
38 size_t buf_size_; // size of the buffer 34 size_t buf_size_; // size of the buffer
39 const uint8_t* buf_; 35 const uint8_t* buf_;
40 } MemBuffer; 36 } MemBuffer;
41 37
42 typedef struct { 38 typedef struct {
(...skipping 25 matching lines...) Expand all
68 WebPDemuxState state_; 64 WebPDemuxState state_;
69 int is_ext_format_; 65 int is_ext_format_;
70 uint32_t feature_flags_; 66 uint32_t feature_flags_;
71 int canvas_width_, canvas_height_; 67 int canvas_width_, canvas_height_;
72 int loop_count_; 68 int loop_count_;
73 uint32_t bgcolor_; 69 uint32_t bgcolor_;
74 int num_frames_; 70 int num_frames_;
75 Frame* frames_; 71 Frame* frames_;
76 Frame** frames_tail_; 72 Frame** frames_tail_;
77 Chunk* chunks_; // non-image chunks 73 Chunk* chunks_; // non-image chunks
74 Chunk** chunks_tail_;
78 }; 75 };
79 76
80 typedef enum { 77 typedef enum {
81 PARSE_OK, 78 PARSE_OK,
82 PARSE_NEED_MORE_DATA, 79 PARSE_NEED_MORE_DATA,
83 PARSE_ERROR 80 PARSE_ERROR
84 } ParseStatus; 81 } ParseStatus;
85 82
86 typedef struct ChunkParser { 83 typedef struct ChunkParser {
87 uint8_t id[4]; 84 uint8_t id[4];
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 const uint8_t* const data = mem->buf_ + mem->start_; 169 const uint8_t* const data = mem->buf_ + mem->start_;
173 const uint32_t val = GetLE32(data); 170 const uint32_t val = GetLE32(data);
174 Skip(mem, 4); 171 Skip(mem, 4);
175 return val; 172 return val;
176 } 173 }
177 174
178 // ----------------------------------------------------------------------------- 175 // -----------------------------------------------------------------------------
179 // Secondary chunk parsing 176 // Secondary chunk parsing
180 177
181 static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { 178 static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
182 Chunk** c = &dmux->chunks_; 179 *dmux->chunks_tail_ = chunk;
183 while (*c != NULL) c = &(*c)->next_;
184 *c = chunk;
185 chunk->next_ = NULL; 180 chunk->next_ = NULL;
181 dmux->chunks_tail_ = &chunk->next_;
186 } 182 }
187 183
188 // Add a frame to the end of the list, ensuring the last frame is complete. 184 // Add a frame to the end of the list, ensuring the last frame is complete.
189 // Returns true on success, false otherwise. 185 // Returns true on success, false otherwise.
190 static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { 186 static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
191 const Frame* const last_frame = *dmux->frames_tail_; 187 const Frame* const last_frame = *dmux->frames_tail_;
192 if (last_frame != NULL && !last_frame->complete_) return 0; 188 if (last_frame != NULL && !last_frame->complete_) return 0;
193 189
194 *dmux->frames_tail_ = frame; 190 *dmux->frames_tail_ = frame;
195 frame->next_ = NULL; 191 frame->next_ = NULL;
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; 290 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
295 291
296 *frame = (Frame*)calloc(1, sizeof(**frame)); 292 *frame = (Frame*)calloc(1, sizeof(**frame));
297 return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; 293 return (*frame == NULL) ? PARSE_ERROR : PARSE_OK;
298 } 294 }
299 295
300 // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. 296 // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow.
301 // 'frame_chunk_size' is the previously validated, padded chunk size. 297 // 'frame_chunk_size' is the previously validated, padded chunk size.
302 static ParseStatus ParseAnimationFrame( 298 static ParseStatus ParseAnimationFrame(
303 WebPDemuxer* const dmux, uint32_t frame_chunk_size) { 299 WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
304 const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); 300 const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
305 const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; 301 const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
306 int added_frame = 0; 302 int added_frame = 0;
307 int bits; 303 int bits;
308 MemBuffer* const mem = &dmux->mem_; 304 MemBuffer* const mem = &dmux->mem_;
309 Frame* frame; 305 Frame* frame;
310 ParseStatus status = 306 ParseStatus status =
311 NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); 307 NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
312 if (status != PARSE_OK) return status; 308 if (status != PARSE_OK) return status;
313 309
314 frame->x_offset_ = 2 * ReadLE24s(mem); 310 frame->x_offset_ = 2 * ReadLE24s(mem);
315 frame->y_offset_ = 2 * ReadLE24s(mem); 311 frame->y_offset_ = 2 * ReadLE24s(mem);
316 frame->width_ = 1 + ReadLE24s(mem); 312 frame->width_ = 1 + ReadLE24s(mem);
317 frame->height_ = 1 + ReadLE24s(mem); 313 frame->height_ = 1 + ReadLE24s(mem);
318 frame->duration_ = ReadLE24s(mem); 314 frame->duration_ = ReadLE24s(mem);
319 bits = ReadByte(mem); 315 bits = ReadByte(mem);
320 frame->dispose_method_ = 316 frame->dispose_method_ =
321 (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; 317 (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
322 frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; 318 frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
323 if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { 319 if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
324 free(frame); 320 free(frame);
325 return PARSE_ERROR; 321 return PARSE_ERROR;
326 } 322 }
327 323
328 // Store a frame only if the animation flag is set there is some data for 324 // Store a frame only if the animation flag is set there is some data for
329 // this frame is available. 325 // this frame is available.
330 status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); 326 status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
331 if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { 327 if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
332 added_frame = AddFrame(dmux, frame); 328 added_frame = AddFrame(dmux, frame);
333 if (added_frame) { 329 if (added_frame) {
334 ++dmux->num_frames_; 330 ++dmux->num_frames_;
335 } else { 331 } else {
336 status = PARSE_ERROR; 332 status = PARSE_ERROR;
337 } 333 }
338 } 334 }
339 335
340 if (!added_frame) free(frame); 336 if (!added_frame) free(frame);
341 return status; 337 return status;
342 } 338 }
343 339
344 #ifdef WEBP_EXPERIMENTAL_FEATURES 340 #ifdef WEBP_EXPERIMENTAL_FEATURES
345 // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow. 341 // Parse a 'FRGM' chunk and any image bearing chunks that immediately follow.
346 // 'fragment_chunk_size' is the previously validated, padded chunk size. 342 // 'fragment_chunk_size' is the previously validated, padded chunk size.
347 static ParseStatus ParseFragment(WebPDemuxer* const dmux, 343 static ParseStatus ParseFragment(WebPDemuxer* const dmux,
348 uint32_t fragment_chunk_size) { 344 uint32_t fragment_chunk_size) {
349 const int frame_num = 1; // All fragments belong to the 1st (and only) frame. 345 const int frame_num = 1; // All fragments belong to the 1st (and only) frame.
350 const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); 346 const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
351 const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE; 347 const uint32_t frgm_payload_size = fragment_chunk_size - FRGM_CHUNK_SIZE;
352 int added_fragment = 0; 348 int added_fragment = 0;
353 MemBuffer* const mem = &dmux->mem_; 349 MemBuffer* const mem = &dmux->mem_;
354 Frame* frame; 350 Frame* frame;
355 ParseStatus status = 351 ParseStatus status =
356 NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame); 352 NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame);
357 if (status != PARSE_OK) return status; 353 if (status != PARSE_OK) return status;
358 354
359 frame->is_fragment_ = 1; 355 frame->is_fragment_ = 1;
360 frame->x_offset_ = 2 * ReadLE24s(mem); 356 frame->x_offset_ = 2 * ReadLE24s(mem);
361 frame->y_offset_ = 2 * ReadLE24s(mem); 357 frame->y_offset_ = 2 * ReadLE24s(mem);
362 358
363 // Store a fragment only if the fragments flag is set there is some data for 359 // Store a fragment only if the 'fragments' flag is set and there is some
364 // this fragment is available. 360 // data available.
365 status = StoreFrame(frame_num, frgm_payload_size, mem, frame); 361 status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
366 if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) { 362 if (status != PARSE_ERROR && is_fragmented && frame->frame_num_ > 0) {
367 added_fragment = AddFrame(dmux, frame); 363 added_fragment = AddFrame(dmux, frame);
368 if (!added_fragment) { 364 if (!added_fragment) {
369 status = PARSE_ERROR; 365 status = PARSE_ERROR;
370 } else { 366 } else {
371 dmux->num_frames_ = 1; 367 dmux->num_frames_ = 1;
372 } 368 }
373 } 369 }
374 370
375 if (!added_fragment) free(frame); 371 if (!added_fragment) free(frame);
376 return status; 372 return status;
(...skipping 11 matching lines...) Expand all
388 384
389 chunk->data_.offset_ = start_offset; 385 chunk->data_.offset_ = start_offset;
390 chunk->data_.size_ = size; 386 chunk->data_.size_ = size;
391 AddChunk(dmux, chunk); 387 AddChunk(dmux, chunk);
392 return 1; 388 return 1;
393 } 389 }
394 390
395 // ----------------------------------------------------------------------------- 391 // -----------------------------------------------------------------------------
396 // Primary chunk parsing 392 // Primary chunk parsing
397 393
398 static int ReadHeader(MemBuffer* const mem) { 394 static ParseStatus ReadHeader(MemBuffer* const mem) {
399 const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE; 395 const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
400 uint32_t riff_size; 396 uint32_t riff_size;
401 397
402 // Basic file level validation. 398 // Basic file level validation.
403 if (MemDataSize(mem) < min_size) return 0; 399 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
404 if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) || 400 if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
405 memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) { 401 memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
406 return 0; 402 return PARSE_ERROR;
407 } 403 }
408 404
409 riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE); 405 riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE);
410 if (riff_size < CHUNK_HEADER_SIZE) return 0; 406 if (riff_size < CHUNK_HEADER_SIZE) return PARSE_ERROR;
411 if (riff_size > MAX_CHUNK_PAYLOAD) return 0; 407 if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
412 408
413 // There's no point in reading past the end of the RIFF chunk 409 // There's no point in reading past the end of the RIFF chunk
414 mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; 410 mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE;
415 if (mem->buf_size_ > mem->riff_end_) { 411 if (mem->buf_size_ > mem->riff_end_) {
416 mem->buf_size_ = mem->end_ = mem->riff_end_; 412 mem->buf_size_ = mem->end_ = mem->riff_end_;
417 } 413 }
418 414
419 Skip(mem, RIFF_HEADER_SIZE); 415 Skip(mem, RIFF_HEADER_SIZE);
420 return 1; 416 return PARSE_OK;
421 } 417 }
422 418
423 static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { 419 static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
424 const size_t min_size = CHUNK_HEADER_SIZE; 420 const size_t min_size = CHUNK_HEADER_SIZE;
425 MemBuffer* const mem = &dmux->mem_; 421 MemBuffer* const mem = &dmux->mem_;
426 Frame* frame; 422 Frame* frame;
427 ParseStatus status; 423 ParseStatus status;
424 int image_added = 0;
428 425
429 if (dmux->frames_ != NULL) return PARSE_ERROR; 426 if (dmux->frames_ != NULL) return PARSE_ERROR;
430 if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; 427 if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
431 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; 428 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
432 429
433 frame = (Frame*)calloc(1, sizeof(*frame)); 430 frame = (Frame*)calloc(1, sizeof(*frame));
434 if (frame == NULL) return PARSE_ERROR; 431 if (frame == NULL) return PARSE_ERROR;
435 432
436 // For the single image case we allow parsing of a partial frame, but we need 433 // For the single image case we allow parsing of a partial frame, but we need
437 // at least CHUNK_HEADER_SIZE for parsing. 434 // at least CHUNK_HEADER_SIZE for parsing.
438 status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame); 435 status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
439 if (status != PARSE_ERROR) { 436 if (status != PARSE_ERROR) {
440 const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); 437 const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
441 // Clear any alpha when the alpha flag is missing. 438 // Clear any alpha when the alpha flag is missing.
442 if (!has_alpha && frame->img_components_[1].size_ > 0) { 439 if (!has_alpha && frame->img_components_[1].size_ > 0) {
443 frame->img_components_[1].offset_ = 0; 440 frame->img_components_[1].offset_ = 0;
444 frame->img_components_[1].size_ = 0; 441 frame->img_components_[1].size_ = 0;
445 frame->has_alpha_ = 0; 442 frame->has_alpha_ = 0;
446 } 443 }
447 444
448 // Use the frame width/height as the canvas values for non-vp8x files. 445 // Use the frame width/height as the canvas values for non-vp8x files.
449 // Also, set ALPHA_FLAG if this is a lossless image with alpha. 446 // Also, set ALPHA_FLAG if this is a lossless image with alpha.
450 if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { 447 if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) {
451 dmux->state_ = WEBP_DEMUX_PARSED_HEADER; 448 dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
452 dmux->canvas_width_ = frame->width_; 449 dmux->canvas_width_ = frame->width_;
453 dmux->canvas_height_ = frame->height_; 450 dmux->canvas_height_ = frame->height_;
454 dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; 451 dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
455 } 452 }
456 AddFrame(dmux, frame); 453 if (!AddFrame(dmux, frame)) {
457 dmux->num_frames_ = 1; 454 status = PARSE_ERROR; // last frame was left incomplete
458 } else { 455 } else {
459 free(frame); 456 image_added = 1;
457 dmux->num_frames_ = 1;
458 }
460 } 459 }
461 460
461 if (!image_added) free(frame);
462 return status; 462 return status;
463 } 463 }
464 464
465 static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { 465 static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
466 const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
466 MemBuffer* const mem = &dmux->mem_; 467 MemBuffer* const mem = &dmux->mem_;
467 int anim_chunks = 0; 468 int anim_chunks = 0;
468 uint32_t vp8x_size;
469 ParseStatus status = PARSE_OK; 469 ParseStatus status = PARSE_OK;
470 470
471 if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
472
473 dmux->is_ext_format_ = 1;
474 Skip(mem, TAG_SIZE); // VP8X
475 vp8x_size = ReadLE32(mem);
476 if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
477 if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR;
478 vp8x_size += vp8x_size & 1;
479 if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
480 if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
481
482 dmux->feature_flags_ = ReadByte(mem);
483 Skip(mem, 3); // Reserved.
484 dmux->canvas_width_ = 1 + ReadLE24s(mem);
485 dmux->canvas_height_ = 1 + ReadLE24s(mem);
486 if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
487 return PARSE_ERROR; // image final dimension is too large
488 }
489 Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
490 dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
491
492 if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
493 if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
494
495 do { 471 do {
496 int store_chunk = 1; 472 int store_chunk = 1;
497 const size_t chunk_start_offset = mem->start_; 473 const size_t chunk_start_offset = mem->start_;
498 const uint32_t fourcc = ReadLE32(mem); 474 const uint32_t fourcc = ReadLE32(mem);
499 const uint32_t chunk_size = ReadLE32(mem); 475 const uint32_t chunk_size = ReadLE32(mem);
500 const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1); 476 const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
501 477
502 if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; 478 if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
503 if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; 479 if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
504 480
505 switch (fourcc) { 481 switch (fourcc) {
506 case MKFOURCC('V', 'P', '8', 'X'): { 482 case MKFOURCC('V', 'P', '8', 'X'): {
507 return PARSE_ERROR; 483 return PARSE_ERROR;
508 } 484 }
509 case MKFOURCC('A', 'L', 'P', 'H'): 485 case MKFOURCC('A', 'L', 'P', 'H'):
510 case MKFOURCC('V', 'P', '8', ' '): 486 case MKFOURCC('V', 'P', '8', ' '):
511 case MKFOURCC('V', 'P', '8', 'L'): { 487 case MKFOURCC('V', 'P', '8', 'L'): {
512 const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
513 // check that this isn't an animation (all frames should be in an ANMF). 488 // check that this isn't an animation (all frames should be in an ANMF).
514 if (anim_chunks > 0 || has_frames) return PARSE_ERROR; 489 if (anim_chunks > 0 || is_animation) return PARSE_ERROR;
515 490
516 Rewind(mem, CHUNK_HEADER_SIZE); 491 Rewind(mem, CHUNK_HEADER_SIZE);
517 status = ParseSingleImage(dmux); 492 status = ParseSingleImage(dmux);
518 break; 493 break;
519 } 494 }
520 case MKFOURCC('A', 'N', 'I', 'M'): { 495 case MKFOURCC('A', 'N', 'I', 'M'): {
521 if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR; 496 if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR;
522 497
523 if (MemDataSize(mem) < chunk_size_padded) { 498 if (MemDataSize(mem) < chunk_size_padded) {
524 status = PARSE_NEED_MORE_DATA; 499 status = PARSE_NEED_MORE_DATA;
(...skipping 16 matching lines...) Expand all
541 #ifdef WEBP_EXPERIMENTAL_FEATURES 516 #ifdef WEBP_EXPERIMENTAL_FEATURES
542 case MKFOURCC('F', 'R', 'G', 'M'): { 517 case MKFOURCC('F', 'R', 'G', 'M'): {
543 status = ParseFragment(dmux, chunk_size_padded); 518 status = ParseFragment(dmux, chunk_size_padded);
544 break; 519 break;
545 } 520 }
546 #endif 521 #endif
547 case MKFOURCC('I', 'C', 'C', 'P'): { 522 case MKFOURCC('I', 'C', 'C', 'P'): {
548 store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); 523 store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
549 goto Skip; 524 goto Skip;
550 } 525 }
526 case MKFOURCC('E', 'X', 'I', 'F'): {
527 store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
528 goto Skip;
529 }
551 case MKFOURCC('X', 'M', 'P', ' '): { 530 case MKFOURCC('X', 'M', 'P', ' '): {
552 store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); 531 store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
553 goto Skip; 532 goto Skip;
554 } 533 }
555 case MKFOURCC('E', 'X', 'I', 'F'): {
556 store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
557 goto Skip;
558 }
559 Skip: 534 Skip:
560 default: { 535 default: {
561 if (chunk_size_padded <= MemDataSize(mem)) { 536 if (chunk_size_padded <= MemDataSize(mem)) {
562 if (store_chunk) { 537 if (store_chunk) {
563 // Store only the chunk header and unpadded size as only the payload 538 // Store only the chunk header and unpadded size as only the payload
564 // will be returned to the user. 539 // will be returned to the user.
565 if (!StoreChunk(dmux, chunk_start_offset, 540 if (!StoreChunk(dmux, chunk_start_offset,
566 CHUNK_HEADER_SIZE + chunk_size)) { 541 CHUNK_HEADER_SIZE + chunk_size)) {
567 return PARSE_ERROR; 542 return PARSE_ERROR;
568 } 543 }
569 } 544 }
570 Skip(mem, chunk_size_padded); 545 Skip(mem, chunk_size_padded);
571 } else { 546 } else {
572 status = PARSE_NEED_MORE_DATA; 547 status = PARSE_NEED_MORE_DATA;
573 } 548 }
574 } 549 }
575 } 550 }
576 551
577 if (mem->start_ == mem->riff_end_) { 552 if (mem->start_ == mem->riff_end_) {
578 break; 553 break;
579 } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { 554 } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
580 status = PARSE_NEED_MORE_DATA; 555 status = PARSE_NEED_MORE_DATA;
581 } 556 }
582 } while (status == PARSE_OK); 557 } while (status == PARSE_OK);
583 558
584 return status; 559 return status;
585 } 560 }
586 561
562 static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
563 MemBuffer* const mem = &dmux->mem_;
564 uint32_t vp8x_size;
565
566 if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
567
568 dmux->is_ext_format_ = 1;
569 Skip(mem, TAG_SIZE); // VP8X
570 vp8x_size = ReadLE32(mem);
571 if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
572 if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR;
573 vp8x_size += vp8x_size & 1;
574 if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
575 if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
576
577 dmux->feature_flags_ = ReadByte(mem);
578 Skip(mem, 3); // Reserved.
579 dmux->canvas_width_ = 1 + ReadLE24s(mem);
580 dmux->canvas_height_ = 1 + ReadLE24s(mem);
581 if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
582 return PARSE_ERROR; // image final dimension is too large
583 }
584 Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
585 dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
586
587 if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
588 if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
589
590 return ParseVP8XChunks(dmux);
591 }
592
587 // ----------------------------------------------------------------------------- 593 // -----------------------------------------------------------------------------
588 // Format validation 594 // Format validation
589 595
590 static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { 596 static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
591 const Frame* const frame = dmux->frames_; 597 const Frame* const frame = dmux->frames_;
592 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; 598 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
593 599
594 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; 600 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
595 if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; 601 if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0;
596 602
(...skipping 16 matching lines...) Expand all
613 } 619 }
614 } else { 620 } else {
615 if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0; 621 if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0;
616 if (frame->width_ + frame->x_offset_ > canvas_width) return 0; 622 if (frame->width_ + frame->x_offset_ > canvas_width) return 0;
617 if (frame->height_ + frame->y_offset_ > canvas_height) return 0; 623 if (frame->height_ + frame->y_offset_ > canvas_height) return 0;
618 } 624 }
619 return 1; 625 return 1;
620 } 626 }
621 627
622 static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { 628 static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
623 const int has_fragments = !!(dmux->feature_flags_ & FRAGMENTS_FLAG); 629 const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
624 const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); 630 const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
625 const Frame* f = dmux->frames_; 631 const Frame* f = dmux->frames_;
626 632
627 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; 633 if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
628 634
629 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; 635 if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
630 if (dmux->loop_count_ < 0) return 0; 636 if (dmux->loop_count_ < 0) return 0;
631 if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; 637 if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
632 #ifndef WEBP_EXPERIMENTAL_FEATURES 638 #ifndef WEBP_EXPERIMENTAL_FEATURES
633 if (has_fragments) return 0; 639 if (is_fragmented) return 0;
634 #endif 640 #endif
635 641
636 while (f != NULL) { 642 while (f != NULL) {
637 const int cur_frame_set = f->frame_num_; 643 const int cur_frame_set = f->frame_num_;
638 int frame_count = 0, fragment_count = 0; 644 int frame_count = 0, fragment_count = 0;
639 645
640 // Check frame properties and if the image is composed of fragments that 646 // Check frame properties and if the image is composed of fragments that
641 // each fragment came from a fragment. 647 // each fragment came from a fragment.
642 for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { 648 for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
643 const ChunkData* const image = f->img_components_; 649 const ChunkData* const image = f->img_components_;
644 const ChunkData* const alpha = f->img_components_ + 1; 650 const ChunkData* const alpha = f->img_components_ + 1;
645 651
646 if (has_fragments && !f->is_fragment_) return 0; 652 if (is_fragmented && !f->is_fragment_) return 0;
647 if (!has_fragments && f->is_fragment_) return 0; 653 if (!is_fragmented && f->is_fragment_) return 0;
648 if (!has_frames && f->frame_num_ > 1) return 0; 654 if (!is_animation && f->frame_num_ > 1) return 0;
649 655
650 if (f->complete_) { 656 if (f->complete_) {
651 if (alpha->size_ == 0 && image->size_ == 0) return 0; 657 if (alpha->size_ == 0 && image->size_ == 0) return 0;
652 // Ensure alpha precedes image bitstream. 658 // Ensure alpha precedes image bitstream.
653 if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { 659 if (alpha->size_ > 0 && alpha->offset_ > image->offset_) {
654 return 0; 660 return 0;
655 } 661 }
656 662
657 if (f->width_ <= 0 || f->height_ <= 0) return 0; 663 if (f->width_ <= 0 || f->height_ <= 0) return 0;
658 } else { 664 } else {
659 // There shouldn't be a partial frame in a complete file. 665 // There shouldn't be a partial frame in a complete file.
660 if (dmux->state_ == WEBP_DEMUX_DONE) return 0; 666 if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
661 667
662 // Ensure alpha precedes image bitstream. 668 // Ensure alpha precedes image bitstream.
663 if (alpha->size_ > 0 && image->size_ > 0 && 669 if (alpha->size_ > 0 && image->size_ > 0 &&
664 alpha->offset_ > image->offset_) { 670 alpha->offset_ > image->offset_) {
665 return 0; 671 return 0;
666 } 672 }
667 // There shouldn't be any frames after an incomplete one. 673 // There shouldn't be any frames after an incomplete one.
668 if (f->next_ != NULL) return 0; 674 if (f->next_ != NULL) return 0;
669 } 675 }
670 676
671 if (f->width_ > 0 && f->height_ > 0 && 677 if (f->width_ > 0 && f->height_ > 0 &&
672 !CheckFrameBounds(f, !(has_frames || has_fragments), 678 !CheckFrameBounds(f, !(is_animation || is_fragmented),
673 dmux->canvas_width_, dmux->canvas_height_)) { 679 dmux->canvas_width_, dmux->canvas_height_)) {
674 return 0; 680 return 0;
675 } 681 }
676 682
677 fragment_count += f->is_fragment_; 683 fragment_count += f->is_fragment_;
678 ++frame_count; 684 ++frame_count;
679 } 685 }
680 if (!has_fragments && frame_count > 1) return 0; 686 if (!is_fragmented && frame_count > 1) return 0;
681 if (fragment_count > 0 && frame_count != fragment_count) return 0; 687 if (fragment_count > 0 && frame_count != fragment_count) return 0;
682 if (f == NULL) break;
683 } 688 }
684 return 1; 689 return 1;
685 } 690 }
686 691
687 // ----------------------------------------------------------------------------- 692 // -----------------------------------------------------------------------------
688 // WebPDemuxer object 693 // WebPDemuxer object
689 694
690 static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { 695 static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
691 dmux->state_ = WEBP_DEMUX_PARSING_HEADER; 696 dmux->state_ = WEBP_DEMUX_PARSING_HEADER;
692 dmux->loop_count_ = 1; 697 dmux->loop_count_ = 1;
693 dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. 698 dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
694 dmux->canvas_width_ = -1; 699 dmux->canvas_width_ = -1;
695 dmux->canvas_height_ = -1; 700 dmux->canvas_height_ = -1;
696 dmux->frames_tail_ = &dmux->frames_; 701 dmux->frames_tail_ = &dmux->frames_;
702 dmux->chunks_tail_ = &dmux->chunks_;
697 dmux->mem_ = *mem; 703 dmux->mem_ = *mem;
698 } 704 }
699 705
700 WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, 706 WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
701 WebPDemuxState* state, int version) { 707 WebPDemuxState* state, int version) {
702 const ChunkParser* parser; 708 const ChunkParser* parser;
703 int partial; 709 int partial;
704 ParseStatus status = PARSE_ERROR; 710 ParseStatus status = PARSE_ERROR;
705 MemBuffer mem; 711 MemBuffer mem;
706 WebPDemuxer* dmux; 712 WebPDemuxer* dmux;
707 713
714 if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR;
715
708 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL; 716 if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL;
709 if (data == NULL || data->bytes == NULL || data->size == 0) return NULL; 717 if (data == NULL || data->bytes == NULL || data->size == 0) return NULL;
710 718
711 if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL; 719 if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL;
712 if (!ReadHeader(&mem)) return NULL; 720 status = ReadHeader(&mem);
721 if (status != PARSE_OK) {
722 if (state != NULL) {
723 *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER
724 : WEBP_DEMUX_PARSE_ERROR;
725 }
726 return NULL;
727 }
713 728
714 partial = (mem.buf_size_ < mem.riff_end_); 729 partial = (mem.buf_size_ < mem.riff_end_);
715 if (!allow_partial && partial) return NULL; 730 if (!allow_partial && partial) return NULL;
716 731
717 dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux)); 732 dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux));
718 if (dmux == NULL) return NULL; 733 if (dmux == NULL) return NULL;
719 InitDemux(dmux, &mem); 734 InitDemux(dmux, &mem);
720 735
736 status = PARSE_ERROR;
721 for (parser = kMasterChunks; parser->parse != NULL; ++parser) { 737 for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
722 if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { 738 if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
723 status = parser->parse(dmux); 739 status = parser->parse(dmux);
724 if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; 740 if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
725 if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR; 741 if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
726 if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; 742 if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
743 if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR;
727 break; 744 break;
728 } 745 }
729 } 746 }
730 if (state) *state = dmux->state_; 747 if (state != NULL) *state = dmux->state_;
731 748
732 if (status == PARSE_ERROR) { 749 if (status == PARSE_ERROR) {
733 WebPDemuxDelete(dmux); 750 WebPDemuxDelete(dmux);
734 return NULL; 751 return NULL;
735 } 752 }
736 return dmux; 753 return dmux;
737 } 754 }
738 755
739 void WebPDemuxDelete(WebPDemuxer* dmux) { 756 void WebPDemuxDelete(WebPDemuxer* dmux) {
740 Chunk* c; 757 Chunk* c;
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE; 993 (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE;
977 return SetChunk(fourcc, iter->chunk_num - 1, iter); 994 return SetChunk(fourcc, iter->chunk_num - 1, iter);
978 } 995 }
979 return 0; 996 return 0;
980 } 997 }
981 998
982 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { 999 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) {
983 (void)iter; 1000 (void)iter;
984 } 1001 }
985 1002
986 #if defined(__cplusplus) || defined(c_plusplus)
987 } // extern "C"
988 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/dec/webpi.h ('k') | third_party/libwebp/dsp/cpu.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698