static byte* ChunkEmit(WebPChunk* chunk, byte* dst) { assert(chunk); assert(chunk.tag_ != NIL_TAG); PutLE32(dst + 0, chunk.tag_); PutLE32(dst + TAG_SIZE, chunk.payload_size_); memcpy(dst + CHUNK_HEADER_SIZE, chunk.data_, chunk.payload_size_); if (chunk.payload_size_ & 1) dst[CHUNK_HEADER_SIZE + chunk.payload_size_] = 0; // Add padding. return dst + ChunkDiskSize(chunk); }
// Outputs a pointer to 'prev_chunk.next_', // where 'prev_chunk' is the pointer to the chunk at position (nth - 1). // Returns 1 if nth chunk was found, 0 otherwise. static int ChunkSearchListToSet(WebPChunk** chunk_list, uint nth, WebPChunk*** location) { uint count = 0; assert(chunk_list); *location = chunk_list; while (*chunk_list) { WebPChunk* cur_chunk = *chunk_list; ++count; if (count == nth) return 1; // Found. chunk_list = &cur_chunk.next_; *location = chunk_list; } // *chunk_list is ok to be null if adding at last location. return (nth == 0 || (count == nth - 1)) ? 1 : 0; }
// Fill the chunk with the given data, after verifying that the data size // doesn't exceed 'max_size'. static WebPMuxError ChunkAssignData(WebPChunk* chunk, byte* data, uint data_size, uint riff_size, int copy_data) { uint chunk_size; // Sanity checks. if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; chunk_size = GetLE32(data + TAG_SIZE); { uint 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. return ChunkAssignDataImageInfo(chunk, data + CHUNK_HEADER_SIZE, chunk_size, null, copy_data, GetLE32(data + 0)); }
// Count number of chunks matching 'tag' in the 'chunk_list'. // If tag == NIL_TAG, any tag will be matched. static int CountChunks(WebPChunk* chunk_list, uint tag) { int count = 0; WebPChunk* current; for (current = chunk_list; current != null; current = current.next_) { if (tag == NIL_TAG || current.tag_ == tag) { count++; // Count chunks whose tags match. } } return count; }
static void DeleteAllChunks(WebPChunk* chunk_list) { while (*chunk_list) { *chunk_list = ChunkDelete(*chunk_list); } }
static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint tag) { WebPMuxError err = WEBP_MUX_NOT_FOUND; assert(chunk_list); while (*chunk_list) { WebPChunk* chunk = *chunk_list; if (chunk.tag_ == tag) { *chunk_list = ChunkDelete(chunk); err = WEBP_MUX_OK; } else { chunk_list = &chunk.next_; } } return err; }
//------------------------------------------------------------------------------ // Chunk search methods. // Returns next chunk in the chunk list with the given tag. static WebPChunk ChunkSearchNextInList(WebPChunk chunk, uint tag) { while (chunk && chunk.tag_ != tag) { chunk = chunk.next_; } return chunk; }
/// <summary> /// Life of a chunk object. /// </summary> static WebPChunk ChunkRelease(WebPChunk chunk) { WebPChunk next; if (chunk == null) return null; free(chunk.image_info_); if (chunk.owner_) { free((void*)chunk.data_); } next = chunk.next_; ChunkInit(chunk); return next; }
//------------------------------------------------------------------------------ // Chunk serialization methods. uint ChunksListDiskSize(WebPChunk* chunk_list) { uint size = 0; while (chunk_list) { size += ChunkDiskSize(chunk_list); chunk_list = chunk_list.next_; } return size; }
WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list, uint nth) { WebPChunk* new_chunk; if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) { return WEBP_MUX_NOT_FOUND; } new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk)); if (new_chunk == null) return WEBP_MUX_MEMORY_ERROR; *new_chunk = *chunk; new_chunk.next_ = *chunk_list; *chunk_list = new_chunk; return WEBP_MUX_OK; }
WebPChunk ChunkSearchList(WebPChunk first, uint nth, uint tag) { uint iter = nth; first = ChunkSearchNextInList(first, tag); if (!first) return null; while (--iter != 0) { WebPChunk next_chunk = ChunkSearchNextInList(first.next_, tag); if (next_chunk == null) break; first = next_chunk; } return ((nth > 0) && (iter > 0)) ? null : first; }
byte* ChunkListEmit(WebPChunk* chunk_list, byte* dst) { while (chunk_list) { dst = ChunkEmit(chunk_list, dst); chunk_list = chunk_list.next_; } return dst; }
//------------------------------------------------------------------------------ // Chunk deletion method(s). WebPChunk* ChunkDelete(WebPChunk* chunk) { WebPChunk* next = ChunkRelease(chunk); free(chunk); return next; }
//------------------------------------------------------------------------------ // Chunk writer methods. WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk, byte* data, uint data_size, WebPImageInfo* image_info, int copy_data, uint tag) { // For internally allocated chunks, always copy data & make it owner of data. if ((tag == kChunks[VP8X_ID].chunkTag) || (tag == kChunks[LOOP_ID].chunkTag)) { copy_data = 1; } ChunkRelease(chunk); if (data == null) { data_size = 0; } else if (data_size == 0) { data = null; } if (data != null) { if (copy_data) { // Copy data. chunk.data_ = (byte*)malloc(data_size); if (chunk.data_ == null) return WEBP_MUX_MEMORY_ERROR; memcpy((byte*)chunk.data_, data, data_size); chunk.payload_size_ = data_size; // Chunk is owner of data. chunk.owner_ = 1; } else { // Don't copy data. chunk.data_ = data; chunk.payload_size_ = data_size; } } if (tag == kChunks[IMAGE_ID].chunkTag) { chunk.image_info_ = image_info; } chunk.tag_ = tag; return WEBP_MUX_OK; }