Skip to content
Permalink
Browse files
Added buffering API.
  • Loading branch information
icculus committed Dec 1, 2002
1 parent c1cf146 commit 3ad51e49e4c1cfe2cbfafc27d3a73dd904b00578
Showing with 561 additions and 29 deletions.
  1. +173 −8 physfs.c
  2. +93 −17 physfs.h
  3. +25 −0 physfs_internal.h
  4. +270 −4 test/test_physfs.c
181 physfs.c
@@ -1227,12 +1227,22 @@ int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
if (h->funcs->isSymLink(h, str, &retval))
{
__PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
retval = 0;
free(str);
return(0); /* insecure. */
} /* if */

/* break out early if path element is missing or it's a symlink. */
/* break out early if path element is missing. */
if (!retval)
{
/*
* We need to clear it if it's the last element of the path,
* since this might be a non-existant file we're opening
* for writing...
*/
if (end == NULL)
retval = 1;
break;
} /* if */
} /* if */

if (end == NULL)
@@ -1569,6 +1579,9 @@ static PHYSFS_file *doOpenWrite(const char *fname, int appending)
free(list);
else
{
rc->buffer = NULL; /* just in case. */
rc->buffill = rc->bufpos = rc->bufsize = 0; /* just in case. */
rc->forReading = 0;
list->handle.opaque = (void *) rc;
list->next = openWriteList;
openWriteList = list;
@@ -1615,13 +1628,17 @@ PHYSFS_file *PHYSFS_openRead(const char *fname)
BAIL_IF_MACRO_MUTEX(rc == NULL, NULL, stateLock, NULL);

list = (FileHandleList *) malloc(sizeof (FileHandleList));
BAIL_IF_MACRO(!list, ERR_OUT_OF_MEMORY, NULL);
BAIL_IF_MACRO_MUTEX(!list, ERR_OUT_OF_MEMORY, stateLock, NULL);
list->handle.opaque = (void *) rc;
list->next = openReadList;
openReadList = list;
retval = &(list->handle);

__PHYSFS_platformReleaseMutex(stateLock);

rc->buffer = NULL; /* just in case. */
rc->buffill = rc->bufpos = rc->bufsize = 0; /* just in case. */
rc->forReading = 1;

return(retval);
} /* PHYSFS_openRead */

@@ -1631,16 +1648,22 @@ static int closeHandleInOpenList(FileHandleList **list, PHYSFS_file *handle)
FileHandle *h = (FileHandle *) handle->opaque;
FileHandleList *prev = NULL;
FileHandleList *i;
int rc;
int rc = 1;

for (i = *list; i != NULL; i = i->next)
{
if (&i->handle == handle) /* handle is in this list? */
{
rc = h->funcs->fileClose(h);
PHYSFS_uint8 *tmp = h->buffer;
rc = PHYSFS_flush(handle);
if (rc)
rc = h->funcs->fileClose(h);
if (!rc)
return(-1);

if (tmp != NULL) /* free any associated buffer. */
free(tmp);

if (prev == NULL)
*list = i->next;
else
@@ -1677,39 +1700,122 @@ int PHYSFS_close(PHYSFS_file *handle)
} /* PHYSFS_close */


static PHYSFS_sint64 doBufferedRead(PHYSFS_file *handle, void *buffer,
PHYSFS_uint32 objSize,
PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;
PHYSFS_sint64 retval = 0;
PHYSFS_uint32 remainder = 0;

while (objCount > 0)
{
PHYSFS_uint64 buffered = h->buffill - h->bufpos;
PHYSFS_uint64 mustread = (objSize * objCount) - remainder;
PHYSFS_uint32 copied;

if (buffered == 0) /* need to refill buffer? */
{
PHYSFS_sint64 rc = h->funcs->read(h, h->buffer, 1, h->bufsize);
if (rc <= 0)
{
h->bufpos -= remainder;
return(((rc == -1) && (retval == 0)) ? -1 : retval);
} /* if */

buffered = h->buffill = rc;
h->bufpos = 0;
} /* if */

if (buffered > mustread)
buffered = mustread;

memcpy(buffer, h->buffer + h->bufpos, (size_t) buffered);
buffer = ((PHYSFS_uint8 *) buffer) + buffered;
h->bufpos += buffered;
buffered += remainder; /* take remainder into account. */
copied = (buffered / objSize);
remainder = (buffered % objSize);
retval += copied;
objCount -= copied;
} /* while */

return(retval);
} /* doBufferedRead */


PHYSFS_sint64 PHYSFS_read(PHYSFS_file *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;

BAIL_IF_MACRO(!h->forReading, ERR_FILE_ALREADY_OPEN_W, -1);
if (h->buffer != NULL)
return(doBufferedRead(handle, buffer, objSize, objCount));

return(h->funcs->read(h, buffer, objSize, objCount));
} /* PHYSFS_read */


static PHYSFS_sint64 doBufferedWrite(PHYSFS_file *handle, const void *buffer,
PHYSFS_uint32 objSize,
PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;

/* whole thing fits in the buffer? */
if (h->buffill + (objSize * objCount) < h->bufsize)
{
memcpy(h->buffer + h->buffill, buffer, objSize * objCount);
h->buffill += (objSize * objCount);
return(objCount);
} /* if */

/* would overflow buffer. Flush and then write the new objects, too. */
BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, -1);
return(h->funcs->write(h, buffer, objSize, objCount));
} /* doBufferedWrite */


PHYSFS_sint64 PHYSFS_write(PHYSFS_file *handle, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;

BAIL_IF_MACRO(h->forReading, ERR_FILE_ALREADY_OPEN_R, -1);
if (h->buffer != NULL)
return(doBufferedWrite(handle, buffer, objSize, objCount));

return(h->funcs->write(h, buffer, objSize, objCount));
} /* PHYSFS_write */


int PHYSFS_eof(PHYSFS_file *handle)
{
FileHandle *h = (FileHandle *) handle->opaque;
return(h->funcs->eof(h));

if (!h->forReading) /* never EOF on files opened for write/append. */
return(0);

/* eof if buffer is empty and archiver says so. */
return((h->bufpos == h->buffill) && (h->funcs->eof(h)));
} /* PHYSFS_eof */


PHYSFS_sint64 PHYSFS_tell(PHYSFS_file *handle)
{
FileHandle *h = (FileHandle *) handle->opaque;
return(h->funcs->tell(h));
PHYSFS_sint64 retval = h->forReading ?
(h->funcs->tell(h) - h->buffill) + h->bufpos :
(h->funcs->tell(h) + h->buffill);
return(retval);
} /* PHYSFS_tell */


int PHYSFS_seek(PHYSFS_file *handle, PHYSFS_uint64 pos)
{
FileHandle *h = (FileHandle *) handle->opaque;
BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
return(h->funcs->seek(h, pos));
} /* PHYSFS_seek */

@@ -1721,6 +1827,65 @@ PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_file *handle)
} /* PHYSFS_filelength */


int PHYSFS_setBuffer(PHYSFS_file *handle, PHYSFS_uint64 bufsize)
{
FileHandle *h = (FileHandle *) handle->opaque;

BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);

/*
* For reads, we need to move the file pointer to where it would be
* if we weren't buffering, so that the next read will get the
* right chunk of stuff from the file. PHYSFS_flush() handles writes.
*/
if ((h->forReading) && (h->buffill != h->bufpos))
{
PHYSFS_uint64 pos;
PHYSFS_sint64 curpos = h->funcs->tell(h);
BAIL_IF_MACRO(curpos == -1, NULL, 0);
pos = ((curpos - h->buffill) + h->bufpos);
BAIL_IF_MACRO(!h->funcs->seek(h, pos), NULL, 0);
} /* if */

if (bufsize == 0) /* delete existing buffer. */
{
if (h->buffer != NULL)
{
free(h->buffer);
h->buffer = NULL;
} /* if */
} /* if */

else
{
PHYSFS_uint8 *newbuf = realloc(h->buffer, bufsize);
BAIL_IF_MACRO(newbuf == NULL, ERR_OUT_OF_MEMORY, 0);
h->buffer = newbuf;
} /* else */

h->bufsize = bufsize;
h->buffill = h->bufpos = 0;
return(1);
} /* PHYSFS_setBuffer */


int PHYSFS_flush(PHYSFS_file *handle)
{
FileHandle *h = (FileHandle *) handle->opaque;
PHYSFS_sint64 rc;

if ((h->forReading) || (h->bufpos == h->buffill))
return(1); /* open for read or buffer empty are successful no-ops. */

/* dump buffer to disk. */
rc = h->funcs->write(h, h->buffer + h->bufpos, h->buffill - h->bufpos, 1);
BAIL_IF_MACRO(rc <= 0, NULL, 0);

h->bufpos = h->buffill = 0;
return(1);
} /* PHYSFS_flush */


LinkedStringList *__PHYSFS_addToLinkedStringList(LinkedStringList *retval,
LinkedStringList **prev,
const char *str,

0 comments on commit 3ad51e4

Please sign in to comment.