// 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;
 
 
 
   // 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
 
   }
 
 
 
   memcpy (&buffer->data[write_index], data, data_size); // write data in place
 
   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);
 
}