kobodl/pfile.cpp
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

283 lines
5.1 KiB
C++

/*(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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}