/** ** Parse an animation */ static CAnimation *ParseAnimation(lua_State *l, int idx) { if (!lua_istable(l, idx)) { LuaError(l, "incorrect argument"); } const int args = lua_rawlen(l, idx); if (args == 0) { return NULL; } Labels.clear(); LabelsLater.clear(); const char *str = LuaToString(l, idx, 1); CAnimation *firstAnim = ParseAnimationFrame(l, str); CAnimation *prev = firstAnim; for (int j = 1; j < args; ++j) { const char *str = LuaToString(l, idx, j + 1); CAnimation *anim = ParseAnimationFrame(l, str); prev->Next = anim; prev = anim; } prev->Next = firstAnim; FixLabels(l); return firstAnim; }
static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); MemBuffer* const mem = &dmux->mem_; int anim_chunks = 0; ParseStatus status = PARSE_OK; do { int store_chunk = 1; const size_t chunk_start_offset = mem->start_; const uint32_t fourcc = ReadLE32(mem); const uint32_t chunk_size = ReadLE32(mem); const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1); if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; switch (fourcc) { case MKFOURCC('V', 'P', '8', 'X'): { return PARSE_ERROR; } case MKFOURCC('A', 'L', 'P', 'H'): case MKFOURCC('V', 'P', '8', ' '): case MKFOURCC('V', 'P', '8', 'L'): { // check that this isn't an animation (all frames should be in an ANMF). if (anim_chunks > 0 || is_animation) return PARSE_ERROR; Rewind(mem, CHUNK_HEADER_SIZE); status = ParseSingleImage(dmux); break; } case MKFOURCC('A', 'N', 'I', 'M'): { if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR; if (MemDataSize(mem) < chunk_size_padded) { status = PARSE_NEED_MORE_DATA; } else if (anim_chunks == 0) { ++anim_chunks; dmux->bgcolor_ = ReadLE32(mem); dmux->loop_count_ = ReadLE16s(mem); Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE); } else { store_chunk = 0; goto Skip; } break; } case MKFOURCC('A', 'N', 'M', 'F'): { if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames. status = ParseAnimationFrame(dmux, chunk_size_padded); break; } #ifdef WEBP_EXPERIMENTAL_FEATURES case MKFOURCC('F', 'R', 'G', 'M'): { status = ParseFragment(dmux, chunk_size_padded); break; } #endif case MKFOURCC('I', 'C', 'C', 'P'): { store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); goto Skip; } case MKFOURCC('E', 'X', 'I', 'F'): { store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); goto Skip; } case MKFOURCC('X', 'M', 'P', ' '): { store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); goto Skip; } Skip: default: { if (chunk_size_padded <= MemDataSize(mem)) { if (store_chunk) { // Store only the chunk header and unpadded size as only the payload // will be returned to the user. if (!StoreChunk(dmux, chunk_start_offset, CHUNK_HEADER_SIZE + chunk_size)) { return PARSE_ERROR; } } Skip(mem, chunk_size_padded); } else { status = PARSE_NEED_MORE_DATA; } } } if (mem->start_ == mem->riff_end_) { break; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; } } while (status == PARSE_OK); return status; }
static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { MemBuffer* const mem = &dmux->mem_; int anim_chunks = 0; uint32_t vp8x_size; ParseStatus status = PARSE_OK; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; dmux->is_ext_format_ = 1; Skip(mem, TAG_SIZE); // VP8X vp8x_size = ReadLE32(mem); if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR; vp8x_size += vp8x_size & 1; if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; dmux->feature_flags_ = ReadByte(mem); Skip(mem, 3); // Reserved. dmux->canvas_width_ = 1 + ReadLE24s(mem); dmux->canvas_height_ = 1 + ReadLE24s(mem); if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { return PARSE_ERROR; // image final dimension is too large } Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. dmux->state_ = WEBP_DEMUX_PARSED_HEADER; if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; do { int store_chunk = 1; const size_t chunk_start_offset = mem->start_; const uint32_t fourcc = ReadLE32(mem); const uint32_t chunk_size = ReadLE32(mem); const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1); if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR; switch (fourcc) { case MKFOURCC('V', 'P', '8', 'X'): { return PARSE_ERROR; } case MKFOURCC('A', 'L', 'P', 'H'): case MKFOURCC('V', 'P', '8', ' '): case MKFOURCC('V', 'P', '8', 'L'): { // check that this isn't an animation (all frames should be in an ANMF). if (anim_chunks > 0) return PARSE_ERROR; Rewind(mem, CHUNK_HEADER_SIZE); status = ParseSingleImage(dmux); break; } case MKFOURCC('A', 'N', 'I', 'M'): { if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR; if (MemDataSize(mem) < chunk_size_padded) { status = PARSE_NEED_MORE_DATA; } else if (anim_chunks == 0) { ++anim_chunks; dmux->bgcolor_ = ReadLE32(mem); dmux->loop_count_ = ReadLE16s(mem); Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE); } else { store_chunk = 0; goto Skip; } break; } case MKFOURCC('A', 'N', 'M', 'F'): { if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames. status = ParseAnimationFrame(dmux, chunk_size_padded); break; } #ifdef WEBP_EXPERIMENTAL_FEATURES case MKFOURCC('F', 'R', 'G', 'M'): { status = ParseFragment(dmux, chunk_size_padded); break; } #endif case MKFOURCC('I', 'C', 'C', 'P'): { store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); goto Skip; } case MKFOURCC('X', 'M', 'P', ' '): { store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); goto Skip; } case MKFOURCC('E', 'X', 'I', 'F'): { store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); goto Skip; } Skip: default: { if (chunk_size_padded <= MemDataSize(mem)) { if (store_chunk) { // Store only the chunk header and unpadded size as only the payload // will be returned to the user. if (!StoreChunk(dmux, chunk_start_offset, CHUNK_HEADER_SIZE + chunk_size)) { return PARSE_ERROR; } } Skip(mem, chunk_size_padded); } else { status = PARSE_NEED_MORE_DATA; } } } if (mem->start_ == mem->riff_end_) { break; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; } } while (status == PARSE_OK); return status; }