/* * This file is part of LibParserUtils. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2008 John-Mark Bell */ #include #include #include #define DEFAULT_SIZE (4096) /** * Create a memory buffer * * \param buffer Pointer to location to receive memory buffer * \return PARSERUTILS_OK on success, * PARSERUTILS_BADPARM on bad parameters, * PARSERUTILS_NOMEM on memory exhausion */ parserutils_error parserutils_buffer_create(parserutils_buffer **buffer) { parserutils_buffer *b; if (buffer == NULL) return PARSERUTILS_BADPARM; b = malloc(sizeof(parserutils_buffer)); if (b == NULL) return PARSERUTILS_NOMEM; b->alloc = malloc(DEFAULT_SIZE); if (b->alloc == NULL) { free(b); return PARSERUTILS_NOMEM; } b->data = b->alloc; b->length = 0; b->allocated = DEFAULT_SIZE; *buffer = b; return PARSERUTILS_OK; } /** * Destroy a memory buffer * * \param buffer The buffer to destroy * \return PARSERUTILS_OK on success, appropriate error otherwise */ parserutils_error parserutils_buffer_destroy(parserutils_buffer *buffer) { if (buffer == NULL) return PARSERUTILS_BADPARM; free(buffer->alloc); free(buffer); return PARSERUTILS_OK; } /** * Get current data offset within buffer's allocation. * * \param[in] buffer The buffer object. * \return data offset in bytes. */ static inline size_t get_offset(parserutils_buffer *buffer) { return buffer->data - buffer->alloc; } /** * Try moving the data to the start of the allocation. * * \param[in] buffer The buffer object. */ static inline void try_rebase(parserutils_buffer *buffer) { if (get_offset(buffer) >= buffer->length) { memcpy(buffer->alloc, buffer->data, buffer->length); buffer->data = buffer->alloc; } } /** * Ensure that the buffer has enough space at the end to add len bytes. * * \param[in] buffer The buffer object. * \param[in] len Number of bytes to ensure there is space for. * \return PARSERUTILS_OK on success, appropriate error otherwise. */ static inline parserutils_error ensure_space( parserutils_buffer *buffer, size_t len) { try_rebase(buffer); while (len >= buffer->allocated - buffer->length - get_offset(buffer)) { parserutils_error error = parserutils_buffer_grow(buffer); if (error != PARSERUTILS_OK) return error; } return PARSERUTILS_OK; } /** * Append data to a memory buffer * * \param buffer The buffer to append to * \param data The data to append * \param len The length, in bytes, of the data to append * \return PARSERUTILS_OK on success, appropriate error otherwise. */ parserutils_error parserutils_buffer_append(parserutils_buffer *buffer, const uint8_t *data, size_t len) { parserutils_error error = ensure_space(buffer, len); if (error != PARSERUTILS_OK) return error; memcpy(buffer->data + buffer->length, data, len); buffer->length += len; return PARSERUTILS_OK; } /** * Append multiple data blocks to a memory buffer. * * Each data block must be passed as a pair of const uint8_t* and size_t * * \param buffer The buffer to append to * \param count The number of data blocks to append * \param ... The pairs of pointer and size * \return PARSERUTILS_OK on success, appropriate error otherwise. */ parserutils_error parserutils_buffer_appendv(parserutils_buffer *buffer, size_t count, ...) { va_list ap; parserutils_error error = PARSERUTILS_OK; const uint8_t *data; size_t len; va_start(ap, count); while (count > 0) { data = va_arg(ap, const uint8_t *); len = va_arg(ap, size_t); error = parserutils_buffer_append(buffer, data, len); if (error != PARSERUTILS_OK) break; count--; } va_end(ap); return error; } /** * Insert data into a memory buffer * * \param buffer The buffer to insert into * \param offset The offset into the buffer to insert at * \param data The data to insert * \param len The length, in bytes, of the data to insert * \return PARSERUTILS_OK on success, appropriate error otherwise */ parserutils_error parserutils_buffer_insert(parserutils_buffer *buffer, size_t offset, const uint8_t *data, size_t len) { parserutils_error error; if (offset > buffer->length) return PARSERUTILS_BADPARM; if (offset == buffer->length) return parserutils_buffer_append(buffer, data, len); error = ensure_space(buffer, len); if (error != PARSERUTILS_OK) return error; memmove(buffer->data + offset + len, buffer->data + offset, buffer->length - offset); memcpy(buffer->data + offset, data, len); buffer->length += len; return PARSERUTILS_OK; } /** * Discard a section of a memory buffer * * \param buffer The buffer to discard data from * \param offset The offset into the buffer of the start of the section * \param len The number of bytes to discard * \return PARSERUTILS_OK on success, appropriate error otherwise. */ parserutils_error parserutils_buffer_discard(parserutils_buffer *buffer, size_t offset, size_t len) { if (offset >= buffer->length || offset + len > buffer->length) return PARSERUTILS_BADPARM; if (offset == 0) { buffer->data += len; buffer->length -= len; try_rebase(buffer); return PARSERUTILS_OK; } memmove(buffer->data + offset, buffer->data + offset + len, buffer->length - (len + offset)); buffer->length -= len; return PARSERUTILS_OK; } /** * Extend the amount of space allocated for a memory buffer * * \param buffer The buffer to extend * \return PARSERUTILS_OK on success, appropriate error otherwise. */ parserutils_error parserutils_buffer_grow(parserutils_buffer *buffer) { size_t offset = get_offset(buffer); uint8_t *temp = realloc(buffer->alloc, buffer->allocated * 2); if (temp == NULL) return PARSERUTILS_NOMEM; buffer->alloc = temp; buffer->data = buffer->alloc + offset; buffer->allocated *= 2; return PARSERUTILS_OK; } parserutils_error parserutils_buffer_randomise(parserutils_buffer *buffer) { #ifndef NDEBUG uint8_t *temp; #endif if (buffer == NULL) return PARSERUTILS_BADPARM; #ifndef NDEBUG temp = malloc(buffer->allocated); if (temp == NULL) return PARSERUTILS_NOMEM; memcpy(temp, buffer->data, buffer->length); memset(buffer->data, 0xff, buffer->length); /* Leak the buffer's current data, so we don't reuse it */ /* buffer->alloc(buffer->data, 0, buffer->pw); */ buffer->alloc = buffer->data = temp; #endif return PARSERUTILS_OK; }