Files
redAcore/CharBufferCore.cpp

798 lines
23 KiB
C++

/*
* CharBufferCore.cpp
*
* Created on: 18 May 2016
* Author: wentzelc
*/
// Standard C/C++ Libraries
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// redA Libraries
#include "CharBufferCore.h"
//---------------------------------------------------------------------------
/***** Char Buffer *****/
CCharBuffer::CCharBuffer( int BufferSize ) : BufSize( BufferSize )
{
// Create Buffer
if (BufSize) {
// Create Buffer
Buffer = (char *)malloc( BufSize+1 );
memset( Buffer, 0, BufSize+1 );
// Create temp output buffer big enough to handle all data
OutBuffer = (char *)malloc( BufSize+1 );
}
else {
// No buffers created
Buffer = NULL;
OutBuffer = NULL;
}
// Set pointers
BufLen = 0;
}
//---------------------------------------------------------------------------
CCharBuffer::~CCharBuffer()
{
// Destroy Buffer
if (Buffer)
free( Buffer );
if (OutBuffer)
free( OutBuffer );
}
//---------------------------------------------------------------------------
// Clear all data from buffer
int CCharBuffer::Reset()
{
int BytesCleared = 0;
// Reset buffer
BytesCleared = BufLen;
BufLen = 0;
Buffer[0] = 0;
return BytesCleared;
}
//---------------------------------------------------------------------------
// Read first-in bytes from buffer
// Return "stitched" buffer data in temporary buffer
int CCharBuffer::Pop( char ** Data, int MaxLen )
{
int BytesWritten = 0;
// Read & clear data
BytesWritten = Peek( Data, 0, MaxLen );
Clear( BytesWritten );
// Return temp buffer
return BytesWritten;
}
//---------------------------------------------------------------------------
// Read first-in bytes from buffer
// Return "stitched" buffer data copied to pointer which if created if NULL
int CCharBuffer::PopCopy( char ** Data, int MaxLen )
{
int BytesWritten = 0;
// Copy & clear data
BytesWritten = PeekCopy( Data, 0, MaxLen );
Clear( BytesWritten );
// Return temp buffer
return BytesWritten;
}
//---------------------------------------------------------------------------
/***** Rolling Buffer *****/
CRollingBuffer::CRollingBuffer( int BufferSize ) : CCharBuffer( BufferSize )
{
// Set pointers
BufStart = 0;
BufEnd = 0;
}
//---------------------------------------------------------------------------
// Clear all data from buffer
int CRollingBuffer::Reset()
{
// Reset pointers
BufStart = 0;
BufEnd = 0;
return CCharBuffer::Reset();
}
//---------------------------------------------------------------------------
// Return specific character for current rolling data
char CRollingBuffer::PeekChar( int Pos )
{
char CharValue = 0;
// Validate buffer and Pos
if (!BufSize || (Pos < 0) || (Pos > BufLen))
return 0;
// Get char
if (BufStart + Pos < BufSize)
CharValue = Buffer[ BufStart+Pos ];
else
CharValue = Buffer[ BufStart+Pos-BufSize ];
// Return char
return CharValue;
}
//---------------------------------------------------------------------------
// Return pointer direct to buffer
// Data is not removed from buffer
// Return number of contiguous chars (cannot rollover)
int CRollingBuffer::PeekDirect( char ** Data, int PeekPos )
{
int BytesReturned = 0;
int StartPos = 0;
// Validate
if (!BufSize || !Data || (PeekPos > BufLen)) {
*Data = NULL;
return 0;
}
// Get reference
if (BufStart + StartPos < BufSize) {
StartPos = BufStart + PeekPos;
BytesReturned = (StartPos + BufLen > BufSize)? BufSize - StartPos : BufLen;
}
else {
StartPos = BufStart + PeekPos - BufSize;
BytesReturned = (StartPos + BufLen > BufEnd) ? BufEnd - StartPos : BufLen;
}
// Return buffer pointer
*Data = &Buffer[StartPos];
return BytesReturned;
}
//---------------------------------------------------------------------------
// Return "stitched" buffer data copied to pointer
// Pointer is created if NULL passed
// Data is not removed from buffer
int CRollingBuffer::Peek( char ** Data, int PeekPos, int MaxLen )
{
int BytesReturned = 0;
int StartPos = 0;
// Validate
if (!BufSize || !Data || !MaxLen || (PeekPos < 0) || (PeekPos > BufLen)) {
if (Data) *Data = NULL;
return 0;
}
// Get buffer start position
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
}
// Zero terminate
OutBuffer[BytesReturned] = 0;
// Return Temp buffer
*Data = OutBuffer;
return BytesReturned;
}
//---------------------------------------------------------------------------
// Return "stitched" buffer data in temporary buffer
// Data is not removed from buffer
int CRollingBuffer::PeekCopy( char ** Data, int PeekPos, int MaxLen )
{
int BytesReturned = 0;
int StartPos = 0;
// Check if any data
if (!BufSize || !Data || !MaxLen || (PeekPos < 0) || (PeekPos > BufLen)) {
if (Data && *Data) (*Data)[0] = 0;
return 0;
}
// Get start position
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;
// Allocate memory
if (!*Data)
*Data = (char*)malloc( BytesReturned + 1 );
// Copy Data from Buffer
if (StartPos + BytesReturned <= BufSize) {
memcpy( *Data, &Buffer[StartPos], BytesReturned );
}
else {
memcpy( *Data, &Buffer[StartPos], BufSize-StartPos ); // Copy from end of buffer
memcpy( &(*Data)[BufSize-StartPos], Buffer, (BytesReturned-(BufSize-StartPos)) ); // Copy rollover from start of buffer
}
(*Data)[BytesReturned] = 0;
return BytesReturned;
}
//---------------------------------------------------------------------------
// Look for first occurrence of character in buffer
bool CRollingBuffer::FindStr( const char * SearchStr, int SearchLen, int &FoundPos, int StartPos )
{
const char * CheckChar = NULL; // Current position in haystack
const char * CheckLimit = NULL; // Roll-over point in haystack
const char * CheckStart = NULL; // Reference to where match starts in haystack
const char * MatchChar = NULL; // Current match position in needle
const char * MatchLimit = NULL; // End of needle
// Check if buffer exists
if (!BufSize || !SearchStr || !SearchLen) {
FoundPos = -1;
return false;
}
// Validate start Pos
if (StartPos >= BufLen) {
FoundPos = -1;
return false;
}
// Get Search start point and roll-over of haystack
CheckChar = (BufStart + StartPos < BufSize)? &Buffer[ BufStart+StartPos ] : &Buffer[ (BufStart+StartPos)-BufSize ];
CheckLimit = &Buffer[BufSize-1];
// Set Match start point and limit of needle
MatchChar = SearchStr;
MatchLimit = &SearchStr[SearchLen-1];
// Search for needle in haystack
FoundPos = StartPos;
while (FoundPos < BufLen) {
// Check if char match
if (*CheckChar == *MatchChar) {
if (MatchChar == MatchLimit) {
// Whole needle found
FoundPos -= SearchLen-1;
return true;
}
else {
// More needle to find
if (MatchChar == SearchStr)
CheckStart = CheckChar; // Mark start of match
MatchChar++; // Continue matching needle
}
}
else if (MatchChar != SearchStr){
// Only partial needle found - reset match search
FoundPos -= MatchChar - SearchStr;
CheckChar = CheckStart;
MatchChar = SearchStr;
}
// Next char
FoundPos++;
if (CheckChar == CheckLimit)
CheckChar = Buffer; // Roll-over, Start at beginning of haystack
else
CheckChar++;
}
// Not Found
FoundPos = -1;
return false;
}
//---------------------------------------------------------------------------
// Remove data from start of buffer
int CRollingBuffer::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;
}
//---------------------------------------------------------------------------
// Add bytes to end of buffer
// Perform roll over if requied
// Option to overwrite existing data if longer than buffer length
int CRollingBuffer::Push( bool Overwrite, const char * Data, int Len )
{
int BytesPushed = 0;
int TotalPushed = 0;
int BufRemain = 0;
int DataRemain;
// Validate Buffer and Len
if (!BufSize || !Data || !Len)
return 0;
else if (Len == -1)
Len = strlen( Data );
// Prevent overwrite
DataRemain = (!Overwrite && (Len > BufSize-BufLen))? BufSize-BufLen : Len;
// Read Data into buffer
while (DataRemain) {
// 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 has caught up with tail, move tail up
BufLen = BufSize;
BufStart = BufEnd;
}
}
return TotalPushed;
}
//---------------------------------------------------------------------------
// Read File descriptor directly into rolling buffer
int CRollingBuffer::ReadFromFD( int Handle, int MaxRead, bool Overwrite )
{
int BytesRead = 0;
int TotalRead = 0;
int BufRemain = 0;
int DataRemain = 0;
bool Error = false;
// Check if buffer created
if (!BufSize)
return 0;
// Read file descriptor into buffer
if (MaxRead == -1)
MaxRead = BufSize;
DataRemain = ((!Overwrite && (MaxRead > BufSize-BufLen)))? BufSize-BufLen : MaxRead;
while (DataRemain) {
// Read from file descriptor
BufRemain = BufSize - BufEnd;
BytesRead = read( Handle, &Buffer[BufEnd], ((BufRemain > DataRemain)? DataRemain : BufRemain) );
if (BytesRead <= 0) {
Error = true;
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
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;
}
if (DataRemain)
usleep( 500 );
}
return (Error)? -TotalRead : TotalRead; // Report negative total on error
}
//---------------------------------------------------------------------------
// Write given number of bytes directly from buffer to File descriptor
int CRollingBuffer::WriteToFD( int Handle, int MaxLen )
{
int BytesWritten = 0;
int TotalWritten = 0;
int BufRemain = 0;
int DataRemain = (MaxLen == -1)? BufLen : MaxLen;;
int ReadPos = BufStart;
bool Error = false;
// Check if buffer created
if (!BufSize)
return 0;
// Read Data into buffer
while (DataRemain) {
// Read from file descriptor
BufRemain = BufSize - ReadPos;
BytesWritten = write( Handle, &Buffer[ReadPos], ((BufRemain > DataRemain)? DataRemain : BufRemain) );
if (BytesWritten <= 0) {
Error = true;
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
break;
}
// Update Data Pointers
TotalWritten += BytesWritten;
DataRemain -= BytesWritten;
// Update Buffer Pointers
ReadPos += BytesWritten;
if (ReadPos >= BufSize)
ReadPos = 0; // Rolling over end of buffer, start at beginning
if (DataRemain)
usleep( 500 );
}
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
}
//---------------------------------------------------------------------------
/***** Shifting Buffer *****/
CShiftBuffer::CShiftBuffer( int BufferSize ) :
CCharBuffer( BufferSize )
{
}
//---------------------------------------------------------------------------
// Return specific character for current rolling data
char CShiftBuffer::PeekChar( int Pos )
{
// Validate buffer and Pos
if (!BufSize || (Pos < 0) || (Pos > BufLen))
return 0;
// Return char
return Buffer[Pos];
}
//---------------------------------------------------------------------------
// Return pointer direct to buffer
// Return number of contiguous chars (cannot rollover)
int CShiftBuffer::PeekDirect( char ** Data, int PeekPos )
{
// Validate
if (!BufSize || !Data || (PeekPos > BufLen)) {
*Data = NULL;
return 0;
}
// Return buffer pointer
*Data = &Buffer[PeekPos];
return (BufLen - PeekPos);
}
//---------------------------------------------------------------------------
// Copy data into temporary buffer
int CShiftBuffer::Peek( char ** Data, int PeekPos, int MaxLen )
{
int BytesReturned = 0;
// Validate
if (!BufSize || !Data || !MaxLen || (PeekPos < 0) || (PeekPos > BufLen)) {
if (Data) *Data = NULL;
return 0;
}
// Calculate bytes to return
if ((MaxLen == -1) || (MaxLen > BufSize))
MaxLen = BufSize;
BytesReturned = (MaxLen > BufLen - PeekPos)? (BufLen - PeekPos) : MaxLen;
// Copy Data from Buffer
memcpy( OutBuffer, &Buffer[PeekPos], BytesReturned );
OutBuffer[BytesReturned] = 0;
// Return Temp buffer
*Data = OutBuffer;
return BytesReturned;
}
//---------------------------------------------------------------------------
// Return "stitched" buffer data in temporary buffer
// Data is not removed from buffer
int CShiftBuffer::PeekCopy( char ** Data, int PeekPos, int MaxLen )
{
int BytesReturned = 0;
int StartPos = 0;
// Check if any data
if (!BufSize || !Data || !MaxLen || (PeekPos < 0) || (PeekPos > BufLen)) {
if (Data && *Data) (*Data)[0] = 0;
return 0;
}
// Calculate bytes to return
if ((MaxLen == -1) || (MaxLen > BufSize))
MaxLen = BufSize;
BytesReturned = (MaxLen > BufLen - PeekPos)? (BufLen - PeekPos) : MaxLen;
// Allocate memory
if (!*Data)
*Data = (char*)malloc( BytesReturned + 1 );
// Copy Data from Buffer
memcpy( *Data, &Buffer[StartPos], BytesReturned );
(*Data)[BytesReturned] = 0;
return BytesReturned;
}
//---------------------------------------------------------------------------
// Look for first occurrence of character in buffer
bool CShiftBuffer::FindStr( const char * SearchStr, int SearchLen, int &FoundPos, int StartPos )
{
const char * CheckChar = NULL; // Current position in haystack
const char * CheckLimit = NULL; // End of haystack
const char * CheckStart = NULL; // Reference to where match starts in haystack
const char * MatchChar = NULL; // Current match position in needle
const char * MatchLimit = NULL; // End of needle
// Check if buffer exists
if (!BufSize || !SearchStr || !SearchLen) {
FoundPos = -1;
return false;
}
// Validate start Pos
if (StartPos >= BufLen) {
FoundPos = -1;
return false;
}
// Get Search start point and end of haystack
CheckChar = &Buffer[StartPos];
CheckLimit = &Buffer[BufLen-1];
// Set Match start point and limit of needle
MatchChar = (char*)SearchStr;
MatchLimit = (char*)&SearchStr[SearchLen-1];
// Search for char
FoundPos = StartPos;
while (FoundPos < BufLen) {
// Check if char match
if (*CheckChar == *MatchChar) {
if (MatchChar == MatchLimit) {
// Whole needle found
FoundPos -= SearchLen-1;
return true;
}
else {
// More needle to find
if (MatchChar == SearchStr)
CheckStart = CheckChar; // Mark start of match
MatchChar++; // Continue matching needle
}
}
else if (MatchChar != SearchStr){
// Only partial needle found - reset match search
FoundPos -= MatchChar - SearchStr;
CheckChar = CheckStart;
MatchChar = SearchStr;
}
// Next char
FoundPos++;
if (CheckChar == CheckLimit) // End of haystack reached
break;
else
CheckChar++;
}
// Not Found
FoundPos = -1;
return false;
}
//---------------------------------------------------------------------------
// Remove data from start of buffer
int CShiftBuffer::Clear( int ClearLen )
{
int BytesCleared;
// Validate ClearLen
if ((ClearLen == -1) || (ClearLen >= BufLen)) {
// Clear all data
BufLen = 0;
Buffer[0] = 0;
BytesCleared = BufLen;
}
else {
// Shift remaining data
memmove( Buffer, &Buffer[ClearLen], BufLen-ClearLen ); // Shift remaining old data left
BufLen -= ClearLen;
Buffer[BufLen] = 0;
BytesCleared = ClearLen;
}
return BytesCleared;
}
//---------------------------------------------------------------------------
// Add bytes to end of buffer
// Option to overwrite existing data if longer than buffer length
int CShiftBuffer::Push( bool Overwrite, const char * Data, int Len )
{
int BytesPushed = 0;
int BufRemain = 0;
// Validate Buffer and Len
if (!BufSize || !Data || !Len)
return 0;
else if (Len == -1)
Len = strlen( Data );
// Copy Data to buffer
BufRemain = BufSize - BufLen;
if (Overwrite && (Len > BufRemain)) {
if (Len < BufSize) {
memcpy( Buffer, &Buffer[Len-BufRemain], BufLen-(Len-BufRemain) ); // Shift remaining old data left
memcpy( &Buffer[BufSize-Len], Data, Len ); // Copy new data
BytesPushed = Len;
}
else {
memcpy( Buffer, &Data[Len-BufSize], BufSize ); // Copy last portion of new data
BytesPushed = Len;
}
// Update Pointers
BufLen = BufSize;
Buffer[BufLen] = 0;
}
else {
// Copy first portion of new data to buffer
BytesPushed = (Len > BufRemain)? BufRemain : Len;
memcpy( &Buffer[BufLen], Data, BytesPushed );
// Update Buffer Pointers
BufLen += BytesPushed;
Buffer[BufLen] = 0;
}
return BytesPushed;
}
//---------------------------------------------------------------------------
// Read File descriptor directly into buffer
int CShiftBuffer::ReadFromFD( int Handle, int MaxRead, bool Overwrite )
{
int BytesRead = 0;
int TotalRead = 0;
int DataRemain = MaxRead;
bool Error = false;
// Check if buffer created
if (!BufSize)
return 0;
// Read file descriptor into buffer
if (MaxRead == -1)
MaxRead = BufSize;
DataRemain = ((!Overwrite && (MaxRead > BufSize-BufLen)))? BufSize-BufLen : MaxRead;
while (DataRemain) {
// Read from file descriptor
BytesRead = read( Handle, &Buffer[BufLen], DataRemain );
if (BytesRead <= 0) {
Error = true;
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
break;
}
// Update Buffer Pointers
DataRemain -= BytesRead;
TotalRead += BytesRead;
BufLen += BytesRead;
// Zero terminate
Buffer[BufLen] = 0;
if (DataRemain)
usleep( 500 );
}
return (Error)? -TotalRead : TotalRead; // Report negative total on error
}
//---------------------------------------------------------------------------
// Write given number of bytes directly from buffer to File descriptor
int CShiftBuffer::WriteToFD( int Handle, int MaxLen )
{
int BytesWritten = 0;
int TotalWritten = 0;
int BufRemain = 0;
int DataRemain = ((MaxLen == -1) || (MaxLen > BufLen))? BufLen : MaxLen;
int ReadPos = 0;
bool Error = false;
// Check if buffer created
if (!BufSize)
return 0;
// Read Data into buffer
while (DataRemain) {
// Read from file descriptor
BufRemain = BufSize - ReadPos;
BytesWritten = write( Handle, &Buffer[ReadPos], ((BufRemain > DataRemain)? DataRemain : BufRemain) );
if (BytesWritten <= 0) {
Error = true;
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
break;
}
// Update Data Pointers
TotalWritten += BytesWritten;
DataRemain -= BytesWritten;
// Update Buffer Pointers
ReadPos += BytesWritten;
if (ReadPos >= BufSize)
ReadPos = 0; // Rolling over end of buffer, start at beginning
if (DataRemain)
usleep( 500 );
}
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
}
//---------------------------------------------------------------------------