WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, int copy_data) { WebPMuxError err; WebPChunk chunk; WebPMuxImage wpi; WebPData image; WebPData alpha; int is_lossless; int image_tag; if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || bitstream->size_ > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // If given data is for a whole webp file, // extract only the VP8/VP8L data from it. err = GetImageData(bitstream, &image, &alpha, &is_lossless); if (err != WEBP_MUX_OK) return err; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; // Delete the existing images. MuxImageDeleteAll(&mux->images_); MuxImageInit(&wpi); if (alpha.bytes_ != NULL) { // Add alpha chunk. ChunkInit(&chunk); err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) goto Err; } // Add image chunk. ChunkInit(&chunk); err = ChunkAssignData(&chunk, &image, copy_data, image_tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.img_, 1); if (err != WEBP_MUX_OK) goto Err; // Add this image to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All OK. return WEBP_MUX_OK; Err: // Something bad happened. ChunkRelease(&chunk); MuxImageRelease(&wpi); return err; }
// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. static WebPMuxError AddDataToChunkList( const WebPData* const data, int copy_data, uint32_t tag, WebPChunk** chunk_list) { WebPChunk chunk; WebPMuxError err; ChunkInit(&chunk); err = ChunkAssignData(&chunk, data, copy_data, tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, chunk_list, 1); if (err != WEBP_MUX_OK) goto Err; return WEBP_MUX_OK; Err: ChunkRelease(&chunk); return err; }
// Fill the chunk with the given data (includes chunk header bytes), after some // verifications. static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk, const uint8_t* data, size_t data_size, size_t riff_size, int copy_data) { uint32_t chunk_size; WebPData chunk_data; // Sanity checks. if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; chunk_size = GetLE32(data + TAG_SIZE); { const size_t chunk_disk_size = SizeWithPadding(chunk_size); if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA; if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA; } // Data assignment. chunk_data.bytes = data + CHUNK_HEADER_SIZE; chunk_data.size = chunk_size; return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); }
static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth, const WebPData* const data, int copy_data) { WebPChunk chunk; WebPMuxError err = WEBP_MUX_NOT_FOUND; assert(mux != NULL); assert(!IsWPI(kChunks[idx].id)); ChunkInit(&chunk); SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); SWITCH_ID_LIST(IDX_LOOP, &mux->loop_); SWITCH_ID_LIST(IDX_META, &mux->meta_); if (idx == IDX_UNKNOWN && data->size_ > TAG_SIZE) { // For raw-data unknown chunk, the first four bytes should be the tag to be // used for the chunk. const WebPData tmp = { data->bytes_ + TAG_SIZE, data->size_ - TAG_SIZE }; err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes_ + 0)); if (err == WEBP_MUX_OK) err = ChunkSetNth(&chunk, &mux->unknown_, nth); } return err; }
static int MuxImageParse(const WebPChunk* const chunk, int copy_data, WebPMuxImage* const wpi) { const uint8_t* bytes = chunk->data_.bytes; size_t size = chunk->data_.size; const uint8_t* const last = bytes + size; WebPChunk subchunk; size_t subchunk_size; ChunkInit(&subchunk); assert(chunk->tag_ == kChunks[IDX_ANMF].tag || chunk->tag_ == kChunks[IDX_FRGM].tag); assert(!wpi->is_partial_); // ANMF/FRGM. { const size_t hdr_size = (chunk->tag_ == kChunks[IDX_ANMF].tag) ? ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE; const WebPData temp = { bytes, hdr_size }; // Each of ANMF and FRGM chunk contain a header at the beginning. So, its // size should at least be 'hdr_size'. if (size < hdr_size) goto Fail; ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_); } ChunkSetNth(&subchunk, &wpi->header_, 1); wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks. // Rest of the chunks. subchunk_size = ChunkDiskSize(&subchunk) - CHUNK_HEADER_SIZE; bytes += subchunk_size; size -= subchunk_size; while (bytes != last) { ChunkInit(&subchunk); if (ChunkVerifyAndAssign(&subchunk, bytes, size, size, copy_data) != WEBP_MUX_OK) { goto Fail; } switch (ChunkGetIdFromTag(subchunk.tag_)) { case WEBP_CHUNK_ALPHA: if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks. if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail; wpi->is_partial_ = 1; // Waiting for a VP8 chunk. break; case WEBP_CHUNK_IMAGE: if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail; if (!MuxImageFinalize(wpi)) goto Fail; wpi->is_partial_ = 0; // wpi is completely filled. break; case WEBP_CHUNK_UNKNOWN: if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk // before some image chunks. if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail; break; default: goto Fail; break; } subchunk_size = ChunkDiskSize(&subchunk); bytes += subchunk_size; size -= subchunk_size; } if (wpi->is_partial_) goto Fail; return 1; Fail: ChunkRelease(&subchunk); return 0; }
static WebPMuxError MuxPushFrameTileInternal( WebPMux* const mux, const WebPData* const bitstream, int x_offset, int y_offset, int duration, int copy_data, uint32_t tag) { WebPChunk chunk; WebPData image; WebPData alpha; WebPMuxImage wpi; WebPMuxError err; WebPData frame_tile; const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0; int is_lossless; int image_tag; // Sanity checks. if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || bitstream->size_ > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || duration <= 0 || duration > MAX_DURATION) { return WEBP_MUX_INVALID_ARGUMENT; } // Snap offsets to even positions. x_offset &= ~1; y_offset &= ~1; // If given data is for a whole webp file, // extract only the VP8/VP8L data from it. err = GetImageData(bitstream, &image, &alpha, &is_lossless); if (err != WEBP_MUX_OK) return err; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; WebPDataInit(&frame_tile); ChunkInit(&chunk); MuxImageInit(&wpi); if (alpha.bytes_ != NULL) { // Add alpha chunk. err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. } // Add image chunk. err = ChunkAssignData(&chunk, &image, copy_data, image_tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.img_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.img_ now. // Create frame/tile data. err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless, is_frame, &frame_tile); if (err != WEBP_MUX_OK) goto Err; // Add frame/tile chunk (with copy_data = 1). err = ChunkAssignData(&chunk, &frame_tile, 1, tag); if (err != WEBP_MUX_OK) goto Err; WebPDataClear(&frame_tile); err = ChunkSetNth(&chunk, &wpi.header_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.header_ now. // Add this WebPMuxImage to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. WebPDataClear(&frame_tile); ChunkRelease(&chunk); MuxImageRelease(&wpi); return err; }