diff options
Diffstat (limited to 'common/binfile.c')
-rw-r--r-- | common/binfile.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/common/binfile.c b/common/binfile.c new file mode 100644 index 0000000..fa0a120 --- /dev/null +++ b/common/binfile.c @@ -0,0 +1,334 @@ + /* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include "binfile.h" + +#define BF_FILE 0x00000010 +#define BF_ERROR 0x00000040 + +/* bfctx: --------------------------------------------------- + * This is the structure that becomes a BFILE + * to the outside world + */ +typedef struct _bfctx +{ + union + { + FILE* file; /* Valid when working with a FILE */ + void* data; /* Valid when working with memory */ + } d; + size_t cur; /* Current position */ + size_t len; /* Size of the memory buffer */ + int flags; +} +bfctx; + + +/* bfWriteRaw: ----------------------------------------------- + * Write data to appropriate buffer/file + */ +int bfWriteRaw(BFILE h, const void* data, size_t len) +{ + bfctx* ctx = (bfctx*)h; + + /* file */ + if(ctx->flags & BF_FILE) + { + len = fwrite(data, len, 1, ctx->d.file); + ctx->cur += len; + return len; + } + + /* memory */ + else + { + /* Check if enough space */ + if((ctx->cur + len) > ctx->len) + { + /* If we ran out of space try and reallocate */ + if(ctx->flags & BF_REALLOC) + { + void* old = ctx->d.data; + + ctx->len = ctx->len + (((len / 1024) + 1) * 1024); + ctx->d.data = realloc(ctx->d.data, ctx->len); + + if(!ctx->d.data) + free(old); + } + + /* + * If there's no more space and we can't + * reallocate then it's an error + */ + if(!ctx->d.data || !(ctx->flags & BF_REALLOC)) + { + ctx->flags |= BF_ERROR; + return 0; + } + + } + + /* write the data in */ + memcpy(((unsigned char*)ctx->d.data) + ctx->cur, data, len); + ctx->cur += len; + return len; + } +} + + +/* bfReadRaw: ------------------------------------------------------ + * Read data from either buffer or file + */ +int bfReadRaw(BFILE h, void* data, size_t len) +{ + bfctx* ctx = (bfctx*)h; + + /* file */ + if(ctx->flags & BF_FILE) + { + len = fread(data, 1, len, ctx->d.file); + ctx->cur += len; + return len; + } + + /* memory */ + else + { + if((ctx->len - ctx->cur) < len) + len = ctx->len - ctx->cur; + + memcpy(data, ((unsigned char*)ctx->d.data) + ctx->cur, len); + ctx->cur += len; + return len; + } +} + + +/* bfSeek: --------------------------------------------------------- + * Seek forward in either buffer or file + */ +int bfSeek(bfctx* ctx, long offset) +{ + /* file */ + if(ctx->flags & BF_FILE) + { + int ret = fseek(ctx->d.file, offset, SEEK_CUR); + if(ret == 0) + ctx->cur += offset; + return ret; + } + + /* memory */ + else + { + if((long)(ctx->len - ctx->cur) < offset) + return 1; + ctx->cur += offset; + + return 0; + } +} + + +/* bfError: ------------------------------------------------- + * Check for errors on output + */ +int bfError(BFILE h) +{ + bfctx* ctx = (bfctx*)h; + if(ctx->flags & BF_FILE) + return ferror(ctx->d.file); + else + return ctx->flags & BF_ERROR; +} + + +/* bfStartFile: ----------------------------------------------- + * Get a BFILE based on a FILE output + * file should be opened for appropriate input or output + */ +BFILE bfStartFile(FILE* file) +{ + bfctx* ctx = (bfctx*)malloc(sizeof(bfctx)); + if(!ctx) return 0; + memset(ctx, 0, sizeof(bfctx)); + + ctx->d.file = file; + ctx->flags = BF_FILE; + return ctx; +} + +/* bfStartMem: ------------------------------------------------- + * Get a BFILE based on memory + * If flags have BF_REALLOC set then NULL can be passed + * and/or we can reallocate the buffer + */ +BFILE bfStartMem(void* mem, size_t len, int flags) +{ + bfctx* ctx = (bfctx*)malloc(sizeof(bfctx)); + if(!ctx) return 0; + memset(ctx, 0, sizeof(bfctx)); + + ctx->len = len; + ctx->flags = flags; + ctx->flags &= ~(BF_FILE | BF_ERROR); + ctx->d.data = mem; + + return ctx; +} + +/* bfClose: ----------------------------------------------------- + * Close a BFILE + * Returns either the file or memory buffer, and returns size + * in the len argument + */ +void bfClose(BFILE h) +{ + if(h) + free(h); +} + +/* bfInternal: -------------------------------------------------- + * Get the internal file handle or memory pointer for this + * binfile + */ +void* bfInternal(BFILE h) +{ + bfctx* ctx = (bfctx*)h; + if(ctx->flags & BF_FILE) + return ctx->d.file; + else + return ctx->d.data; +} + +/* bfCount: ---------------------------------------------------- + * Returns the number of bytes written or read to this binfile + */ +size_t bfCount(BFILE h) +{ + bfctx* ctx = (bfctx*)h; + return ctx->cur; +} + +/* bfWriteEnd: ------------------------------------------------- + * Puts down an end of tags marker in the binfile + */ +int bfWriteEnd(BFILE h) +{ + bfval opt; + int c; + + opt.id = BINTYPE_END; + opt.len = 0; + opt.type = BINTYPE_END; + c = bfWriteRaw(h, &opt, sizeof(opt)); + + return bfError(h) ? 0 : c; +} + +/* bfWriteValue: ----------------------------------------------- + * Writes a tagged value to the binfile + */ +int bfWriteValue(BFILE h, const bfval* val, const void* data) +{ + int c = bfWriteRaw(h, val, sizeof(bfval)); + c += bfWriteRaw(h, data, val->len); + return bfError(h) ? 0 : c; +} + +/* bfReadValueInfo: -------------------------------------------- + * Gets the next tag (without data) and returns the length + * of the memory required to hold it. + */ +int bfReadValueInfo(BFILE h, bfval* val) +{ + int c = bfReadRaw(h, val, sizeof(bfval)); + return c == sizeof(bfval) && !bfError(h); +} + +/* bfReadValueData: --------------------------------------------- + * Gets the data for a value. val should be same one returned + * from bfReadValueInfo + */ +int bfReadValueData(BFILE h, const bfval* val, void* data) +{ + size_t c; + if((c = bfReadRaw(h, data, val->len)) != val->len || + bfError(h)) + return 0; + + /* Special handling for these guys */ + switch(val->type) + { + case BINTYPE_ASCII: + { + char* str = (char*)data; + str[val->len] = 0; + } + break; + + case BINTYPE_INT32: + case BINTYPE_INT16: + /* TODO: do endianness here */ + break; + }; + + return c; +} + +/* bfSkipValueData: ------------------------------------------------ + * Skips the data for a tagged value + */ +int bfSkipValueData(BFILE h, const bfval* val) +{ + bfctx* ctx = (bfctx*)h; + return bfSeek(ctx, val->len) == 0; +} + + +/* bfWriteString: -------------------------------------------------- + * Convenience function for writing out strings to file + */ +int bfWriteString(BFILE h, short id, const char* data) +{ + bfval val; + val.id = id; + val.type = BINTYPE_ASCII; + val.len = strlen(data); + + return bfWriteValue(h, &val, (void*)data); +} + +/* bfWriteInt: ----------------------------------------------------- + * Convenience function for writing out 4 byte integers to file + */ +int bfWriteInt(BFILE h, short id, int data) +{ + bfval val; + val.id = id; + val.type = BINTYPE_INT32; + val.len = BINSIZE_INT32; + + /* TODO: take care of endianess here */ + return bfWriteValue(h, &val, &data); +} + |