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>
283 lines
5.1 KiB
C++
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;
|
|
}
|