// buffer.cpp
#include "common.h"
// cross-platform facilities
#ifndef _WIN32
#define fopen_s(fp,filename,mode) *(fp) = fopen (filename, mode)
#endif // _WIN32
void Buffer_Initialize (buffer_t *buffer)
{
// this function initializes a new buffer_t structure, resetting its data pointer and size.
buffer->data = NULL; // allocate max_size bytes for data
buffer->size = 0; // reset size
return; // finished, buffer structure is empty
}
void Buffer_Forget (buffer_t *buffer)
{
// this function forgets a buffer's contents, freeing its associated memory buffer,
// and resets the buffer_t structure.
if (buffer->data != NULL)
free (buffer->data); // free buffer data
buffer->data = NULL;
buffer->size = 0; // reset data size
return; // finished, buffer structure is virgin again
}
int Buffer_Append (buffer_t *buffer, char *data, unsigned long data_size)
{
// this function appends the content of data to a buffer's data.
// Returns 1 on success, 0 on error.
char *new_data;
// first, reallocate space to hold data_size bytes more
new_data = (char *) realloc (buffer->data, buffer->size + data_size);
if (new_data == NULL)
return (0); // on failure, return an error value
buffer->data = new_data; // save pointer to reallocated data
memcpy (&buffer->data[buffer->size], data, data_size); // write new data at the end
buffer->size += data_size; // and increment buffer size
return (1); // buffer appended successfully, return SUCCESS
}
int Buffer_Prepend (buffer_t *buffer, char *data, unsigned long data_size)
{
// this function prepends the content of data to a buffer's data.
// Returns 1 on success, 0 on error.
char *new_data;
// first, reallocate space to hold data_size bytes more
new_data = (char *) realloc (buffer->data, data_size + buffer->size);
if (new_data == NULL)
return (0); // on failure, return an error value
buffer->data = new_data; // save pointer to reallocated data
if (buffer->size > 0)
memmove (&buffer->data[data_size], buffer->data, buffer->size); // move existing data to the end
memcpy (buffer->data, data, data_size); // write new data at the beginning
buffer->size += data_size; // and increment buffer size
return (1); // buffer appended successfully, return SUCCESS
}
int Buffer_WriteAt (buffer_t *buffer, unsigned long write_index, char *data, unsigned long data_size)
{
// this function writes the content of data to a buffer's data at position write_index.
// Returns 1 on success, 0 on error.
char *new_data;
char *dest;
// see if we need to grow the data
if (write_index + data_size > buffer->size)
{
// if so, reallocate data buffer at the right size
new_data = (char *) realloc (buffer->data, write_index + data_size);
if (new_data == NULL)
return (0); // on failure, return an error value
buffer->data = new_data; // save pointer to reallocated data
}
// do dest and source overlap ?
dest = &buffer->data[write_index];
if (((data <= dest) && (data + data_size > dest)) || ((dest <= data) && (dest + data_size > data)))
memmove (&buffer->data[write_index], data, data_size); // if so, move data in place
else
memcpy (&buffer->data[write_index], data, data_size); // else write data in place (faster)
if (write_index + data_size > buffer->size)
buffer->size = write_index + data_size; // update data size only if it growed
return (1); // buffer written successfully, return SUCCESS
}
int Buffer_ReadFromFile (buffer_t *buffer, const char *file_pathname)
{
// this function copies the contents of file_pathname in a newly allocated data buffer
// and fills in the buffer size accordingly. It is up to the caller to free that buffer.
// Returns 1 on success, 0 on error.
struct stat stat_buffer;
FILE *fp;
// start by reporting a zero length
buffer->size = 0;
// figure out file existence and size
if (stat (file_pathname, &stat_buffer) != 0)
return (0); // on failure, return an error value
// allocate enough space for it
if ((buffer->data = (char *) malloc (stat_buffer.st_size)) == NULL)
return (0); // on failure, return an error value
// open it for binary reading
fopen_s (&fp, file_pathname, "rb");
if (fp == NULL)
{
free (buffer->data);
return (0); // on failure, return an error value
}
// and read it at once
if (fread (buffer->data, 1, stat_buffer.st_size, fp) != (size_t) stat_buffer.st_size)
{
free (buffer->data);
return (0); // on failure, return an error value
}
fclose (fp); // finished, close file
buffer->size = stat_buffer.st_size; // report its size
return (1); // and return SUCCESS
}
int Buffer_ReadFromFileW (buffer_t *buffer, const wchar_t *file_pathname)
{
// this function copies the contents of file_pathname in a newly allocated data buffer
// and fills in the buffer size accordingly. It is up to the caller to free that buffer.
// Returns 1 on success, 0 on error.
struct _stat stat_buffer;
FILE *fp;
// start by reporting a zero length
buffer->size = 0;
// figure out file existence and size
if (_wstat (file_pathname, &stat_buffer) != 0)
return (0); // on failure, return an error value
// allocate enough space for it
if ((buffer->data = (char *) malloc (stat_buffer.st_size)) == NULL)
return (0); // on failure, return an error value
// open it for binary reading
_wfopen_s (&fp, file_pathname, L"rb");
if (fp == NULL)
{
free (buffer->data);
return (0); // on failure, return an error value
}
// and read it at once
if (fread (buffer->data, 1, stat_buffer.st_size, fp) != (size_t) stat_buffer.st_size)
{
free (buffer->data);
return (0); // on failure, return an error value
}
fclose (fp); // finished, close file
buffer->size = stat_buffer.st_size; // report its size
return (1); // and return SUCCESS
}
int Buffer_WriteToFile (buffer_t *buffer, const char *file_pathname)
{
// this function copies the contents of buffer's data into the file pointed to by
// file_pathname. Returns 1 on success, 0 on error.
FILE *fp;
// open file for binary writing
fopen_s (&fp, file_pathname, "wb");
if (fp == NULL)
return (0);
// and write it at once
if (fwrite (buffer->data, 1, buffer->size, fp) != (size_t) buffer->size)
return (0);
fclose (fp); // finished, close file
return (1); // and return SUCCESS
}
int Buffer_WriteToFileW (buffer_t *buffer, const wchar_t *file_pathname)
{
// this function copies the contents of buffer's data into the file pointed to by
// file_pathname. Returns 1 on success, 0 on error.
FILE *fp;
// open file for binary writing
_wfopen_s (&fp, file_pathname, L"wb");
if (fp == NULL)
return (0);
// and write it at once
if (fwrite (buffer->data, 1, buffer->size, fp) != (size_t) buffer->size)
return (0);
fclose (fp); // finished, close file
return (1); // and return SUCCESS
}
char *Buffer_Find (buffer_t *buffer, char *needle, unsigned long needle_length)
{
// returns a pointer to the first occurence of needle in buffer haystack, or NULL if not found
unsigned long byte_index;
if (buffer->size < needle_length)
return (NULL); // consistency check: if buffer is too small for needle, return NULL
// parse buffer from start to end
for (byte_index = 0; byte_index < buffer->size - needle_length; byte_index++)
if (memcmp (&buffer->data[byte_index], needle, needle_length) == 0)
return (&buffer->data[byte_index]); // return the first match we find
return (NULL); // definitely no needle in buffer
}
int Buffer_Compare (buffer_t *buffer1, buffer_t *buffer2)
{
// compares two buffers and return 0 if they match, non-zero if they differ.
// If their size differ, the difference between both is returned.
// If their content differ, the result of memcmp() is returned.
if (buffer1->size != buffer2->size)
return (buffer2->size - buffer1->size); // buffers differ in size
return (memcmp (buffer1->data, buffer2->data, buffer1->size)); // do a memcmp() on both buffers
}
unsigned long Buffer_OffsetOf (buffer_t *buffer, void *something)
{
// returns the absolute offset of the data pointed to by something relatively to the beginning of buffer data
return ((unsigned long) something - (unsigned long) buffer->data);
}