Files
filza27.2/XPF/external/ChOma/src/BufferedStream.c
T

194 lines
6.0 KiB
C

#include "BufferedStream.h"
#include "MemoryStream.h"
#include <stdlib.h>
static int buffered_stream_expand(MemoryStream *stream, size_t expandAtStart, size_t expandAtEnd);
static int _buffered_stream_make_own_data(MemoryStream *stream)
{
BufferedStreamContext *context = stream->context;
if ((stream->flags & MEMORY_STREAM_FLAG_OWNS_DATA) == 0) {
void *newBuffer = malloc(context->subBufferSize);
memcpy(newBuffer, context->buffer + context->subBufferStart, context->subBufferSize);
context->buffer = newBuffer;
stream->flags |= MEMORY_STREAM_FLAG_OWNS_DATA;
}
return 0;
}
static int buffered_stream_read(MemoryStream *stream, uint64_t offset, size_t size, void *outBuf)
{
BufferedStreamContext *context = stream->context;
if ((offset + size) > context->subBufferSize) {
printf("Error: cannot read %zx bytes at %llx, maximum is %zx.\n", size, offset, context->subBufferSize);
return -1;
}
memcpy(outBuf, context->buffer + context->subBufferStart + offset, size);
return size;
}
static int buffered_stream_write(MemoryStream *stream, uint64_t offset, size_t size, const void *inBuf)
{
BufferedStreamContext *context = stream->context;
bool expandAllowed = (stream->flags & MEMORY_STREAM_FLAG_AUTO_EXPAND);
bool needsExpand = (offset + size) > context->subBufferSize;
if (needsExpand && !expandAllowed) {
printf("Error: cannot write %zx bytes at %llx, maximum is %zx.\n", size, offset, context->subBufferSize);
return -1;
}
if ((stream->flags & MEMORY_STREAM_FLAG_OWNS_DATA) == 0) {
int r = _buffered_stream_make_own_data(stream);
if (r != 0) return r;
}
if (needsExpand) {
buffered_stream_expand(stream, 0, (offset + size) - context->subBufferSize);
}
memcpy(context->buffer + context->subBufferStart + offset, inBuf, size);
return size;
}
static int buffered_stream_get_size(MemoryStream *stream, size_t *sizeOut)
{
BufferedStreamContext *context = stream->context;
*sizeOut = context->subBufferSize;
return 0;
}
static uint8_t *buffered_stream_get_raw_pointer(MemoryStream *stream)
{
BufferedStreamContext *context = stream->context;
return &context->buffer[context->subBufferStart];
}
static int buffered_stream_trim(MemoryStream *stream, size_t trimAtStart, size_t trimAtEnd)
{
BufferedStreamContext *context = stream->context;
// TODO: bound checks
context->subBufferStart += trimAtStart;
context->subBufferSize -= (trimAtEnd + trimAtStart);
return 0;
}
static int buffered_stream_expand(MemoryStream *stream, size_t expandAtStart, size_t expandAtEnd)
{
BufferedStreamContext *context = stream->context;
size_t newSize = context->subBufferSize + expandAtStart + expandAtEnd;
uint8_t *newBuffer = malloc(newSize);
memset(newBuffer, 0, newSize);
memcpy(&newBuffer[expandAtStart], &context->buffer[context->subBufferStart], context->subBufferSize);
if (stream->flags & MEMORY_STREAM_FLAG_OWNS_DATA) {
free(context->buffer);
}
context->buffer = newBuffer;
context->bufferSize = newSize;
context->subBufferStart = 0;
context->subBufferSize = newSize;
stream->flags |= MEMORY_STREAM_FLAG_OWNS_DATA;
return 0;
}
static MemoryStream *buffered_stream_softclone(MemoryStream *stream)
{
MemoryStream* clone = malloc(sizeof(MemoryStream));
if (!clone) return NULL;
memset(clone, 0, sizeof(MemoryStream));
BufferedStreamContext *context = stream->context;
BufferedStreamContext *contextCopy = malloc(sizeof(BufferedStreamContext));
contextCopy->buffer = context->buffer;
contextCopy->bufferSize = context->bufferSize;
contextCopy->subBufferStart = context->subBufferStart;
contextCopy->subBufferSize = context->subBufferSize;
clone->flags = stream->flags & ~(MEMORY_STREAM_FLAG_OWNS_DATA);
clone->context = contextCopy;
return clone;
}
static MemoryStream *buffered_stream_hardclone(MemoryStream *stream)
{
MemoryStream* clone = buffered_stream_softclone(stream);
if (clone) {
_buffered_stream_make_own_data(clone);
}
return clone;
}
static void buffered_stream_free(MemoryStream *stream)
{
BufferedStreamContext *context = stream->context;
if (context->buffer) {
if (stream->flags & MEMORY_STREAM_FLAG_OWNS_DATA) {
free(context->buffer);
}
}
free(context);
}
static int _buffered_stream_init(MemoryStream *stream)
{
stream->read = buffered_stream_read;
stream->write = buffered_stream_write;
stream->getSize = buffered_stream_get_size;
stream->getRawPtr = buffered_stream_get_raw_pointer;
stream->trim = buffered_stream_trim;
stream->expand = buffered_stream_expand;
stream->softclone = buffered_stream_softclone;
stream->hardclone = buffered_stream_hardclone;
stream->free = buffered_stream_free;
stream->flags = MEMORY_STREAM_FLAG_MUTABLE;
return 0;
}
MemoryStream *buffered_stream_init_from_buffer_nocopy(void *buffer, size_t bufferSize, uint32_t flags)
{
MemoryStream *stream = malloc(sizeof(MemoryStream));
if (!stream) return NULL;
memset(stream, 0, sizeof(MemoryStream));
BufferedStreamContext *context = malloc(sizeof(BufferedStreamContext));
context->buffer = buffer;
context->bufferSize = bufferSize;
context->subBufferStart = 0;
context->subBufferSize = bufferSize;
stream->context = context;
if (_buffered_stream_init(stream) != 0) goto fail;
if (flags & BUFFERED_STREAM_FLAG_AUTO_EXPAND) {
stream->flags |= MEMORY_STREAM_FLAG_AUTO_EXPAND;
}
return stream;
fail:
buffered_stream_free(stream);
return NULL;
}
MemoryStream *buffered_stream_init_from_buffer(void *buffer, size_t bufferSize, uint32_t flags)
{
void *copy = malloc(bufferSize);
if (!copy) return NULL;
memcpy(copy, buffer, bufferSize);
MemoryStream *stream = buffered_stream_init_from_buffer_nocopy(copy, bufferSize, flags);
if (stream) {
stream->flags |= MEMORY_STREAM_FLAG_OWNS_DATA;
}
return stream;
}