/*(LGPL) --------------------------------------------------------------------------- pfile.cpp - Portable File Access Toolkit --------------------------------------------------------------------------- * Copyright (C) 2002, 2003, David Olofson * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define DBG(x) #include #include #include #include "kobolog.h" #include "pfile.h" /*---------------------------------------------------------- Constructor/Destructor ----------------------------------------------------------*/ pfile_t::pfile_t(FILE *file) { f = file; _status = 0; bufsize = bufused = bufpos = 0; buffer = NULL; } pfile_t::~pfile_t() { buffer_close(); } /*---------------------------------------------------------- Internal buffer control ----------------------------------------------------------*/ int pfile_t::buffer_init() { buffer_close(); bufsize = 1024; buffer = (char *)malloc(bufsize); if(!buffer) return status(-1); bufused = bufpos = 0; return _status; } int pfile_t::buffer_write() { DBG(log_printf(D3LOG, "pfile_t::buffer_write() %d bytes\n", bufused);) if(fwrite(buffer, bufused, 1, f) != 1) return status(-1); bufused = bufpos = 0; return _status; } int pfile_t::buffer_read(int len) { buffer_close(); bufsize = len; buffer = (char *)malloc(bufsize); if(!buffer) return status(-1); if(fread(buffer, bufsize, 1, f) != 1) { buffer_close(); return status(-1); } bufused = bufsize; bufpos = 0; return status(len); } void pfile_t::buffer_close() { free(buffer); buffer = NULL; bufsize = bufused = bufpos = 0; } int pfile_t::read(void *data, int len) { if(_status < 0) return _status; if(buffer) { if(bufpos + len > bufused) return -1; memcpy(data, buffer + bufpos, len); bufpos += len; return len; } else { if(fread(data, len, 1, f) != 1) return status(-1); return len; } } int pfile_t::write(void *data, int len) { if(_status < 0) return _status; DBG(log_printf(D3LOG, "pfile_t::write(block of %d bytes)\n", len);) if(bufused + len > bufsize) { int nbs = (bufused + len) * 3 / 2; char *nb = (char *)realloc(buffer, nbs); if(!nb) return -1; buffer = nb; bufsize = nbs; } memcpy(buffer + bufused, data, len); bufused += len; return len; } /*---------------------------------------------------------- Status ----------------------------------------------------------*/ int pfile_t::status() { int os = _status; _status = 0; return os; } int pfile_t::status(int new_status) { if(_status >= 0) _status = new_status; return _status; } /*---------------------------------------------------------- Little endian read/write API ----------------------------------------------------------*/ int pfile_t::read(unsigned int &x) { unsigned char b[4]; int result = read(&b, 4); if(4 == result) x = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); return result; } int pfile_t::read(int &x) { unsigned int ux; int result = read(ux); if(4 == result) x = (int)ux; return result; } int pfile_t::write(unsigned int x) { DBG(log_printf(D3LOG, "pfile_t::write(int)\n");) unsigned char b[4]; b[0] = x & 0xff; b[1] = (x >> 8) & 0xff; b[2] = (x >> 16) & 0xff; b[3] = (x >> 24) & 0xff; return status(write(&b, 4)); } int pfile_t::write(int x) { return status(write((unsigned int)x)); } /*---------------------------------------------------------- Unbuffered Write API ----------------------------------------------------------*/ int pfile_t::write_ub(void *data, int len) { DBG(log_printf(D3LOG, "pfile_t::write_ub(block of %d bytes)\n", len);) if(fwrite(data, len, 1, f) != 1) return status(-1); return _status; } int pfile_t::write_ub(unsigned int x) { unsigned char b[4]; b[0] = x & 0xff; b[1] = (x >> 8) & 0xff; b[2] = (x >> 16) & 0xff; b[3] = (x >> 24) & 0xff; return status(write_ub(&b, 4)); } int pfile_t::write_ub(int x) { return status(write_ub((unsigned int)x)); } /*---------------------------------------------------------- RIFF style chunk API ----------------------------------------------------------*/ int pfile_t::chunk_read() { unsigned int size; chunk_writing = 0; if(read(chunk_id) != 4) return _status; if(read(size) != 4) return _status; return buffer_read(size); } int pfile_t::chunk_write(int id) { chunk_writing = 1; chunk_id = id; buffer_init(); return _status; } int pfile_t::chunk_end() { if(chunk_writing) { write_ub(chunk_id); write_ub(bufused); buffer_write(); } buffer_close(); return _status; }