/* * BufferCore.cpp * * Created on: 18 May 2016 * Author: wentzelc */ // redA Libraries #include "BufferCore.h" // Standard C/C++ Libraries #include #include #include #include #include //--------------------------------------------------------------------------- /***** Rolling Buffer *****/ CRollingBuffer::CRollingBuffer( 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 BufStart = 0; BufEnd = 0; BufLen = 0; } //--------------------------------------------------------------------------- CRollingBuffer::~CRollingBuffer() { // Destroy Buffer if (Buffer) { free( Buffer ); } if (OutBuffer) { free( OutBuffer ); } } //--------------------------------------------------------------------------- // Clear all data from buffer int CRollingBuffer::Reset() { int BytesCleared = 0; // Clear buffer BytesCleared = BufLen; // Reset pointers BufStart = 0; BufEnd = 0; BufLen = 0; return BytesCleared; } //--------------------------------------------------------------------------- // 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)) { *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)[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 ) { char * CheckPos = NULL; char * CheckLimit = NULL; char * MatchPos = NULL; char * MatchLimit = NULL; // 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 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 FoundPos -= SearchLen-1; 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; } //--------------------------------------------------------------------------- // 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 first-in bytes from buffer // Return "stitched" buffer data in temporary buffer int CRollingBuffer::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 CRollingBuffer::PopCopy( char ** Data, int MaxLen ) { int BytesWritten = 0; // Copy & clear data BytesWritten = PeekCopy( Data, 0, MaxLen ); Clear( BytesWritten ); // Return temp buffer return BytesWritten; } //--------------------------------------------------------------------------- // 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; // Check if buffer created if (!BufSize) { return 0; } // Read file descriptor into buffer if (Overwrite && (MaxRead > BufLen)) { DataRemain = MaxRead; } else { DataRemain = BufLen; } 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 CRollingBuffer::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; } //--------------------------------------------------------------------------- /***** Shifting Buffer *****/ CShiftBuffer::CShiftBuffer( int BufferSize ) : BufSize( BufferSize ) { // Create Buffer if (BufSize) { // Create Buffer Buffer = (char *)malloc( BufSize+1 ); Buffer[0] = 0; // Create temp output buffer big enough to handle all data OutBuffer = (char *)malloc( BufSize+1 ); } else { // No buffers created Buffer = NULL; OutBuffer = NULL; } // Set vars BufLen = 0; } //--------------------------------------------------------------------------- CShiftBuffer::~CShiftBuffer() { // Destroy Buffer if (Buffer) { free( Buffer ); } if (OutBuffer) { free( OutBuffer ); } } //--------------------------------------------------------------------------- // Clear all data from buffer int CShiftBuffer::Reset() { int BytesCleared = 0; // Reset buffer BytesCleared = BufLen; BufLen = 0; Buffer[0] = 0; return BytesCleared; } //--------------------------------------------------------------------------- // 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)) { *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)[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 ) { char * CheckPos = NULL; char * CheckLimit = NULL; char * MatchPos = NULL; char * MatchLimit = NULL; // 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 limit CheckPos = &Buffer[StartPos]; CheckLimit = &Buffer[BufLen-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 FoundPos -= SearchLen-1; return true; } else { // Next char to match MatchPos++; } } else { // Reset match point MatchPos = (char*)SearchStr; } // Next char FoundPos++; if (CheckPos == CheckLimit) { break; } else { CheckPos++; } } // 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 BytesCleared = BufLen; BufLen = 0; Buffer[0] = 0; } else { // Shift remaining data BytesCleared = ClearLen; memmove( Buffer, &Buffer[ClearLen], BufLen-ClearLen ); // Shift remaining old data left BufLen -= ClearLen; Buffer[BufLen] = 0; } 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 first-in bytes from buffer // Return "stitched" buffer data in temporary buffer int CShiftBuffer::Pop( char ** Data, int MaxLen ) { int BytesWritten = 0; // Read and clear bytes BytesWritten = Peek( Data, 0, MaxLen ); Clear( BytesWritten ); return BytesWritten; } //--------------------------------------------------------------------------- // Read first-in bytes from buffer // Return "stitched" buffer data copied to pointer which if created if NULL int CShiftBuffer::PopCopy( char ** Data, int MaxLen ) { int BytesWritten = 0; // Copy and clear bytes BytesWritten = PeekCopy( Data, 0, MaxLen ); Clear( BytesWritten ); // Return temp buffer return BytesWritten; } //--------------------------------------------------------------------------- // Read File descriptor directly into buffer int CShiftBuffer::ReadFromFD( int Handle, int MaxRead ) { int BytesRead = 0; int TotalRead = 0; int DataRemain = 0; // Check if buffer created if (!BufSize) { return 0; } // Read file descriptor into buffer DataRemain = ((MaxRead < 0) || (MaxRead > BufSize-BufLen))? BufSize-BufLen : MaxRead; while (DataRemain) { // Read from file descriptor BytesRead = read( Handle, &Buffer[BufLen], DataRemain ); if (BytesRead <= 0) { break; } // Update Buffer Pointers DataRemain -= BytesRead; TotalRead += BytesRead; BufLen += BytesRead; } return TotalRead; } //--------------------------------------------------------------------------- // 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 = 0; int ReadPos = 0; // Check if buffer created if (!BufSize) { return 0; } // Read Data into buffer ReadPos = 0; DataRemain = ((MaxLen == -1) || (MaxLen > BufLen))? 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; } //---------------------------------------------------------------------------