home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2005 June
/
ccd0605.iso
/
LINUX
/
gopchop-1.1.7.tar.tar
/
gopchop-1.1.7.tar
/
gopchop-1.1.7
/
src
/
file_buffer.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-08-25
|
6KB
|
235 lines
/*
#
# Utilities for seeking around in a file stream
#
# $Id: file_buffer.c,v 1.2 2003/08/25 08:17:41 nemies Exp $
#
# Copyright (C) 2001-2003 Kees Cook
# kees@outflux.net, http://outflux.net/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
#
*/
/*
* buffer management inspired by mplayer
*/
#include "file_buffer.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct file_buf_t
{
char * filename;
FILE *fp;
uint8_t * buffer;
off_t offset;
size_t buffer_min;
size_t buffer_max;
size_t buffer_malloc;
};
off_t buffer_tell(struct file_buf_t *fb)
{
if (!fb) return 0;
return fb->offset - fb->buffer_max + fb->buffer_min;
}
off_t buffer_file_size(struct file_buf_t *fb)
{
struct stat info;
if (!fb) return 0;
if (!(fstat(fileno(fb->fp), &info))<0) {
perror("fstat");
exit(1);
}
return info.st_size;
}
// can point to a file offset to refill from
int buffer_refill(struct file_buf_t *fb)
{
size_t got;
if (!fb)
return FILE_BUF_ERR_NULL_STRUCT;
//fprintf(stderr,"filling...\n");
if (fb->buffer_min < fb->buffer_max)
{
memmove(fb->buffer, fb->buffer + fb->buffer_min,
fb->buffer_max - fb->buffer_min);
}
fb->buffer_max -= fb->buffer_min;
fb->buffer_min = 0;
got =
fread(fb->buffer + fb->buffer_max, sizeof(uint8_t),
fb->buffer_malloc - fb->buffer_max, fb->fp);
if (got < 0)
return FILE_BUF_ERR_READ;
fb->offset += got;
fb->buffer_max += got;
//fprintf(stderr,"bump %d more\n",got);
return FILE_BUF_OKAY;
}
int buffer_seek(struct file_buf_t *fb, off_t location)
{
if (!fb)
return FILE_BUF_ERR_NULL_STRUCT;
// is this location within our current buffer?
if (location < fb->offset && location >= buffer_tell(fb)) {
fb->buffer_min += location - buffer_tell(fb);
}
else {
// outside: clear the buffer
fb->buffer_min = fb->buffer_max = 0; // clear buffer
fb->offset = location;
if (FSEEK(fb->fp, fb->offset, SEEK_SET) < 0) {
return FILE_BUF_ERR_SEEK;
}
}
//don't do this... way too slow
//buffer_refill();
return FILE_BUF_OKAY;
}
// A null return from "buffer_start" indicates that errno has been set,
// and calls to "perror" and the like are valid.
struct file_buf_t * buffer_start(struct file_buf_t *fb, char *filename,
size_t size)
{
FILE * fp=NULL;
uint8_t * buffer=NULL;
// check for fopen first, before dealing with memory allocation or
// making changes to the passed-in structure
if (!(fp = fopen(filename, "r"))) {
goto err_out;
}
if (!fb || fb->buffer_malloc != size) {
if (!(buffer=(uint8_t*)calloc(size,sizeof(uint8_t)))) {
goto err_out;
}
}
// create a buffer if it doesn't already exist
if (!fb) {
if (!(fb=(struct file_buf_t*)calloc(1,sizeof(*fb)))) {
goto err_out;
}
}
// swap out the new file handle
if (fb->fp)
fclose(fb->fp);
fb->fp = fp;
// swap out the new buffer
if (buffer) {
// drop the old buffer if we have a new one
if (fb->buffer)
free(fb->buffer);
fb->buffer = buffer;
}
// record our buffer size
fb->buffer_malloc = size;
// clear our counters
fb->offset = 0;
fb->buffer_min = 0;
fb->buffer_max = 0;
return fb;
err_out:
if (buffer)
free(buffer);
if (fp)
fclose(fp);
buffer_end(fb); // hm: well I guess I *will* muck with the passed in one
return NULL;
}
int buffer_end(struct file_buf_t *fb)
{
if (!fb)
return FILE_BUF_ERR_NULL_STRUCT;
if (fb->fp)
fclose(fb->fp);
if (fb->buffer)
free(fb->buffer);
free(fb);
return FILE_BUF_OKAY;
}
int buffer_get_byte(struct file_buf_t *fb, uint8_t * byte)
{
int ret;
if (!fb)
return FILE_BUF_ERR_NULL_STRUCT;
if (!byte)
return FILE_BUF_ERR_NULL_ARG;
if (fb->buffer_min == fb->buffer_max) {
if ((ret=buffer_refill(fb))!=FILE_BUF_OKAY)
return ret;
}
if (fb->buffer_min == fb->buffer_max)
return FILE_BUF_ERR_PAST_END;
//fprintf(stderr,"getting %" OFF_T_FORMAT "\n",buffer_tell(fb));
*byte = fb->buffer[fb->buffer_min++];
return FILE_BUF_OKAY;
}
int buffer_look_ahead(struct file_buf_t *fb, uint8_t * bytes, size_t count)
{
if (!fb)
return FILE_BUF_ERR_NULL_STRUCT;
if (!bytes)
return FILE_BUF_ERR_NULL_ARG;
if (count >= fb->buffer_malloc)
return FILE_BUF_ERR_COUNT_EXCEEDS_BUFFER_SIZE;
if (fb->buffer_min + count > fb->buffer_max)
buffer_refill(fb);
if (fb->buffer_min + count > fb->buffer_max)
return FILE_BUF_ERR_PAST_END;
memcpy(bytes,fb->buffer+fb->buffer_min,count);
/*
* for debugging:
for (i = 0; i < count; i++)
{
*(bytes++) = fb->buffer[fb->buffer_min + i];
//fprintf(stderr,"\tsaw: 0x%02X\n",buffer[buffer_min+i]);
}
*/
return FILE_BUF_OKAY;
}
/* vi:set ai ts=4 sw=4 expandtab: */