- 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
386 lines
9.4 KiB
C++
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;
|
|
}
|
|
//---------------------------------------------------------------------------
|