| OLD | NEW |
| 1 // Copyright 2010 Google Inc. All Rights Reserved. | 1 // Copyright 2010 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 // Main decoding functions for WEBP images. | 10 // Main decoding functions for WEBP images. |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 // RIFF + VP8X + (optional chunks) + VP8(L) | 279 // RIFF + VP8X + (optional chunks) + VP8(L) |
| 280 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. | 280 // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. |
| 281 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. | 281 // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. |
| 282 static VP8StatusCode ParseHeadersInternal(const uint8_t* data, | 282 static VP8StatusCode ParseHeadersInternal(const uint8_t* data, |
| 283 size_t data_size, | 283 size_t data_size, |
| 284 int* const width, | 284 int* const width, |
| 285 int* const height, | 285 int* const height, |
| 286 int* const has_alpha, | 286 int* const has_alpha, |
| 287 int* const has_animation, | 287 int* const has_animation, |
| 288 WebPHeaderStructure* const headers) { | 288 WebPHeaderStructure* const headers) { |
| 289 int canvas_width = 0; |
| 290 int canvas_height = 0; |
| 291 int image_width = 0; |
| 292 int image_height = 0; |
| 289 int found_riff = 0; | 293 int found_riff = 0; |
| 290 int found_vp8x = 0; | 294 int found_vp8x = 0; |
| 291 VP8StatusCode status; | 295 VP8StatusCode status; |
| 292 WebPHeaderStructure hdrs; | 296 WebPHeaderStructure hdrs; |
| 293 | 297 |
| 294 if (data == NULL || data_size < RIFF_HEADER_SIZE) { | 298 if (data == NULL || data_size < RIFF_HEADER_SIZE) { |
| 295 return VP8_STATUS_NOT_ENOUGH_DATA; | 299 return VP8_STATUS_NOT_ENOUGH_DATA; |
| 296 } | 300 } |
| 297 memset(&hdrs, 0, sizeof(hdrs)); | 301 memset(&hdrs, 0, sizeof(hdrs)); |
| 298 hdrs.data = data; | 302 hdrs.data = data; |
| 299 hdrs.data_size = data_size; | 303 hdrs.data_size = data_size; |
| 300 | 304 |
| 301 // Skip over RIFF header. | 305 // Skip over RIFF header. |
| 302 status = ParseRIFF(&data, &data_size, &hdrs.riff_size); | 306 status = ParseRIFF(&data, &data_size, &hdrs.riff_size); |
| 303 if (status != VP8_STATUS_OK) { | 307 if (status != VP8_STATUS_OK) { |
| 304 return status; // Wrong RIFF header / insufficient data. | 308 return status; // Wrong RIFF header / insufficient data. |
| 305 } | 309 } |
| 306 found_riff = (hdrs.riff_size > 0); | 310 found_riff = (hdrs.riff_size > 0); |
| 307 | 311 |
| 308 // Skip over VP8X. | 312 // Skip over VP8X. |
| 309 { | 313 { |
| 310 uint32_t flags = 0; | 314 uint32_t flags = 0; |
| 311 status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags); | 315 int animation_present; |
| 316 status = ParseVP8X(&data, &data_size, &found_vp8x, |
| 317 &canvas_width, &canvas_height, &flags); |
| 312 if (status != VP8_STATUS_OK) { | 318 if (status != VP8_STATUS_OK) { |
| 313 return status; // Wrong VP8X / insufficient data. | 319 return status; // Wrong VP8X / insufficient data. |
| 314 } | 320 } |
| 321 animation_present = !!(flags & ANIMATION_FLAG); |
| 315 if (!found_riff && found_vp8x) { | 322 if (!found_riff && found_vp8x) { |
| 316 // Note: This restriction may be removed in the future, if it becomes | 323 // Note: This restriction may be removed in the future, if it becomes |
| 317 // necessary to send VP8X chunk to the decoder. | 324 // necessary to send VP8X chunk to the decoder. |
| 318 return VP8_STATUS_BITSTREAM_ERROR; | 325 return VP8_STATUS_BITSTREAM_ERROR; |
| 319 } | 326 } |
| 320 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); | 327 if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG); |
| 321 if (has_animation != NULL) *has_animation = !!(flags & ANIMATION_FLAG); | 328 if (has_animation != NULL) *has_animation = animation_present; |
| 322 if (found_vp8x && headers == NULL) { | 329 |
| 323 return VP8_STATUS_OK; // Return features from VP8X header. | 330 if (found_vp8x && animation_present && headers == NULL) { |
| 331 if (width != NULL) *width = canvas_width; |
| 332 if (height != NULL) *height = canvas_height; |
| 333 return VP8_STATUS_OK; // Just return features from VP8X header. |
| 324 } | 334 } |
| 325 } | 335 } |
| 326 | 336 |
| 327 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; | 337 if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; |
| 328 | 338 |
| 329 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". | 339 // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH". |
| 330 if ((found_riff && found_vp8x) || | 340 if ((found_riff && found_vp8x) || |
| 331 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { | 341 (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) { |
| 332 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, | 342 status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, |
| 333 &hdrs.alpha_data, &hdrs.alpha_data_size); | 343 &hdrs.alpha_data, &hdrs.alpha_data_size); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 344 } | 354 } |
| 345 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { | 355 if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) { |
| 346 return VP8_STATUS_BITSTREAM_ERROR; | 356 return VP8_STATUS_BITSTREAM_ERROR; |
| 347 } | 357 } |
| 348 | 358 |
| 349 if (!hdrs.is_lossless) { | 359 if (!hdrs.is_lossless) { |
| 350 if (data_size < VP8_FRAME_HEADER_SIZE) { | 360 if (data_size < VP8_FRAME_HEADER_SIZE) { |
| 351 return VP8_STATUS_NOT_ENOUGH_DATA; | 361 return VP8_STATUS_NOT_ENOUGH_DATA; |
| 352 } | 362 } |
| 353 // Validates raw VP8 data. | 363 // Validates raw VP8 data. |
| 354 if (!VP8GetInfo(data, data_size, | 364 if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size, |
| 355 (uint32_t)hdrs.compressed_size, width, height)) { | 365 &image_width, &image_height)) { |
| 356 return VP8_STATUS_BITSTREAM_ERROR; | 366 return VP8_STATUS_BITSTREAM_ERROR; |
| 357 } | 367 } |
| 358 } else { | 368 } else { |
| 359 if (data_size < VP8L_FRAME_HEADER_SIZE) { | 369 if (data_size < VP8L_FRAME_HEADER_SIZE) { |
| 360 return VP8_STATUS_NOT_ENOUGH_DATA; | 370 return VP8_STATUS_NOT_ENOUGH_DATA; |
| 361 } | 371 } |
| 362 // Validates raw VP8L data. | 372 // Validates raw VP8L data. |
| 363 if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) { | 373 if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) { |
| 364 return VP8_STATUS_BITSTREAM_ERROR; | 374 return VP8_STATUS_BITSTREAM_ERROR; |
| 365 } | 375 } |
| 366 } | 376 } |
| 367 | 377 // Validates image size coherency. TODO(urvang): what about FRGM? |
| 378 if (found_vp8x) { |
| 379 if (canvas_width != image_width || canvas_height != image_height) { |
| 380 return VP8_STATUS_BITSTREAM_ERROR; |
| 381 } |
| 382 } |
| 383 if (width != NULL) *width = image_width; |
| 384 if (height != NULL) *height = image_height; |
| 368 if (has_alpha != NULL) { | 385 if (has_alpha != NULL) { |
| 369 // If the data did not contain a VP8X/VP8L chunk the only definitive way | 386 // If the data did not contain a VP8X/VP8L chunk the only definitive way |
| 370 // to set this is by looking for alpha data (from an ALPH chunk). | 387 // to set this is by looking for alpha data (from an ALPH chunk). |
| 371 *has_alpha |= (hdrs.alpha_data != NULL); | 388 *has_alpha |= (hdrs.alpha_data != NULL); |
| 372 } | 389 } |
| 373 if (headers != NULL) { | 390 if (headers != NULL) { |
| 374 *headers = hdrs; | 391 *headers = hdrs; |
| 375 headers->offset = data - headers->data; | 392 headers->offset = data - headers->data; |
| 376 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); | 393 assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD); |
| 377 assert(headers->offset == headers->data_size - data_size); | 394 assert(headers->offset == headers->data_size - data_size); |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 io->fancy_upsampling = 0; | 799 io->fancy_upsampling = 0; |
| 783 } | 800 } |
| 784 return 1; | 801 return 1; |
| 785 } | 802 } |
| 786 | 803 |
| 787 //------------------------------------------------------------------------------ | 804 //------------------------------------------------------------------------------ |
| 788 | 805 |
| 789 #if defined(__cplusplus) || defined(c_plusplus) | 806 #if defined(__cplusplus) || defined(c_plusplus) |
| 790 } // extern "C" | 807 } // extern "C" |
| 791 #endif | 808 #endif |
| OLD | NEW |