Files
redAcore/BufferCore.cpp
Charl Wentzel 839c8a1432 Important Update:
- Improve parameter checking before function execution
- Rename functions:
  Get->Peek, ReadFD->ReadFromFD, WriteFD->WriteToFD
- Add StartPos param to Peek() & FindChar()
- Add ClearChar param for GetChar()
- Add default values for Position and Lengths
  Get, Set, Clear, Push, Peek, GetChar, FindChar
2016-05-19 07:44:28 +02:00

386 lines
9.4 KiB
C++

/*
* BufferCore.cpp
*
* Created on: 18 May 2016
* Author: wentzelc
*/
// redA Libraries
#include "BufferCore.h"
// Standard C/C++ Libraries
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
//---------------------------------------------------------------------------
CBuffer::CBuffer( int BufferSize ) : BufSize( BufferSize )
{
// Create Buffer
if (BufSize) {
Buffer = (char *)malloc( BufSize+1 );
OutBuffer = (char *)malloc( BufSize+1 );
}
else {
Buffer = NULL;
OutBuffer = NULL;
}
// Set pointers
BufStart = 0;
BufEnd = 0;
BufLen = 0;
}
//---------------------------------------------------------------------------
CBuffer::~CBuffer()
{
// Destroy Buffer
if (Buffer) {
free( Buffer );
}
if (OutBuffer) {
free( OutBuffer );
}
}
//---------------------------------------------------------------------------
// Over write existing buffer with new data
int CBuffer::Set( const char * Data, int Len )
{
// Validate data
if (!Data || !Len) {
return 0;
}
else if (Len == -1) {
Len = strlen( Data );
}
if (Len <= BufSize) {
memcpy( Buffer, Data, Len );
BufStart = 0;
BufEnd = Len;
BufLen = Len;
}
else {
memcpy( Buffer, &Data[Len-BufSize], BufSize );
BufStart = 0;
BufEnd = 0;
BufLen = BufSize;
}
return BufLen;
}
//---------------------------------------------------------------------------
// Return "stitched" buffer data in temporary buffer
int CBuffer::Peek( char ** Data, int PeekPos, int MaxLen )
{
int BytesReturned = 0;
int StartPos = 0;
// Check if any data
if (!BufLen || !MaxLen) {
*Data = NULL;
return 0;
}
// Validate start position
if (PeekPos >= BufLen) {
*Data = NULL;
return 0;
}
else if (BufStart + StartPos < BufSize) {
StartPos = BufStart + PeekPos;
}
else {
StartPos = BufStart + PeekPos - BufSize;
}
// Validate MaxLen
if ((MaxLen == -1) || (MaxLen > BufSize)) {
MaxLen = BufSize;
}
BytesReturned = (MaxLen > BufLen - PeekPos)? (BufLen - PeekPos) : MaxLen;
// Copy Data from Buffer
if (StartPos + BytesReturned <= BufSize) {
memcpy( OutBuffer, &Buffer[StartPos], BytesReturned );
}
else {
memcpy( OutBuffer, &Buffer[StartPos], BufSize-StartPos ); // Copy from end of buffer
memcpy( &OutBuffer[BufSize-StartPos], Buffer, (BytesReturned-(BufSize-StartPos)) ); // Copy rollover from start of buffer
}
OutBuffer[BytesReturned] = 0;
// Return Temp buffer
*Data = OutBuffer;
return BytesReturned;
}
//---------------------------------------------------------------------------
int CBuffer::Clear( int ClearLen )
{
int BytesCleared;
// Validate ClearLen
if (ClearLen == -1) {
BytesCleared = BufLen;
}
else {
BytesCleared = (ClearLen > BufLen)? BufLen : ClearLen;
}
// Update Buffer pointers
if (BufStart + BytesCleared < BufSize) {
BufStart += BytesCleared;
} else {
BufStart = (BytesCleared-(BufSize-BufStart)); // Copy roll-over from start of buffer
}
BufLen -= BytesCleared;
return BytesCleared;
}
//---------------------------------------------------------------------------
int CBuffer::Reset()
{
int BytesCleared = 0;
// Clear all data
BytesCleared = BufLen;
BufStart = 0;
BufEnd = 0;
BufLen = 0;
return BytesCleared;
}
//---------------------------------------------------------------------------
// Add bytes to end of buffer
// Return "stitched" buffer data in temporary buffer
int CBuffer::Push( const char * Data, int Len )
{
int BytesPushed = 0;
int TotalPushed = 0;
int BufRemain = 0;
int DataRemain = Len;
// Validate Buffer and Len
if (!BufSize || !Len) {
return 0;
}
else if (Len == -1) {
Len = strlen( Data );
}
// Read Data into buffer
while (TotalPushed < Len)
{
// Read from file descriptor
BufRemain = BufSize - BufEnd;
BytesPushed = ((BufRemain > DataRemain)? DataRemain : BufRemain);
memcpy( &Buffer[BufEnd], &Data[TotalPushed], BytesPushed );
// Update Data Pointers
TotalPushed += BytesPushed;
DataRemain -= BytesPushed;
// Update Buffer Pointers
BufLen += BytesPushed;
BufEnd += BytesPushed;
if (BufEnd >= BufSize) {
// Rolling over end of buffer, start at beginning
BufEnd = 0;
}
if (BufLen > BufSize) {
// Head is caught up with tail, move tail up
BufLen = BufSize;
BufStart = BufEnd;
}
}
return TotalPushed;
}
//---------------------------------------------------------------------------
// Read first-in bytes from buffer
// Return "stitched" buffer data in temporary buffer
int CBuffer::Pop( char ** Data, int MaxLen )
{
int BytesWritten = 0;
// Read data
BytesWritten = Peek( Data, MaxLen );
// Clear bytes
Clear( BytesWritten );
// Return temp buffer
return BytesWritten;
}
//---------------------------------------------------------------------------
// Read File descriptor directly into rolling buffer
int CBuffer::ReadFromFD( int Handle, int MaxRead )
{
int BytesRead = 0;
int TotalRead = 0;
int BufRemain = 0;
int DataRemain = 0;
// Check if buffer created
if (!BufSize) {
return 0;
}
// Read file descriptor into buffer
DataRemain = (MaxRead == -1)? BufSize : MaxRead;
while (DataRemain)
{
// Read from file descriptor
BufRemain = BufSize - BufEnd;
BytesRead = read( Handle, &Buffer[BufEnd], ((BufRemain > DataRemain)? DataRemain : BufRemain) );
if (BytesRead <= 0)
break;
// Update Buffer Pointers
DataRemain -= BytesRead;
TotalRead += BytesRead;
BufLen += BytesRead;
BufEnd += BytesRead;
if (BufEnd >= BufSize) {
// Rolling over end of buffer, start at beginning
BufEnd = 0;
}
if (BufLen > BufSize) {
// Head is caught up with tail, move tail up
BufLen = BufSize;
BufStart = BufEnd;
}
}
return TotalRead;
}
//---------------------------------------------------------------------------
// Write given number of bytes directly from buffer to File descriptor
int CBuffer::WriteToFD( int Handle, int MaxLen )
{
int BytesWritten = 0;
int TotalWritten = 0;
int BufRemain = 0;
int DataRemain = 0;
int ReadPos = 0;
// Check if buffer created
if (!BufSize) {
return 0;
}
// Read Data into buffer
ReadPos = BufStart;
DataRemain = (MaxLen == -1)? BufLen : MaxLen;
while ((TotalWritten < MaxLen) && (BufLen > 0))
{
// Read from file descriptor
BufRemain = BufSize - ReadPos;
BytesWritten = write( Handle, &Buffer[ReadPos], ((BufRemain > DataRemain)? DataRemain : BufRemain) );
if (BytesWritten <= 0)
break;
// Update Data Pointers
TotalWritten += BytesWritten;
DataRemain -= BytesWritten;
// Update Buffer Pointers
BufLen -= BytesWritten;
ReadPos += BytesWritten;
if (ReadPos >= BufSize) {
ReadPos = 0; // Rolling over end of buffer, start at beginning
}
}
return TotalWritten;
}
//---------------------------------------------------------------------------
// Return specific character for current rolling data
char CBuffer::PeekChar( int Pos, bool ClearChar )
{
char CharValue = 0;
// Validate buffer and Pos
if (!BufLen) {
return 0;
}
// Get char
if (BufStart + Pos < BufSize) {
CharValue = Buffer[ BufStart+Pos ];
}
else {
CharValue = Buffer[ BufStart+Pos-BufSize ];
}
// Clear Char
if (ClearChar && (Pos == 0)) {
BufStart++;
BufLen--;
}
// Return char
return CharValue;
}
//---------------------------------------------------------------------------
// Look for first occurrence of character in buffer
bool CBuffer::FindChar( char SearchChar, int &FoundPos, int StartPos )
{
char * CheckPos;
char * Limit;
// Check if buffer exists
if (!BufLen) {
FoundPos = -1;
return false;
}
// Validate start Pos
if (StartPos >= BufLen) {
FoundPos = -1;
return false;
}
// Get Search start point
if (BufStart + StartPos < BufSize) {
CheckPos = &Buffer[ BufStart+StartPos ];
} else {
CheckPos = &Buffer[ (BufStart+StartPos)-BufSize ];
}
// Search for char
FoundPos = StartPos;
Limit = &Buffer[BufSize-1];
while (FoundPos < BufLen)
{
if (*CheckPos == SearchChar)
return true;
// Next char
FoundPos++;
if (CheckPos == Limit) {
CheckPos = Buffer; // Roll-over, Start at beginning of buffer
} else {
CheckPos++;
}
}
// Not Found
FoundPos = -1;
return false;
}
//---------------------------------------------------------------------------