/* * BufferCore.cpp * * Created on: 18 May 2016 * Author: wentzelc */ // redA Libraries #include "BufferCore.h" // Standard C/C++ Libraries #include #include #include #include //--------------------------------------------------------------------------- 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 (DataRemain) { // 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 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::FindStr( const char * SearchStr, int SearchLen, int &FoundPos, int StartPos ) { char * CheckPos = NULL; char * CheckLimit = NULL; char * MatchPos = NULL; char * MatchLimit = NULL; // Check if buffer exists if (!BufLen) { FoundPos = -1; return false; } // Validate start Pos if (StartPos >= BufLen) { FoundPos = -1; return false; } // Get Search start point and limit CheckPos = (BufStart + StartPos < BufSize)? &Buffer[ BufStart+StartPos ] : &Buffer[ (BufStart+StartPos)-BufSize ]; CheckLimit = &Buffer[BufSize-1]; // Set Match start point and limit MatchPos = (char*)SearchStr; MatchLimit = (char*)&SearchStr[SearchLen-1]; // Search for char FoundPos = StartPos; while (FoundPos < BufLen) { // Check if char match if (*CheckPos == *MatchPos) { if (MatchPos == MatchLimit) // Full match found return true; else // Next char to match MatchPos++; } else { // Reset match point MatchPos = (char*)SearchStr; } // Next char FoundPos++; if (CheckPos == CheckLimit) { CheckPos = Buffer; // Roll-over, Start at beginning of buffer } else { CheckPos++; } } // Not Found FoundPos = -1; return false; } //---------------------------------------------------------------------------