/* * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "fifo_buffer.h" #include #include #include struct fifo_buffer { size_t size, start, end; unsigned char buffer[sizeof(size_t)]; }; struct fifo_buffer * fifo_buffer_new(size_t size) { struct fifo_buffer *buffer; assert(size > 0); buffer = (struct fifo_buffer *)g_malloc(sizeof(*buffer) - sizeof(buffer->buffer) + size); buffer->size = size; buffer->start = 0; buffer->end = 0; return buffer; } void fifo_buffer_init(struct fifo_buffer *buffer, size_t size) { buffer->size = size - (sizeof(*buffer) - sizeof(buffer->buffer)); buffer->start = 0; buffer->end = 0; } static void fifo_buffer_move(struct fifo_buffer *buffer); struct fifo_buffer * fifo_buffer_realloc(struct fifo_buffer *buffer, size_t new_size) { if (buffer == NULL) return new_size > 0 ? fifo_buffer_new(new_size) : NULL; /* existing data must fit in new size */ assert(new_size >= buffer->end - buffer->start); if (new_size == 0) { fifo_buffer_free(buffer); return NULL; } /* compress the buffer when we're shrinking and the tail of the buffer would exceed the new size */ if (buffer->end > new_size) fifo_buffer_move(buffer); /* existing data must fit in new size: second check */ assert(buffer->end <= new_size); buffer = g_realloc(buffer, sizeof(*buffer) - sizeof(buffer->buffer) + new_size); buffer->size = new_size; return buffer; } void fifo_buffer_free(struct fifo_buffer *buffer) { assert(buffer != NULL); g_free(buffer); } size_t fifo_buffer_capacity(const struct fifo_buffer *buffer) { assert(buffer != NULL); return buffer->size; } size_t fifo_buffer_available(const struct fifo_buffer *buffer) { assert(buffer != NULL); return buffer->end - buffer->start; } void fifo_buffer_clear(struct fifo_buffer *buffer) { assert(buffer != NULL); buffer->start = 0; buffer->end = 0; } const void * fifo_buffer_read(const struct fifo_buffer *buffer, size_t *length_r) { assert(buffer != NULL); assert(buffer->end >= buffer->start); assert(length_r != NULL); if (buffer->start == buffer->end) /* the buffer is empty */ return NULL; *length_r = buffer->end - buffer->start; return buffer->buffer + buffer->start; } void fifo_buffer_consume(struct fifo_buffer *buffer, size_t length) { assert(buffer != NULL); assert(buffer->end >= buffer->start); assert(buffer->start + length <= buffer->end); buffer->start += length; } /** * Move data to the beginning of the buffer, to make room at the end. */ static void fifo_buffer_move(struct fifo_buffer *buffer) { if (buffer->start == 0) return; if (buffer->end > buffer->start) memmove(buffer->buffer, buffer->buffer + buffer->start, buffer->end - buffer->start); buffer->end -= buffer->start; buffer->start = 0; } void * fifo_buffer_write(struct fifo_buffer *buffer, size_t *max_length_r) { assert(buffer != NULL); assert(buffer->end <= buffer->size); assert(max_length_r != NULL); if (buffer->end == buffer->size) { fifo_buffer_move(buffer); if (buffer->end == buffer->size) return NULL; } else if (buffer->start > 0 && buffer->start == buffer->end) { buffer->start = 0; buffer->end = 0; } *max_length_r = buffer->size - buffer->end; return buffer->buffer + buffer->end; } void fifo_buffer_append(struct fifo_buffer *buffer, size_t length) { assert(buffer != NULL); assert(buffer->end >= buffer->start); assert(buffer->end + length <= buffer->size); buffer->end += length; } bool fifo_buffer_is_empty(struct fifo_buffer *buffer) { return buffer->start == buffer->end; } bool fifo_buffer_is_full(struct fifo_buffer *buffer) { return buffer->start == 0 && buffer->end == buffer->size; }