commit e2b653e51f535271efb3dbab64fbc8ee495d5ebb Author: Sean Date: Sun Aug 10 11:35:20 2025 -0400 Initial Comit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87399cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +common/build/** +listener/build/** diff --git a/common/.vscode/c_cpp_properties.json b/common/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..d336180 --- /dev/null +++ b/common/.vscode/c_cpp_properties.json @@ -0,0 +1,26 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/home/pi/Boneyard" + ], + "defines": [], + "cStandard": "c17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-gcc-arm64" + }, + { + "name": "ARM64", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "cStandard": "c17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-gcc-arm64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/common/.vscode/settings.json b/common/.vscode/settings.json new file mode 100644 index 0000000..0e0dcd2 --- /dev/null +++ b/common/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..b920016 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.10.0) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/home/pi/Boneyard") +project(common VERSION 0.1.0 LANGUAGES C CXX) + +add_library(common string.cpp fileio.cpp intel.cpp mmap.cpp) + diff --git a/common/array.hpp b/common/array.hpp new file mode 100755 index 0000000..e0a913c --- /dev/null +++ b/common/array.hpp @@ -0,0 +1,129 @@ +#ifndef _COMMON_ARRAY_HPP_ +#define _COMMON_ARRAY_HPP_ +#ifndef _COMMON_WINDOWS_HPP_ +#include +#endif +#ifndef _COMMON_EXCEPTION_HPP_ +#include +#endif + +template +class Array +{ +public: + Array(void); + Array(const Array &someArray); + virtual ~Array(); + T &operator[](DWORD index); + T &elementAt(DWORD index); + Array &operator=(const Array &someArray); + bool operator==(const Array &someArray)const; + DWORD size(void)const; + void size(DWORD size); + DWORD sizeBytes(void)const; +private: + void destroy(void); + void create(DWORD elements); + + T *mpArray; + DWORD mElements; +}; + +template +inline +Array::Array(void) +: mpArray(0), mElements(0) +{ +} + +template +inline +Array::Array(const Array &someArray) +: mpArray(0), mElements(0) +{ + *this=someArray; +} + +template +inline +Array::~Array() +{ + destroy(); +} + +template +inline +T &Array::operator[](DWORD index) +{ + if(index>mElements)throw ArrayIndexOutOfBoundsException(); + return mpArray[index]; +} + +template +inline +Array &Array::operator=(const Array &someArray) +{ + destroy(); + if(!someArray.size())return *this; + size(someArray.size()); + for(unsigned index=0;index&)someArray)[index]; + return *this; +} + +template +inline +bool Array::operator==(const Array &someArray)const +{ + if(!someArray.size()||(size()!=someArray.size()))return FALSE; + for(int index=0;index<(int)size();index++)if(!(((Array&)*this).operator[](index)==((Array&)someArray)[index]))return FALSE; + return TRUE; +} + +template +inline +DWORD Array::sizeBytes(void)const +{ + return mElements*sizeof(T); +} + +template +DWORD Array::size(void)const +{ + return mElements; +} + +template +void Array::size(DWORD size) +{ + create(size); +} + +template +inline +void Array::destroy(void) +{ + if(!mpArray)return; + delete[] mpArray; + mpArray=0; + mElements=0; +} + +template +inline +void Array::create(DWORD elements) +{ + destroy(); + if(!elements)return; + mpArray=new T[elements]; + if(0==mpArray)throw(NullError()); + mElements=elements; +} + +template +inline +T &Array::elementAt(DWORD index) +{ + if(index>mElements)throw ArrayIndexOutOfBoundsException(); + return mpArray[index]; +} +#endif diff --git a/common/block.hpp b/common/block.hpp new file mode 100755 index 0000000..9502dea --- /dev/null +++ b/common/block.hpp @@ -0,0 +1,173 @@ +#ifndef _COMMON_BLOCK_HPP_ +#define _COMMON_BLOCK_HPP_ +#ifndef _COMMON_EXCEPTION_HPP_ +#include +#endif +#ifndef _COMMON_WINDOWS_HPP_ +#include +#endif +#ifndef _COMMON_ARRAY_HPP_ +#include +#endif +#ifndef _MSC_VER +#ifdef _EXPAND_BLOCK_TEMPLATES_ +#pragma option -Jgd +#endif +#endif + +template +class Block; + +template +class Container +{ +friend class Block; +public: + Container *next(); + void next(Container *nextItem); + Container *prev(); + void prev(Container *prevItem); +private: + Container *mNext; + Container *mPrev; + T *mItem; + Container(void); + virtual ~Container(); +}; + +template +class Block +{ +public: + class BlockBoundary{}; + typedef LONG Index; + Block(void); + Block(const Block &someBlock); + virtual ~Block(void); + LONG size(void)const; + void insert(const T& item); + void insert(const T *item); + bool insertAfter(Index itemIndex,const T *item); + void insert(Block &newBlock); + void remove(void); + void remove(const T *item); + void remove(Block &removeBlock); + void remove(Index itemIndex); + void toArray(Array &array); + Block &operator=(const Block &someBlock); + WORD operator==(const Block &someBlock)const; + T &operator[](LONG itemIndex); + Block &operator+=(const Block &someBlock); +private: + T &find(LONG itemIndex); + LONG mSize; + LONG mLastIndexReferenced; + Container *mLastObjectReferenced; + Container *mLastObjectInserted; + Container *mContainer; +}; + +template +inline +Block::Block(void) +: mContainer(0), mSize(0), mLastIndexReferenced(-1), + mLastObjectReferenced(0), mLastObjectInserted(0) +{ +} + +template +inline +Block::Block(const Block &someBlock) +: mContainer(0), mSize(0), mLastIndexReferenced(-1), + mLastObjectReferenced(0), mLastObjectInserted(0) +{ + *this=someBlock; +} + +template +inline +Block::~Block() +{ + remove(); +} + +template +inline +LONG Block::size(void)const +{ + return mSize; +} + +template +inline +T & Block::operator [](LONG itemIndex) +{ + if(itemIndex>=mSize)throw(BoundaryError()); + if(!mContainer)return *((T*)0); + else if(itemIndex==mLastIndexReferenced&&-1!=mLastIndexReferenced&&mLastObjectReferenced)return *mLastObjectReferenced->mItem; + else if(itemIndex==mLastIndexReferenced+1&&-1!=mLastIndexReferenced) + { + mLastIndexReferenced++; + mLastObjectReferenced=mLastObjectReferenced->next(); + return *mLastObjectReferenced->mItem; + } + return find(itemIndex); +} + +template +inline +void Block::toArray(Array &array) +{ + array.size(size()); + for(int index=0;index +inline +Container::Container() +: mNext(0), mPrev(0), mItem(0) +{ +} + +template +inline +Container::~Container() +{ + if(mItem)delete mItem; +} + +template +inline +Container *Container::next(void) +{ + return mNext; +} + +template +inline +void Container::next(Container *nextItem) +{ + mNext=nextItem; +} + +template +inline +Container *Container::prev(void) +{ + return mPrev; +} + +template +inline +void Container::prev(Container *prevItem) +{ + mPrev=prevItem; +} +#if defined(_MSC_VER) +#include +#endif +#endif + diff --git a/common/block.tpp b/common/block.tpp new file mode 100755 index 0000000..8c18a2d --- /dev/null +++ b/common/block.tpp @@ -0,0 +1,185 @@ +#ifndef _COMMON_BLOCK_TPP_ +#define _COMMON_BLOCK_TPP_ + +template +void Block::remove(void) +{ + if(!mContainer)return; + Container *Cursor=mContainer; + Container *Thumb; + while(Cursor) + { + Thumb=Cursor; + Cursor=Cursor->next(); + ::delete Thumb; + } + mContainer=0; + mLastIndexReferenced=-1L; + mLastObjectReferenced=0; + mLastObjectInserted=0; + mSize=0; +} + +template +T &Block::find(LONG itemIndex) +{ + Container *lpCursor=mContainer; + Index i=0; + for(i=0;inext(); + if(i==itemIndex) + { + mLastIndexReferenced=i; + mLastObjectReferenced=lpCursor; + return *lpCursor->mItem; + } + return *((T*)0); +} + +template +Block &Block::operator+=(const Block &someBlock) +{ + size_t blockSize(someBlock.size()); + + if(!blockSize)return *this; + for(int itemIndex=0;itemIndex&)someBlock)[itemIndex]); + return *this; +} + +template +bool Block::insertAfter(Index itemIndex,const T *item) +{ + if(itemIndex>=mSize)return false; + mLastObjectInserted->next(::new Container); + mLastObjectInserted->next()->prev(mLastObjectInserted); + mLastObjectInserted=mLastObjectInserted->next(); + mLastObjectInserted->mItem=::new T(); + mSize++; + for(int index=mSize-1;index>itemIndex+1;index--) + { + operator[](index)=operator[](index-1); + } + operator[](itemIndex+1)=*item; + return true; +} + +template +void Block::insert(Block &newBlock) +{ + LONG size(newBlock.size()); + for(Index i=0;i +void Block::insert(const T& item) +{ + insert(&item); +} + +template +void Block::insert(const T *item) +{ + if(!mContainer) + { + mContainer=::new Container; + mContainer->mItem=::new T(*item); + mLastObjectInserted=mContainer; + mSize++; + } + else + { + mLastObjectInserted->next(::new Container); + mLastObjectInserted->next()->prev(mLastObjectInserted); + mLastObjectInserted=mLastObjectInserted->next(); + mLastObjectInserted->mItem=::new T(*item); + mSize++; + } +} + +template +void Block::remove(Block &removeBlock) +{ + LONG size(removeBlock.size()); + + if(!size)return; + for(long itemIndex=size-1;itemIndex>=0;itemIndex--)remove(&removeBlock[itemIndex]); +} + +template +void Block::remove(const T *item) +{ + Container *lpThumb=mContainer; + + if(!lpThumb)return; + if(*item==*(mLastObjectInserted->mItem))lpThumb=mLastObjectInserted; + else while(lpThumb){if(*item==*(lpThumb->mItem))break;lpThumb=lpThumb->next();} + if(!lpThumb)return; + if(lpThumb==mContainer) + { + if(lpThumb->next()){mContainer=lpThumb->next();mContainer->prev(0);} + else {mContainer=0;mLastObjectInserted=0;} + } + else + { + if(lpThumb->next()){lpThumb->prev()->next(lpThumb->next());lpThumb->next()->prev(lpThumb->prev());} + else {lpThumb->prev()->next(0);mLastObjectInserted=lpThumb->prev();} + } + ::delete lpThumb; + mSize--; + mLastIndexReferenced=-1; + mLastObjectReferenced=0; +} + +template +void Block::remove(LONG itemIndex) +{ + Container *lpThumb=mContainer; + + if(!lpThumb||itemIndex>=mSize)return; + if(itemIndex==mSize-1)lpThumb=mLastObjectInserted; + else + { + for(Index i=0;inext(); + } + if(!lpThumb)return; + } + if(lpThumb==mContainer) + { + if(lpThumb->next()){mContainer=lpThumb->next();mContainer->prev(0);} + else {mContainer=0;mLastObjectInserted=0;} + } + else + { + if(lpThumb->next()){lpThumb->prev()->next(lpThumb->next());lpThumb->next()->prev(lpThumb->prev());} + else {lpThumb->prev()->next(0);mLastObjectInserted=lpThumb->prev();} + } + ::delete lpThumb; + mSize--; + mLastIndexReferenced=-1; + mLastObjectReferenced=0; +} + +template +Block &Block::operator=(const Block &someBlock) +{ + LONG itemCount(someBlock.size()); + + remove(); + if(!itemCount)return *this; + for(LONG itemIndex=0;itemIndex&)someBlock)[itemIndex])); + return *this; +} + +template +WORD Block::operator==(const Block &someBlock)const +{ + LONG itemCount(size()); + + if(itemCount!=someBlock.size())return FALSE; + for(LONG itemIndex=0;itemIndex&)*this).operator[](itemIndex)==((Block&)someBlock)[itemIndex]))return FALSE; + return TRUE; +} +#endif diff --git a/common/except.hpp b/common/except.hpp new file mode 100755 index 0000000..d92ec11 --- /dev/null +++ b/common/except.hpp @@ -0,0 +1,50 @@ +#ifndef _COMMON_EXCEPTION_HPP_ +#define _COMMON_EXCEPTION_HPP_ +#ifndef _COMMON_STRING_HPP_ +#include +#endif + +class Exception +{ +public: + Exception(){mReason="";} + Exception(const String &reason){mReason=reason;} + virtual ~Exception(){;} + virtual String toString(){return mReason;} + const String &getReason(void)const{return mReason;}; +private: + String mReason; +}; + +class BoundaryError : public Exception +{ +public : + String toString(){return "BoundaryError";} +}; + +class NullError : public Exception +{ +public : + String toString(){return "NullError";} +}; + +class ArrayIndexOutOfBoundsException : public Exception +{ +public : + String toString(){return "ArrayIndexOutOfBounds";} +}; + +class LibraryNotFoundException : public Exception +{ +public: + LibraryNotFoundException(const String &reason="LibraryNotFoundException"):Exception(reason){;} + String toString(){return getReason();} +}; + +class InvalidStateException : public Exception +{ +public: + InvalidStateException(const String &reason="InvalidStateException"):Exception(reason){;} + String toString(){return getReason();} +}; +#endif diff --git a/common/fileio.cpp b/common/fileio.cpp new file mode 100755 index 0000000..ba2c5a5 --- /dev/null +++ b/common/fileio.cpp @@ -0,0 +1,239 @@ +#include +#include + +FileIO::FileIO(void) +: mlpFilePointer(0), mByteOrder(LittleEndian) +{ +} + +FileIO::FileIO(String pathFileName,ByteOrder byteOrder,Mode openMode,CreationFlags creationFlags) +: mlpFilePointer(0) , mByteOrder(byteOrder) +{ + open(pathFileName,byteOrder,openMode,creationFlags); +} + +FileIO::~FileIO() +{ + close(); +} + +bool FileIO::close(void) +{ + if(!mlpFilePointer)return false; + ::fclose(mlpFilePointer); + mlpFilePointer=0; + return true; +} + +bool FileIO::open(String pathFileName,ByteOrder byteOrder,Mode openMode,CreationFlags creationFlags) +{ + close(); + if(pathFileName.isNull())return false; + mByteOrder=byteOrder; + if(ReadOnly==openMode) + { + mlpFilePointer=::fopen(pathFileName,"rb"); + } + else + { + if(CreateAlways==creationFlags)mlpFilePointer=::fopen(pathFileName,"w+b"); + else if(Create==creationFlags)mlpFilePointer=::fopen(pathFileName,"a+b"); + else mlpFilePointer=::fopen(pathFileName,"r+b"); + } + if(!mlpFilePointer)return false; + setBufferLength(BufferLength); + return true; +} + +bool FileIO::setBufferLength(DWORD length) +{ + if(!isOkay())return false; + return !::setvbuf(mlpFilePointer, 0, _IOFBF, length); +} + +bool FileIO::peek(BYTE &value) +{ + if(!isOkay())return false; + read(value); + seek(tell()-1,SeekCurrent); + return true; +} + +bool FileIO::read(WORD &value) +{ + BYTE byteValue; + + if(!isOkay())return false; + if(!read(byteValue))return false; + value=byteValue; + if(!read(byteValue))return false; + value|=((WORD)byteValue)<<8; + if(BigEndian==mByteOrder)value=Intel::intelData(value); + return true; +} + +bool FileIO::read(DWORD &value) +{ + WORD wordValue; + + if(!isOkay())return false; + if(!read(wordValue))return false; + value=wordValue; + if(!read(wordValue))return false; + value|=((DWORD)wordValue)<<16; + if(BigEndian==mByteOrder)value=Intel::intelData(value); + return true; +} + +size_t FileIO::read(char *lpBuffer,DWORD lengthData) +{ + BYTE byteValue(0); + + if(!isOkay()||!lpBuffer)return false; + size_t result = ::fread(lpBuffer,1,lengthData,mlpFilePointer); + return result; +} + +size_t FileIO::read(char *lpBuffer,DWORD lengthData,int stopChar) +{ + BYTE tempChar; + int bytesRead; + + if(!isOkay()||!lpBuffer||!lengthData)return false; + for(bytesRead=0;bytesRead=adaptiveBlockLength-1) + { + *ptrLine=0; + String tmpString(lineString); + int nextIndex(ptrLine-(BYTE*)(char*)lineString); + lineString.reserve(adaptiveBlockLength+BlockIncrement,false); + ::memcpy((char*)lineString,(char*)tmpString,adaptiveBlockLength); + adaptiveBlockLength+=BlockIncrement; + ptrLine=(BYTE*)(char*)lineString+nextIndex; + } + if(CarriageReturn==charByte) + { + if(!read(charByte))break; + if(LineFeed==charByte) + { + *ptrLine=0; + break; + } + } + else if(LineFeed==charByte) + { + *ptrLine++=0; + break; + } + else if(NullChar==charByte) + { + *ptrLine++=0; + break; + } + else + { + *ptrLine++=charByte; + bytesRead++; + } + } + return actualBytesRead>0; +} + +bool FileIO::write(WORD value) +{ + BYTE byteValue; + + if(!isOkay())return false; + if(BigEndian==mByteOrder)value=Intel::intelData(value); + byteValue=(BYTE)(value&0x00FF); + if(!write(byteValue))return false; + byteValue=(BYTE)(value>>8); + if(!write(byteValue))return false; + return true; +} + +bool FileIO::write(DWORD value) +{ + WORD wordValue; + + if(!isOkay())return false; + if(BigEndian==mByteOrder) + { + WORD hiWord(HIWORD(value)); + WORD loWord(LOWORD(value)); + + value=((DWORD)Intel::intelData(loWord))<<16; + value|=Intel::intelData(hiWord); + if(!write((char*)&value,sizeof(value)))return false; + return true; + } + wordValue=(WORD)(value&0xFFFF); + if(!write(wordValue))return false; + wordValue=(WORD)(value>>16); + if(!write(wordValue))return false; + return true; +} + +bool FileIO::writeLine(const String &strLine) +{ + if(!isOkay()||strLine.isNull())return false; + if(!write((char*)(String&)strLine,strLine.length()))return false; + return write((char*)"\r\n",2); +} + +bool FileIO::rewind(void) +{ + if(!isOkay())return false; + return (!::fseek(mlpFilePointer,0,SEEK_SET)); +} + +FileIO &FileIO::operator++(void) +{ + seek(1L,SeekCurrent); + return *this; +} + +FileIO &FileIO::operator--(void) +{ + seek(-1L,SeekCurrent); + return *this; +} + +bool FileIO::seek(LONG seekOffset,SeekFrom seekFrom) +{ + if(!isOkay())return false; + return 0==::fseek(mlpFilePointer,seekOffset,seekFrom)?true:false; +} + diff --git a/common/fileio.hpp b/common/fileio.hpp new file mode 100755 index 0000000..5a619bb --- /dev/null +++ b/common/fileio.hpp @@ -0,0 +1,128 @@ +#ifndef _COMMON_FILEIO_HPP_ +#define _COMMON_FILEIO_HPP_ +#ifndef _COMMON_WINDOWS_HPP_ +#include +#endif +#ifndef _COMMON_STRING_HPP_ +#include +#endif +#ifndef _COMMON_STDIO_HPP_ +#include +#endif +#ifndef _COMMON_INTEL_HPP_ +#include +#endif + +#pragma warning( disable : 26812) + +// Optimized for fast reading of files. + +class FileIO +{ +public: + enum Mode{ReadOnly,ReadWrite}; + enum ByteOrder{BigEndian,LittleEndian}; + enum SeekFrom{SeekCurrent=SEEK_CUR,SeekEnd=SEEK_END,SeekBeginning=SEEK_SET}; + enum CreationFlags{Create,CreateAlways,None}; + FileIO(void); + FileIO(String pathFileName,ByteOrder byteOrder=LittleEndian,Mode openMode=ReadOnly,CreationFlags creationFlags=None); + virtual ~FileIO(); + bool open(String pathFileName,ByteOrder byteOrder=LittleEndian,Mode openMode=ReadOnly,CreationFlags creationFlags=None); + bool close(void); + bool rewind(void); + bool peek(BYTE &value); + bool read(BYTE &value); + bool read(WORD &value); + bool read(DWORD &value); + size_t read(char *lpBuffer,DWORD lengthData); + size_t read(BYTE *lpBuffer,DWORD lengthData); + size_t read(char *lpBuffer,DWORD lengthData,int stopChar); + bool eof(void)const; + bool setBufferLength(DWORD length); + bool write(BYTE value); + bool write(WORD value); + bool write(DWORD value); + bool write(char *lpBuffer,DWORD lengthData); + FileIO &operator++(void); + FileIO &operator--(void); + bool seek(LONG seekOffset,SeekFrom seekFrom); + BOOL readLine(String &lineString); + bool writeLine(const String &strLine); + bool isOkay(void)const; + DWORD tell(void)const; + ByteOrder getByteOrder(void)const; + void setByteOrder(ByteOrder byteOrder); + DWORD size(void); +private: + enum {CarriageReturn=0x0D,LineFeed=0x0A,NullChar=0x00}; + enum {BufferLength=65536}; // This is for the file stream + enum {InitialBlockLength=65536,BlockIncrement=65536}; // This is for readLine + FILE *mlpFilePointer; + ByteOrder mByteOrder; + DWORD adaptiveBlockLength=InitialBlockLength; // This is for readLine +}; + +inline +bool FileIO::isOkay(void)const +{ + return (mlpFilePointer?true:false); +} + +inline +DWORD FileIO::tell(void)const +{ + if(!isOkay())return false; + return ::ftell(mlpFilePointer); +} + +inline +bool FileIO::eof(void)const +{ + if(!isOkay())return true; + return ::feof(mlpFilePointer); +} + +inline +bool FileIO::read(BYTE &value) +{ + if(!isOkay())return false; + return (sizeof(value)==::fread(&value,1,1,mlpFilePointer)?true:false); +} + +inline +size_t FileIO::read(BYTE *lpBuffer,DWORD lengthData) +{ + return read((char*)lpBuffer,lengthData); +} + +inline +bool FileIO::write(BYTE value) +{ + if(!isOkay())return false; + if(1!=::fwrite(&value,1,1,mlpFilePointer))return false; + return true; +} + +inline +FileIO::ByteOrder FileIO::getByteOrder(void)const +{ + return mByteOrder; +} + +inline +void FileIO::setByteOrder(ByteOrder byteOrder) +{ + mByteOrder=byteOrder; +} + +inline +DWORD FileIO::size(void) +{ + DWORD currentPosition = tell(); + seek(0,FileIO::SeekFrom::SeekEnd); + DWORD lastPosition = tell(); + seek(currentPosition, FileIO::SeekFrom::SeekBeginning); + return lastPosition-currentPosition; +} + +#endif diff --git a/common/intel.cpp b/common/intel.cpp new file mode 100755 index 0000000..d3a14d8 --- /dev/null +++ b/common/intel.cpp @@ -0,0 +1,21 @@ +#include + +WORD Intel::intelData(WORD someData) +{ + WORD tempData(someData); + + someData>>=8; + someData+=tempData<<8; + return someData; +} + +DWORD Intel::intelData(DWORD someData) +{ + WORD tempDataHi(HIWORD(someData)); + WORD tempDataLo(LOWORD(someData)); + + someData=tempDataLo; + someData<<=16; + someData|=tempDataHi; + return someData; +} diff --git a/common/intel.hpp b/common/intel.hpp new file mode 100755 index 0000000..6f683c7 --- /dev/null +++ b/common/intel.hpp @@ -0,0 +1,26 @@ +#ifndef _COMMON_INTEL_HPP_ +#define _COMMON_INTEL_HPP_ +#ifndef _COMMON_WINDOWS_HPP_ +#include +#endif + +class Intel +{ +public: + Intel(void); + virtual ~Intel(); + static WORD intelData(WORD someData); + static DWORD intelData(DWORD someData); +private: +}; + +inline +Intel::Intel(void) +{ +} + +inline +Intel::~Intel() +{ +} +#endif diff --git a/common/mmap.cpp b/common/mmap.cpp new file mode 100644 index 0000000..8c00f6d --- /dev/null +++ b/common/mmap.cpp @@ -0,0 +1,74 @@ +#include +#include + +bool MemoryMappedFile::open(const String& pathFileName,CreationFlags creationFlags) +{ + if(isOkay()) + { + close(); + } + mFD=::open(pathFileName,getFileAccessFromFlags(creationFlags)); + mCreationFlags= creationFlags; + if(!isOkay())return false; + struct stat sb; + if(-1==::fstat(mFD,&sb)) + { + close(); + return false; + } + mFileLength = sb.st_size; + if(!createMemoryMap()) + { + close(); + return false; + } + return true; +} + +bool MemoryMappedFile::createMemoryMap(void) +{ + void *pAddress = ::mmap(NULL,mFileLength,getMemoryMapAccessFromFlags(mCreationFlags),mCreationFlags == CreationFlags::ReadOnly?MAP_PRIVATE:MAP_SHARED,mFD,0); + if(MAP_FAILED == pAddress) + { + return false; + } + mlpMappedDataBase = (char *)pAddress; + mIndex=0; + return true; +} + +void MemoryMappedFile::close() +{ + if(!isOkay())return; + ::munmap((void*)mlpMappedDataBase, mFileLength); + ::close(mFD); + mFD=-1; + mFileLength=-1; +} + +int MemoryMappedFile::getFileAccessFromFlags(CreationFlags creationFlags)const +{ + switch(creationFlags) + { + case ReadOnly : + return O_RDONLY | S_IRUSR ; + case ReadWrite : + return O_RDWR | O_CREAT, S_IRUSR | S_IWUSR; + default : + throw new Exception("Undefined creation flag"); + } +} + +int MemoryMappedFile::getMemoryMapAccessFromFlags(CreationFlags creationFlags)const +{ + switch(creationFlags) + { + case ReadOnly : + return PROT_READ; + case ReadWrite : + return PROT_READ | PROT_WRITE; + default : + throw new Exception("Undefined creation flag"); + } +} + diff --git a/common/mmap.hpp b/common/mmap.hpp new file mode 100644 index 0000000..b0bc6ae --- /dev/null +++ b/common/mmap.hpp @@ -0,0 +1,96 @@ +#ifndef _COMMON_MMAP_HPP_ +#define _COMMON_MMAP_HPP_ +#include +#include +#include +#include +#include +#include + +class MemoryMappedFile +{ + public: + enum CreationFlags{ReadOnly,ReadWrite}; + MemoryMappedFile(const String& pathFileName,CreationFlags creationFlags); + virtual ~MemoryMappedFile(); + bool open(const String& pathFileName,CreationFlags creationFlags); + bool readLine(String &strLine); + char readChar(void); + bool eof(void); + char peekChar(void); + void close(void); + bool isOkay(void); + off_t tell(void); + private: + enum {CarriageReturn=0x0D,LineFeed=0x0A,NullChar=0x00}; + enum {BlockSize=65536}; + bool createMemoryMap(void); + int getFileAccessFromFlags(CreationFlags creationFlags)const; + int getMemoryMapAccessFromFlags(CreationFlags creationFlags)const; + + int mFD = -1; + unsigned long mIndex; + off_t mFileLength = -1; + char *mlpMappedDataBase = 0; + CreationFlags mCreationFlags; +}; + +/// @brief +/// @param pathFileName +/// @param access +inline +MemoryMappedFile::MemoryMappedFile(const String& pathFileName,CreationFlags creationFlags) +{ + open(pathFileName, creationFlags); +} + +inline +MemoryMappedFile::~MemoryMappedFile() +{ +} + +inline +char MemoryMappedFile::readChar() +{ + return mlpMappedDataBase[mIndex++]; +} + +inline +bool MemoryMappedFile::eof() +{ + return mIndex +#endif + +class PointerDisposition +{ +public: + enum Disposition{Assume,Delete}; +}; + +template +class SmartPointer +{ +public: + SmartPointer(void); + SmartPointer(T FAR *lpSmartPointer,PointerDisposition::Disposition disposition=PointerDisposition::Assume); + SmartPointer(const SmartPointer &someSmartPointer); + virtual ~SmartPointer(); + T FAR *operator->(void); + operator T FAR *(void); + operator LPARAM(void); + SmartPointer &operator=(const SmartPointer &someSmartPointer); + SmartPointer &operator=(T FAR *lpSmartPointer); + WORD operator==(const SmartPointer &someSmartPointer)const; + void disposition(PointerDisposition::Disposition disposition); + PointerDisposition::Disposition disposition(void)const; + void destroy(void); + bool isOkay(void)const; + bool isNull(void)const; +protected: + T **ppt(void); +private: + T FAR *mlpSmartPointer; + PointerDisposition::Disposition mDisposition; +}; + +template +inline +SmartPointer::SmartPointer(void) +: mlpSmartPointer(0), mDisposition(PointerDisposition::Assume) +{ +} + +template +inline +SmartPointer::SmartPointer(T FAR *lpSmartPointer,PointerDisposition::Disposition disposition) +: mlpSmartPointer(lpSmartPointer), mDisposition(disposition) +{ +} + +template +inline +SmartPointer::SmartPointer(const SmartPointer &someSmartPointer) +: mlpSmartPointer(0), mDisposition(PointerDisposition::Assume) +{ + *this=someSmartPointer; +} + +template +inline +SmartPointer::~SmartPointer() +{ + destroy(); +} + +template +inline +SmartPointer::operator T FAR *(void) +{ + return mlpSmartPointer; +} + +template +inline +T **SmartPointer::ppt(void) +{ + return &mlpSmartPointer; +} + +template +inline +SmartPointer::operator LPARAM(void) +{ + return (LPARAM)mlpSmartPointer; +} + +template +inline +T FAR *SmartPointer::operator->(void) +{ + return mlpSmartPointer; +} + +template +inline +SmartPointer &SmartPointer::operator=(const SmartPointer &someSmartPointer) +{ + destroy(); + mlpSmartPointer=someSmartPointer.mlpSmartPointer; + mDisposition=PointerDisposition::Assume; + return *this; +} + +template +inline +SmartPointer &SmartPointer::operator=(T FAR *lpSmartPointer) +{ + destroy(); + mlpSmartPointer=lpSmartPointer; + mDisposition=PointerDisposition::Assume; + return *this; +} + +template +inline +WORD SmartPointer::operator==(const SmartPointer &someSmartPointer)const +{ + return *mlpSmartPointer==*someSmartPointer.mlpSmartPointer; +} + +template +inline +void SmartPointer::destroy(void) +{ + if(!mlpSmartPointer)return; + if(PointerDisposition::Assume==mDisposition)mlpSmartPointer=0; + else {::delete mlpSmartPointer;mlpSmartPointer=0;} +} + +template +inline +void SmartPointer::disposition(PointerDisposition::Disposition disposition) +{ + mDisposition=disposition; +} + +template +inline +PointerDisposition::Disposition SmartPointer::disposition(void)const +{ + return mDisposition; +} + +template +inline +bool SmartPointer::isNull(void)const +{ + return (mlpSmartPointer?FALSE:TRUE); +} + +template +inline +bool SmartPointer::isOkay(void)const +{ + return !isNull(); +} +#endif diff --git a/common/profiler.hpp b/common/profiler.hpp new file mode 100644 index 0000000..d1eb8fe --- /dev/null +++ b/common/profiler.hpp @@ -0,0 +1,46 @@ +#ifndef _COMMON_PROFILER_HPP_ +#define _COMMON_PROFILER_HPP_ +#include + +class Profiler +{ + public: + Profiler(); + virtual ~Profiler(); + void start(void); + long end(void); + long elapsed(void); + private: + std::chrono::_V2::system_clock::time_point start_time = std::chrono::high_resolution_clock::now(); +}; + +inline +Profiler::Profiler() +{ +} + +inline +Profiler::~Profiler() +{ +} + +inline +void Profiler::start(void) +{ + start_time = std::chrono::high_resolution_clock::now(); +} + +inline +long Profiler::end(void) +{ + std::chrono::_V2::system_clock::time_point end_time = std::chrono::high_resolution_clock::now(); + long elapsed_time_ms = std::chrono::duration_cast(end_time - start_time).count(); + return elapsed_time_ms; +} + +inline +long Profiler::elapsed(void) +{ + return end(); +} +#endif \ No newline at end of file diff --git a/common/stdio.hpp b/common/stdio.hpp new file mode 100755 index 0000000..b15a0ac --- /dev/null +++ b/common/stdio.hpp @@ -0,0 +1,4 @@ +#ifndef _COMMON_STDIO_HPP_ +#define _COMMON_STDIO_HPP_ +#include +#endif \ No newline at end of file diff --git a/common/stdlib.hpp b/common/stdlib.hpp new file mode 100755 index 0000000..1152e28 --- /dev/null +++ b/common/stdlib.hpp @@ -0,0 +1,4 @@ +#ifndef _COMMON_STDLIB_HPP_ +#define _COMMON_STDLIB_HPP_ +#include +#endif diff --git a/common/string.cpp b/common/string.cpp new file mode 100755 index 0000000..1e3c53b --- /dev/null +++ b/common/string.cpp @@ -0,0 +1,705 @@ +#include +#include +#include +#include +#include + +String::String(const char *npStr) +: mnpStr(0), mLengthBytes(0) +{ + DWORD stringLength; + + if(!npStr)return; + try{stringLength=::strlen(npStr);} + catch(...){{stringLength=0;}} + if(!stringLength)return; + stringLength++; + reserve(stringLength,FALSE); + ::strcpy(mnpStr,npStr); +} + +String::String(const wchar_t* npWideString, int length) + : mnpStr(0), mLengthBytes(0) +{ + if (!npWideString || 0 == length)return; + reserve(length); + for (wchar_t index = 0;index < length;index++) + { + char character = (char)((npWideString[index]<<8)>>8); + operator[](index) = character; + } +} + +String::String(const String &newString) +: mnpStr(0), mLengthBytes(0) +{ + DWORD stringLength; + + if(!newString.mnpStr)return; + if(!(stringLength=newString.length()))return; + stringLength++; + reserve(stringLength,FALSE); + ::strcpy(mnpStr,newString.mnpStr); +} + +String &String::operator=(const String &someString) +{ + int stringLength; + + if(this==&someString)return *this; + if(someString.isNull()){removeData();return *this;} + if(!(stringLength=::strlen(someString.mnpStr)))return *this; + stringLength++; + if(lengthBytes()>=stringLength)::strcpy(mnpStr,someString.mnpStr); + else {reserve(stringLength,FALSE);::strcpy(mnpStr,someString.mnpStr);} + return *this; +} + +int String::operator=(const char *someCharStar) +{ + int stringLength; + + if(!someCharStar)return 0; + if(!(stringLength=::strlen(someCharStar)))return 0; + stringLength++; + if(lengthBytes()>=stringLength)::strcpy(mnpStr,someCharStar); + else {reserve(stringLength,FALSE);::strcpy(mnpStr,someCharStar);} + return 1; +} + +void String::operator+=(char someChar) +{ + DWORD strLength(length()); + if(strLength+2>mLengthBytes) + { + String tmpString(someChar); + *this+=tmpString; + return; + } + *(mnpStr+strLength)=someChar; + *(mnpStr+strLength+1)=0; +} + +int String::operator+=(const String &someString) +{ + char *lpString; + DWORD currLength; + DWORD stringLength; + + if(!someString.mnpStr)return 0; + stringLength=someString.length(); + stringLength++; + if(!mnpStr) + { + reserve(stringLength,FALSE); + ::strcpy(mnpStr,someString.mnpStr); + return 1; + } + currLength=::strlen(mnpStr); + if(lengthBytes()-currLength>=stringLength) + { + ::strcat(mnpStr,someString.mnpStr); + return 1; + } + lpString=mnpStr; + mnpStr=::new char[currLength+stringLength+MaxString]; + mLengthBytes=currLength+stringLength+MaxString; + ::strcpy(mnpStr,lpString); + ::strcpy(mnpStr+currLength,someString.mnpStr); + ::delete[] lpString; + return 1; +} + +int String::operator+=(const char *someStr) +{ + char *lpString; + DWORD currLength; + DWORD stringLength; + + if(!someStr)return 0; + stringLength=::strlen(someStr); + stringLength++; + if(!mnpStr) + { + reserve(stringLength,FALSE); + ::strcpy(mnpStr,someStr); + return 1; + } + currLength=::strlen(mnpStr); + if(lengthBytes()-currLength>=stringLength) + { + ::strcat(mnpStr,someStr); + return 1; + } + lpString=mnpStr; + mnpStr=::new char[currLength+stringLength+MaxString]; + mLengthBytes=currLength+stringLength+MaxString; + ::strcpy(mnpStr,lpString); + ::strcpy(mnpStr+currLength,someStr); + ::delete[] lpString; + return 1; +} + +String String::operator+(const String &someString)const +{ + String tmpString(*this); + tmpString+=someString; + return tmpString; +} + +int String::token(const char *tokenString) +{ + if(!tokenString||!mnpStr)return 0; + if(::strtok(mnpStr,tokenString))return 1; + return 0; +} + +long String::strchr(char someChar)const +{ + long pos; + if(!mnpStr)return -1; + pos=(long)::strchr(mnpStr,someChar); + if(!pos)return -1; + return pos-(long)mnpStr; +} + +long String::strpos(const char *string)const +{ + long stringPosition; + if(!mnpStr)return -1; + stringPosition=(long)::strstr(mnpStr,string); + if(!stringPosition)return -1; + return stringPosition-(long)mnpStr; +} + +int String::strncmp(const char *string)const +{ + int srcLength; + int dstLength; + + if(!mnpStr)return -1; + srcLength=::strlen(string); + dstLength=::strlen(mnpStr); + return ::strncmp(mnpStr,string,srcLength=stringLength)return String(nullString); + if(beginToken) + { + if(0==(lpBegin=::strchr(mnpStr,beginToken)))return String(nullString); + if(++lpBegin-mnpStr>=stringLength)return String(nullString); + } + else lpBegin=mnpStr; + if(0==(lpEnd=::strchr(lpBegin,endToken)))return *this; + if(lpBegin==lpEnd)return String(nullString); + if(sizeof(nullString)<=(lpEnd-lpBegin)+1) + { + String nullString; + nullString.reserve((lpEnd-lpBegin)+1,FALSE); + ::memcpy(nullString,lpBegin,lpEnd-lpBegin); + *((char*)nullString+(lpEnd-lpBegin))=0; + return nullString; + } + ::memcpy(nullString,lpBegin,lpEnd-lpBegin); + *(nullString+(lpEnd-lpBegin))=0; + return String(nullString); +} + +Block String::split(char delimeter)const +{ + Block stringList = Block(); + String strDelimeter = String(delimeter); + String runningString = String(*this); + + int position = runningString.strpos(strDelimeter); + while (-1 != position) + { + stringList.insert(new String(runningString.substr(0, position - 1))); + runningString = runningString.substr(position + 1); + position = runningString.strpos(strDelimeter); + } + if (runningString.length())stringList.insert(new String(runningString)); + return stringList; +} + +WORD String::makeBlock(Block &receiveStrings,const String &tokenString)const +{ + String stringData(*this); + String workString; + LONG stringPos; + LONG lengthToken; + + receiveStrings.remove(); + if(!(lengthToken=tokenString.length()))return FALSE; + if(stringData.isNull())return FALSE; + while(TRUE) + { + if(-1==(stringPos=stringData.strpos(tokenString))) + { + if(!stringData.isNull())receiveStrings.insert(&stringData); + return receiveStrings.size(); + } + else if(stringData.length()!=stringPos+lengthToken) + { + if(stringPos) + { + workString=stringData.substr(0,stringPos-lengthToken); + receiveStrings.insert(&workString); + } + stringData=stringData.substr(stringPos+lengthToken,stringData.length()); + } + else stringData.removeTokens(tokenString); + } +} + +String String::extractDigits(void)const +{ + String tempString; + String nullString; + char *lpClampOne; + char *lpClampTwo; + + if(!mnpStr)return nullString; + tempString=mnpStr; + lpClampOne=(char*)tempString; + while(*lpClampOne&&!isdigit(*lpClampOne))lpClampOne++; + if(!*lpClampOne)return nullString; + lpClampTwo=lpClampOne; + while(*lpClampTwo&&isdigit(*lpClampTwo))lpClampTwo++; + *lpClampTwo=0; + return lpClampOne; +} + +String String::extractAlpha(void)const +{ + String tempString; + String nullString; + char *lpClampOne; + char *lpClampTwo; + + if(!mnpStr)return nullString; + tempString=mnpStr; + lpClampOne=(char*)tempString; + while(*lpClampOne&&!isalpha(*lpClampOne))lpClampOne++; + if(!*lpClampOne)return nullString; + lpClampTwo=lpClampOne; + while(*lpClampTwo&&isalpha(*lpClampTwo))lpClampTwo++; + *lpClampTwo=0; + return lpClampOne; +} + +int String::hex(void)const +{ + String workString(*this); + DWORD stringLength; + DWORD multiplier(0x01); + DWORD value(0L); + char *ptrString; + + if(workString.isNull())return FALSE; + if(workString.strstr(" "))workString.removeTokens(" "); + if(!(stringLength=workString.length()))return FALSE; + workString.upper(); + if(0!=(ptrString=(char*)workString.strstr("0X"))) + { + ptrString+=2; + stringLength=::strlen(ptrString); + ptrString+=(stringLength-1); + } + else if('H'==*((char*)workString+(stringLength-1))) + { + stringLength--; + ptrString=(char*)workString+(stringLength-1); + } + else ptrString=(char*)workString+(stringLength-1); + for(LONG stringIndex=stringLength-1;stringIndex>=0;stringIndex--) + { + switch(*(ptrString--)) + { + case '0' : break; + case '1' : {value+=multiplier;break;} + case '2' : {value+=multiplier*2;break;} + case '3' : {value+=multiplier*3;break;} + case '4' : {value+=multiplier*4;break;} + case '5' : {value+=multiplier*5;break;} + case '6' : {value+=multiplier*6;break;} + case '7' : {value+=multiplier*7;break;} + case '8' : {value+=multiplier*8;break;} + case '9' : {value+=multiplier*9;break;} + case 'A' : {value+=multiplier*10;break;} + case 'B' : {value+=multiplier*11;break;} + case 'C' : {value+=multiplier*12;break;} + case 'D' : {value+=multiplier*13;break;} + case 'E' : {value+=multiplier*14;break;} + case 'F' : {value+=multiplier*15;break;} + case '-' : {value*=-1;break;} + default : return value; + } + multiplier*=16; + } + return value; +} + +void String::spaceTerm(void) +{ + size_t strLen; + + if(isNull()||(0==(strLen=length())))return; + for(short index=0;index=0;index--) + { + char ch = mnpStr[index]; + if (Blank == ch || CarriageReturn==ch || LineFeed==ch)mnpStr[index] = 0; + else break; + } + return *this; +} + +String &String::trimLeft(void) +{ + size_t strLen; + + if(isNull()||(0==(strLen=length())))return *this; + short index=0; + for (index = 0;index < strLen;index++) + { + char ch = mnpStr[index]; + if (Blank != ch && CarriageReturn != ch && LineFeed != ch)break; + } + if(!index)return *this; + *this=substr(index); + return *this; +} + +void String::removeTokens(String someTokens) +{ + int length(this->length()); + int tokens(someTokens.length()); + String tempString; + + if(!length||!tokens)return; + for(int token=0;tokenlength()); + String tempString; + + if(!length)return; + int pos=0; + for(pos=0;posnewLength) + { + String tempString; + tempString.reserve(newLength+1); + ::memcpy(tempString,*this,newLength); + *this=tempString; + } + else while(length()endPosition)return resultString; + if(endPosition>stringLength)endPosition=stringLength; + resultString.reserve(endPosition-startPosition+2); + ::memcpy(resultString,mnpStr+startPosition,(endPosition-startPosition)+1); + return resultString; +} + +WORD String::insert(const String &insertString,WORD insertPosition) +{ + WORD insertLength(insertString.length()); + + if(!insertLength)return FALSE; + if(!mnpStr) + { + reserve(insertLength+insertPosition+1); + ::memset(mnpStr,Blank,insertLength+insertPosition); + ::memcpy(mnpStr+insertPosition,insertString,insertLength); + } + else + { + WORD currentLength(length()); + String tempString; + + if(insertLength+insertPosition>currentLength) + { + tempString.reserve(insertLength+insertPosition+currentLength+1); + ::memset(tempString,Blank,insertLength+insertPosition+currentLength); + } + else + { + tempString.reserve(currentLength+insertLength+1); + ::memset(tempString,Blank,currentLength+insertLength); + } + ::memcpy(tempString,mnpStr,currentLength); + if(!(insertPosition>currentLength))shiftRight(tempString,insertPosition,currentLength+insertLength-1,insertLength,currentLength); + ::memcpy(((char*)tempString)+insertPosition,insertString,insertLength); + *this=tempString; + } + return TRUE; +} + +WORD String::insert(char *lpInsertString,WORD insertPosition) +{ + WORD insertLength; + + if(!lpInsertString||!(insertLength=::strlen(lpInsertString)))return FALSE; + if(!mnpStr) + { + reserve(insertLength+insertPosition+1); + ::memset(mnpStr,Blank,insertLength+insertPosition); + ::memcpy(mnpStr+insertPosition,lpInsertString,insertLength); + } + else + { + WORD currentLength(length()); + String tempString; + + if(insertLength+insertPosition>currentLength) + { + tempString.reserve(insertLength+insertPosition+currentLength+1); + ::memset(tempString,Blank,insertLength+insertPosition+currentLength); + } + else + { + tempString.reserve(currentLength+insertLength+1); + ::memset(tempString,Blank,currentLength+insertLength); + } + ::memcpy(tempString,mnpStr,currentLength); + if(!(insertPosition>currentLength))shiftRight(tempString,insertPosition,currentLength+insertLength-1,insertLength,currentLength); + ::memcpy(((char*)tempString)+insertPosition,lpInsertString,insertLength); + *this=tempString; + } + return TRUE; +} + +void String::shiftRight(String &shiftString,WORD startPos,WORD endPos,WORD insertLength,WORD originalLength) +{ + WORD shiftLength(originalLength-startPos); + for(WORD shiftIndex=0;shiftIndex +#ifndef _COMMON_STDLIB_HPP_ +#include +#endif +#ifndef _COMMON_WINDOWS_HPP_ +#include +#endif + +#pragma warning( disable : 6387) + +template +class Block; +template +class Array; +class istream; +class ostream; +class String; + +istream &operator>>(istream &stream,String &someString); +ostream &operator<<(ostream &stream,const String &someString); + +String operator+(const char *str,const String &string); + +class String +{ +public: + enum{MaxString=256}; + String(void); + String(const char *npStr); + String(const wchar_t *npWideString,int length); + String(const String &newString); + String(int resourceStringID); + String(char characterItem); + virtual ~String(); + int operator!=(const String &someString)const; + int operator!=(const char *someCharStar)const; + int operator==(const String &someString)const; + int operator==(const char *someCharStar)const; + int operator<(const String &someString)const; + int operator>(const String &someString)const; + String &operator=(const String &someString); + int operator=(const char *someCharStar); + int operator+=(const String &someString); + int operator+=(const char *someStr); + void operator+=(char someChar); + char &operator[](DWORD itemIndex); + char charAt(DWORD itemIndex)const; + String &setAt(DWORD itemIndex,char ch); + friend istream &operator>>(istream &stream,String &someString); + friend ostream &operator<<(ostream &stream,const String &someString); + operator char *(void)const; + String operator+(const String &someString)const; + void reserve(DWORD nBytes,BOOL setZero=TRUE)__attribute__((always_inline)); + int token(const char *token); + int isNull(void)const; + void upper(void); + void lower(void); + int length(void)const; + void length(short newLength); + DWORD lengthBytes(void)const; + void removeTokens(String someTokens); + void replaceToken(BYTE tokenFind,BYTE tokenReplace); + int hex(void)const; + void expand(void); + void convert(double doubleValue,const char *formatString); + void convert(int integerValue,const char *formatString); + void convert(long longValue,const char *formatString); + long strstr(const char *string)const; + long strpos(const char *string)const; + long strchr(char someChar)const; + int strncmp(const char *string)const; + BOOL endsWidth(char ch)const; + String& trim(void); + String &trimRight(void); + String &trimLeft(void); + void spaceTerm(void); + String betweenString(char beginToken,char endToken)const; + Block split(char delimter)const; + String substr(WORD startPosition,WORD endPosition)const; + String substr(WORD startPosition)const; + String extractDigits(void)const; + String extractAlpha(void)const; + WORD makeBlock(Block &receiveStrings,const String &tokenString)const; + WORD insert(const String &insertString,WORD insertPosition=0); + WORD insert(char *lpInsertString,WORD insertPosition=0); + WORD remove(WORD removePosition=0); + int toInt(void)const; + short toShort(void)const; + unsigned short toUShort(void)const; + float toFloat(void)const; + double toDouble(void)const; + long toLong(void)const; + unsigned long toULong(void)const; + String &fromInt(int value); + String &fromShort(short value); + String &fromUShort(unsigned short value); + String &fromFloat(float value); + String &fromLong(long value); + String &fromULong(unsigned long value); + String &fromBool(bool value); + String &fromDouble(double value); + bool equals(const String &string)const; + const char *str(void)const; + char *str(void); + String quotes(void)const; + String reverse(void)const; +private: + enum{Blank=' ',CarriageReturn=0x0D,LineFeed=0x0A}; + void shiftRight(String &shiftString,WORD startPos,WORD endPos,WORD insertLength,WORD originalLength); + void removeData(void); + + char FAR *mnpStr; + DWORD mLengthBytes; +}; + +inline +String::String(void) +: mnpStr(0), mLengthBytes(0L) +{ + reserve(MaxString); +} + +inline +String::String(char characterItem) +: mnpStr(0), mLengthBytes(0) +{ + reserve(sizeof(characterItem)+1); + *mnpStr=characterItem; +} + +inline +String::~String() +{ + removeData(); +} + +inline +String::operator char *(void)const +{ + return mnpStr; +} + +inline +char &String::operator[](DWORD itemIndex) +{ + return *(mnpStr+itemIndex); +} + +inline +String &String::setAt(DWORD itemIndex,char ch) +{ + *(mnpStr+itemIndex)=ch; + return *this; +} + +inline +char String::charAt(DWORD itemIndex)const +{ + return *(mnpStr+itemIndex); +} + +inline +void String::reserve(DWORD nBytes,BOOL setZero) +{ + if(nBytes>mLengthBytes) + { + removeData(); + mnpStr=::new char[nBytes]; + mLengthBytes=nBytes; + } + if(setZero)::memset(mnpStr,0,mLengthBytes); +} + +inline +String String::substr(WORD startPosition)const +{ + return substr(startPosition,length()); +} + +inline +int String::length(void)const +{ + return (mnpStr?::strlen(mnpStr):0); +} + +inline +void String::removeData(void) +{ + if(!mnpStr)return; + ::delete[] mnpStr; + mnpStr=0; + mLengthBytes=0; +} + +inline +int String::isNull(void)const +{ + if(!mnpStr||!(*mnpStr))return 1; + return 0; +} + +inline +DWORD String::lengthBytes(void)const +{ + return mLengthBytes; +} + +inline +int String::operator==(const String &someString)const +{ + if(!mnpStr&&!someString.mnpStr)return 1; + if(!mnpStr||!someString.mnpStr)return 0; + return (0==::strcmp(mnpStr,someString.mnpStr)); +} + +inline +int String::operator!=(const String &someString)const +{ + if(!mnpStr&&!someString.mnpStr)return 0; + if(!mnpStr||!someString.mnpStr)return 1; + return (::strcmp(mnpStr,someString.mnpStr)); +} + +inline +int String::operator!=(const char *someCharStar)const +{ + if(!mnpStr&&!someCharStar)return 0; + if(!mnpStr||!someCharStar)return 1; + return (::strcmp(mnpStr,someCharStar)); +} + +inline +int String::operator==(const char *someCharStar)const +{ + if(!mnpStr&&!someCharStar)return 1; + if(!mnpStr||!someCharStar)return 0; + return (0==::strcmp(mnpStr,someCharStar)); +} + +inline +int String::operator<(const String &someString)const +{ + if(isNull()&&someString.isNull())return FALSE; + if(isNull())return TRUE; + return (::strcmp(mnpStr,someString.mnpStr)<0?TRUE:FALSE); +} + +inline +int String::operator>(const String &someString)const +{ + if(isNull()&&someString.isNull())return FALSE; + if(isNull())return FALSE; + return (::strcmp(mnpStr,someString.mnpStr)>0?TRUE:FALSE); +} + +inline +long String::strstr(const char *string)const +{ + if(!mnpStr)return 0; + return (long)::strstr(mnpStr,string); +} + +inline +bool String::equals(const String &string)const +{ + return *this==string?true:false; +} + +inline +const char *String::str(void)const +{ + return mnpStr; +} + +inline +char *String::str(void) +{ + return mnpStr; +} + +inline +String String::quotes(void)const +{ + return String("\"")+*this+String("\""); +} + +inline +String String::reverse(void)const +{ + String reverse; + for(int index=length()-1;index>=0;index--) + { + reverse+=charAt(index); + } + return reverse; +} + +typedef String string; + +#endif diff --git a/common/utility.hpp b/common/utility.hpp new file mode 100644 index 0000000..5c494e7 --- /dev/null +++ b/common/utility.hpp @@ -0,0 +1,160 @@ +#ifndef _COMMON_UTILITY_HPP_ +#define _COMMON_UTILITY_HPP_ +#include +#include +#include +#include + +class Utility +{ + public: + static String formatNumber(long number,bool commas=true); + static String formatNumber(double number,bool commas=true); + static String formatNumber(double number,int places=2); + static String formatCurrency(double number,int places=2); + static bool fmod(double dividend,double divisor); + static bool fmod(double dividend, double divisor,double epsilon); + static String bytesTransferredToString(double bytesTransferred); + private: + static String pad(String theString,char padChar,int toLength); + static String addCommas(String& theString); + Utility(); + ~Utility(); +}; + +inline +Utility::Utility() +{ +} + +inline +Utility::~Utility() +{ +} + +inline +String Utility::bytesTransferredToString(double bytesTransferred) +{ + double roundedValue = std::round(bytesTransferred * 100.00)/100.00; + if(roundedValue >= 1E+15) + { + return Utility::formatNumber(roundedValue/1E+15,2) + "Pb/s"; + } + else if(roundedValue >= 1000000000000) + { + return Utility::formatNumber(roundedValue/1000000000000,2) + "Tb/s"; + } + else if(roundedValue >= 1073741824) + { + return Utility::formatNumber(roundedValue/1073741824,2) + "Gbb/s"; + } + else if(roundedValue >= 1000000) + { + return Utility::formatNumber(roundedValue/1000000,2) + "Mb/s"; + } + else if(roundedValue >= 1000) + { + return Utility::formatNumber(roundedValue/1000,2) + "Kb/s"; + } + return Utility::formatNumber(roundedValue,2) + "B/s"; +} + +inline +String Utility::formatNumber(long number,bool commas) +{ + String formattedString; + String format="%ld"; + ::sprintf(formattedString.str(),format,number); + return addCommas(formattedString); +} + +inline +String Utility::formatNumber(double number,int places) +{ + String numberString = formatCurrency(number, places); + return numberString.substr(1); +} + +inline +String Utility::formatCurrency(double number,int places) +{ + String formattedString; + String format="%."; + format+=String().fromInt(places); + format+="f"; + ::sprintf(formattedString.str(),format,number); + Block items = formattedString.split('.'); + if(items[0].length()<=3) + { + if(2==items.size()) + { + return "$"+items[0]+"."+items[1]; + } + else + { + return "$"+items[0]; + } + } + String wholePart = addCommas(items[0]); + if(2==items.size()) + { + return "$"+wholePart+"."+items[1]; + } + return "$"+wholePart; +} + +inline +String Utility::addCommas(String& wholePart) +{ + String placesString; + wholePart=wholePart.reverse(); + for(int index=0;index0 && 0==(index%3))placesString+=","; + placesString+=wholePart.charAt(index); + } + placesString=placesString.reverse(); + return placesString; +} + +inline +String Utility::pad(String theString,char padChar,int toLength) +{ + while(theString.length()::epsilon() * 100; // Multiplied for a slightly larger tolerance + + // Calculate the remainder + double remainder = std::fmod(dividend, divisor); + + // Check if the absolute remainder is less than epsilon + return std::fabs(remainder) < epsilon; +} +#endif \ No newline at end of file diff --git a/common/windows.hpp b/common/windows.hpp new file mode 100755 index 0000000..1dc9448 --- /dev/null +++ b/common/windows.hpp @@ -0,0 +1,72 @@ +#ifndef _COMMON_WINDOWS_HPP_ +#define _COMMON_WINDOWS_HPP_ +#ifndef _MSC_VER +#define _MSC_VER 1200 +#endif +#define WIN32_LEAN_AND_MEAN +#define NOSERVICE +#define NOKANJI +#define NOCRYPT +#define NOMCX +#define NOLSTRING +#define NODBCS +#define NOMETAFILE +#define NOPROFILER +#define NOLANGUAGE +#define NOLOGERROR +#define NOMCX +#define NOIME +#define NOCOMM + +// for backwards compatibility +typedef unsigned short USHORT; +//typedef unsigned int DWORD; +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef bool BOOL; +typedef long LONG; +typedef unsigned long LPARAM; +typedef unsigned long DWORD_PTR; +#define TRUE 1 +#define FALSE 0 +#define FAR +#define NEAR +#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8)) +#define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16)) +#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff)) +#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff)) + +// The following definitions might be obsolete + +#ifndef DS_3DLOOK +#define DS_3DLOOK 0x0004L +#endif +#ifndef PFD_GENERIC_ACCELERATED +#define PFD_GENERIC_ACCELERATED 0x00001000 +#endif +#ifndef PFD_SWAP_LAYER_BUFFERS +#define PFD_SWAP_LAYER_BUFFERS 0x00000800 +#endif +#ifndef PFD_DEPTH_DONTCARE +#define PFD_DEPTH_DONTCARE 0x20000000 +#endif +#ifndef EN_MSGFILTER +#define EN_MSGFILTER 0x0700 +#endif +#ifndef EN_REQUESTRESIZE +#define EN_REQUESTRESIZE 0x0701 +#endif +#ifndef EN_SELCHANGE +#define EN_SELCHANGE 0x0702 +#endif +#ifndef EN_DROPFILES +#define EN_DROPFILES 0x0703 +#endif +#ifndef EN_PROTECTED +#define EN_PROTECTED 0x0704 +#endif +#endif +#ifndef IMAGE_DIRECTORY_ENTRY_COPYRIGHT +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT IMAGE_DIRECTORY_ENTRY_ARCHITECTURE +#endif diff --git a/listener/.vscode/launch.json b/listener/.vscode/launch.json new file mode 100644 index 0000000..c59732b --- /dev/null +++ b/listener/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/listener", + "args": ["SERVERMODE","55000"], + "stopAtEntry": true, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + } + + ] +} diff --git a/listener/.vscode/settings.json b/listener/.vscode/settings.json new file mode 100644 index 0000000..6da71c9 --- /dev/null +++ b/listener/.vscode/settings.json @@ -0,0 +1,57 @@ +{ + "files.associations": { + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "*.tpp": "cpp" + } +} \ No newline at end of file diff --git a/listener/.vscode/tasks.json b/listener/.vscode/tasks.json new file mode 100644 index 0000000..05054c5 --- /dev/null +++ b/listener/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/listener/CMakeLists.txt b/listener/CMakeLists.txt new file mode 100644 index 0000000..c8ba9c4 --- /dev/null +++ b/listener/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10.0) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/home/pi/Boneyard") +project(listener VERSION 0.1.0 LANGUAGES C CXX) + +add_executable(listener main.cpp ClientSocketSender.cpp SocketConnectionReceiver.cpp SocketServer.cpp) + +add_subdirectory(/home/pi/Boneyard/common /home/pi/Boneyard/common/build) +target_link_libraries(listener PRIVATE common) + + + diff --git a/listener/ClientSocketSender.cpp b/listener/ClientSocketSender.cpp new file mode 100644 index 0000000..d760a3d --- /dev/null +++ b/listener/ClientSocketSender.cpp @@ -0,0 +1,118 @@ +#include + +ClientSocketSender::ClientSocketSender(String ipAddress, int port) +: mIPAddress(ipAddress), mPort(port) +{ + mSocket = ::socket(AF_INET,SOCK_STREAM,0); + if(!isOkay()) + { + std::cout << "Unable to initialize socket " << std::endl; + return; + } + mInternalSocketAddress.sin_family = AF_INET; + mInternalSocketAddress.sin_port= ::htons(mPort); + int result = ::inet_pton(AF_INET, ipAddress.str(), &mInternalSocketAddress.sin_addr); + if(result<0) + { + std::cout << "Unable to convert ipaddress to network address" << std::endl; + close(); + return; + } + result = ::connect(mSocket, (struct sockaddr*)&mInternalSocketAddress, sizeof(mInternalSocketAddress)); + if(result<0) + { + close(); + std::cout << "Unable to connect to host " << mIPAddress << ":" << mPort << std::endl; + } +} + +ClientSocketSender::~ClientSocketSender() +{ + close(); +} + +void ClientSocketSender::close(void) +{ + if(-1!=mSocket) + { + ::close(mSocket); + mSocket=-1; + } +} + +bool ClientSocketSender::sendFile(String &pathFileName) +{ + Profiler profiler; + FileIO readFile(pathFileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadOnly, FileIO::CreationFlags::None); + if(!readFile.isOkay()) + { + std::cout << "File open failed " << pathFileName << std::endl; + return false; + } + readFile.setBufferLength(BUFFER_LENGTH); + DWORD fileLength = readFile.size(); + sendPutIndicator(pathFileName, fileLength); + Array readBuffer; + readBuffer.size(BUFFER_LENGTH); + while(true) + { + size_t bytesRead = readFile.read(&readBuffer[0], readBuffer.size()); + if(0==bytesRead) + { + std::cout << "No data was read from the file" << std::endl; + break; + } + sendPacketIndicator(bytesRead); + sendPacket(readBuffer, bytesRead); + if(bytesRead parts = fileName.split('/'); + String pureFileName = parts[parts.size()-1]; + String putIndicator = "PUT|"; + putIndicator+=pureFileName; + putIndicator+="|"; + putIndicator+=String().fromULong(fileLength); + putIndicator+="\r\n"; + ::send(mSocket, (char*)putIndicator, putIndicator.length(),0); + return true; +} + +bool ClientSocketSender::sendQuit(void) +{ + if(!isOkay())return false; + String quitIndicator = "QUIT\r\n"; + ::send(mSocket, (char*)quitIndicator, quitIndicator.length(),0); + return true; +} + +bool ClientSocketSender::sendPacket(Array &buffer,DWORD bytesToSend) +{ + if(!isOkay())return false; + ::send(mSocket, (char*)&buffer[0], bytesToSend,0); + return true; +} + +bool ClientSocketSender::isOkay(void) +{ + return -1==mSocket?false:true; +} diff --git a/listener/ClientSocketSender.hpp b/listener/ClientSocketSender.hpp new file mode 100644 index 0000000..535b883 --- /dev/null +++ b/listener/ClientSocketSender.hpp @@ -0,0 +1,37 @@ +#ifndef _LISTENER_CLIENTSOCKETSENDER_HPP_ +#define _LISTENER_CLIENTSOCKETSENDER_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ClientSocketSender +{ + public: + ClientSocketSender(String ipAddress,int port); + virtual ~ClientSocketSender(); + bool sendFile(String &pathFileName); + bool isOkay(void); + private: +// static constexpr int BUFFER_LENGTH=65536; + static constexpr int BUFFER_LENGTH=1048576; + void close(void); + bool sendPacketIndicator(DWORD bytesToSend); + bool sendPacket(Array &buffer,DWORD bytesToSend); + bool sendPutIndicator(String fileName,DWORD fileLength); + bool sendQuit(void); + + struct sockaddr_in mInternalSocketAddress; + int mSocket; + String mIPAddress; + int mPort; +}; +#endif diff --git a/listener/SocketConnectionReceiver.cpp b/listener/SocketConnectionReceiver.cpp new file mode 100644 index 0000000..e618f3f --- /dev/null +++ b/listener/SocketConnectionReceiver.cpp @@ -0,0 +1,157 @@ +#include +#include + +SocketConnectionReceiver::SocketConnectionReceiver(int socket, sockaddr_in internalSocketAddress) +: mSocket(socket), mInternalSocketAddress(internalSocketAddress) +{ +} + +SocketConnectionReceiver::~SocketConnectionReceiver() +{ +} + +void SocketConnectionReceiver::close(void) +{ + if(-1==mSocket)return; + std::cout << "Closing connection " << mSocket << std::endl; + ::close(mSocket); + mSocket=-1; +} + +void SocketConnectionReceiver::threadFunction(int data) +{ + String line; + while(true) + { + readLine(line); + if(0==line.length()) + { + std::cout << "Received an empty command" << std::endl; + break; + } + if(line=="QUIT" || line=="quit")break; + Block commands = line.split('|'); + if(0==commands.size())continue; + std::cout << commands[0] << std::endl; + commands[0].upper(); + if(commands[0]=="PUT") + { + handlePut(commands); + } + else + { + std::cout << "Unrecognized command >" << line << "<" << std::endl; + } + } + close(); + return; +} + +/// @brief The client wants to put a file. put {filename} {lengthbytes} +/// @param commands [0]=PUT, [1]=filename, [2]=total length +/// This will read PCKT {length}. +/// The connection will continue reading and writing until it receives PCKT 0 +/// @return +bool SocketConnectionReceiver::handlePut(Block &commands) +{ + Profiler profiler; + Array receiveBuffer; + Block subCommands; + String strLine; + String fileName; + size_t fileLength; + size_t totalBytesRead=0; + + fileName = commands[1]; + fileLength = commands[commands.size()-1].toLong(); + std::cout << "PUT" << " " << fileName << " " << fileLength << std::endl; + FileIO writeFile(fileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadWrite,FileIO::CreationFlags::CreateAlways); + + if(!writeFile.isOkay()) + { + std::cout << "Error creating " << fileName << std::endl; + return false; + } + + while(true) + { + readLine(strLine); + strLine.makeBlock(subCommands, "|"); + if(subCommands.size()!=2 || !(subCommands[0]=="PCKT")) + { + std::cout << "Unexpected command sequence" << std::endl; + break; + } + int bufferLength = subCommands[1].toLong(); + if(0==bufferLength) + { + std::cout << "Client indicated end of data" << std::endl; + break; + } + receiveBuffer.size(bufferLength); + size_t bytes_read = read(receiveBuffer); + totalBytesRead+=bytes_read; + if(bufferLength!=bytes_read) + { + std::cout << "Send/Receive size mismatch. The client indicated a data length of " << bufferLength << " but a data length of " << bytes_read << " was received"; + break; + } + writeFile.write(&receiveBuffer[0], receiveBuffer.size()); + + double percent = ((double)totalBytesRead / (double)fileLength)*100.00; + if(Utility::fmod(percent,10.00,0.0078125)) + { + double elapsedTimeSeconds = profiler.elapsed()/1000.00; + double bytesPerSecond = totalBytesRead / elapsedTimeSeconds; + String strBytesPerSecond = Utility::bytesTransferredToString(bytesPerSecond); + std::cout << "Transferred " << totalBytesRead << " of " << fileLength << " " << percent << " percent " << strBytesPerSecond << std::endl; + } + + } + std::cout << "Transfer complete" << std::endl; + std::cout << "Received " << totalBytesRead << std::endl; + writeFile.close(); + return totalBytesRead==fileLength; +} + +size_t SocketConnectionReceiver::readLine(String &line) +{ + size_t bytes_read = 0; + size_t total_bytes = 0; + char ch; + + char *lpLineBuffer = (char*)line; + while (total_bytes < line.lengthBytes() - 1) + { + bytes_read = ::recv(mSocket, &ch, 1, 0); + if (bytes_read <= 0) + { + return bytes_read; + } + if (ch=='\r') // Carriage return + { + recv(mSocket, &ch, 1, 0); // consume the line feed + break; + } + lpLineBuffer[total_bytes++] = ch; + } + lpLineBuffer[total_bytes] = '\0'; + return total_bytes; +} + +size_t SocketConnectionReceiver::read(Array &buffer) +{ + size_t bytes_read = 0; + size_t bytes_to_read = buffer.size(); + size_t total_bytes_read =0; + + char *lpLineBuffer = (char*)&buffer[0]; + while(bytes_to_read>0) + { + bytes_read = ::recv(mSocket, lpLineBuffer, bytes_to_read, 0); + lpLineBuffer+=bytes_read; + bytes_to_read -= bytes_read; + total_bytes_read += bytes_read; + } + return total_bytes_read; +} diff --git a/listener/SocketConnectionReceiver.hpp b/listener/SocketConnectionReceiver.hpp new file mode 100644 index 0000000..f33f967 --- /dev/null +++ b/listener/SocketConnectionReceiver.hpp @@ -0,0 +1,35 @@ +#ifndef _LISTENER_SOCKETCONNECTIONRECEIVER_HPP_ +#define _LISTENER_SOCKETCONNECTIONRECEIVER_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SocketConnectionReceiver +{ + public: + SocketConnectionReceiver(int socket, sockaddr_in inernalSocketAddress); + virtual ~SocketConnectionReceiver(); + void close(void); + private: + static constexpr size_t BUFFER_LENGTH=65536; // this is the buffer length for the socket + void threadFunction(int data); + bool handlePut(Block &commands); + size_t readLine(String &line); + size_t read(Array &buffer); + String restoreFileName(Block block,DWORD startIndex,DWORD endIndex); + + friend class SocketServer; + char mBuffer[BUFFER_LENGTH] = {0}; + int mSocket; + sockaddr_in mInternalSocketAddress; +}; +#endif \ No newline at end of file diff --git a/listener/SocketServer.cpp b/listener/SocketServer.cpp new file mode 100644 index 0000000..bfc44df --- /dev/null +++ b/listener/SocketServer.cpp @@ -0,0 +1,85 @@ +#include +#include + +/// @brief This will construct the socket listener. You must then call listen() to listen for connections +/// @param port +SocketServer::SocketServer(int port) +: mListenPort(port), mIsOkay(false), mSocketFileDescriptor(-1) +{ + std::cout << "SocketServer()" << std::endl; + int opt=-1; + int result; + +// create socket file descriptor + mSocketFileDescriptor = ::socket(AF_INET,SOCK_STREAM,0); + if(0==mSocketFileDescriptor)return; + +// attach socket to port + result = ::setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); + if(result) + { + close(); + return; + } + +// bind socket to network address and port + mInternalSocketAddress.sin_family = AF_INET; + mInternalSocketAddress.sin_addr.s_addr=INADDR_ANY; + + + mInternalSocketAddress.sin_port = htons(mListenPort); + result = ::bind(mSocketFileDescriptor,(struct sockaddr*)&mInternalSocketAddress,sizeof(mInternalSocketAddress)); + if(result) + { + close(); + return; + } + mIsOkay=true; +} + +SocketServer::~SocketServer() +{ + std::cout << "~SocketServer()" << std::endl; + close(); +} + +bool SocketServer::isOkay(void) +{ + return mIsOkay; +} + +void SocketServer::listen(void) +{ + while(isOkay()) + { + std::cout << "Listening on port " << mListenPort << std::endl; + int result = ::listen(mSocketFileDescriptor, MAX_CONNECTIONS); + if(result) + { + std::cout << "Error listening on port " << mListenPort << std::endl; + close(); + return; + } + struct sockaddr_in internalSocketAddress; + socklen_t addressLength = sizeof(internalSocketAddress); + + int socket = ::accept(mSocketFileDescriptor, (struct sockaddr*)&internalSocketAddress, &addressLength); + if(result) + { + std::cout << "Error accepting connection " << mListenPort << std::endl; + close(); + return; + } + SocketConnectionReceiver socketConnectionReceiver(socket, internalSocketAddress); + mExecutionThreads.push_back(std::thread(&SocketConnectionReceiver::threadFunction, &socketConnectionReceiver, 0)); + } +} + +void SocketServer::close(void) +{ + if(-1!=mSocketFileDescriptor) + { + ::close(mSocketFileDescriptor); + mSocketFileDescriptor=-1; + } +} diff --git a/listener/SocketServer.hpp b/listener/SocketServer.hpp new file mode 100644 index 0000000..bcfe24b --- /dev/null +++ b/listener/SocketServer.hpp @@ -0,0 +1,34 @@ +#ifndef _LISTENER_SOCKETSERVER_HPP_ +#define _LISTENER_SOCKETSERVER_HPP_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SocketServer +{ + public: + SocketServer(int port); + virtual ~SocketServer(); + void listen(void); + void close(void); + bool isOkay(void); + private: + static constexpr int MAX_CONNECTIONS=10; // The maximum connections to be queued at a time + bool mIsOkay; + int mListenPort; + int mSocketFileDescriptor; + struct sockaddr_in mInternalSocketAddress; + socklen_t mAddressLength = sizeof(mInternalSocketAddress); + std::vector mExecutionThreads; +}; +#endif \ No newline at end of file diff --git a/listener/main.cpp b/listener/main.cpp new file mode 100644 index 0000000..350186c --- /dev/null +++ b/listener/main.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// https://www.man7.org/linux/man-pages/man2/accept.2.html + +void handleServer(Block &commands); +void handleClient(Block &commands); + +/// @brief +/// @param argc +/// @param argv [0] program. [1] SERVERMODE {port} [2] CLIENTMODE {serveripaddress} {serverport} SEND {FileName} +/// @return +int main(int argc, char **argv) +{ + Profiler profiler; + + if(argc<2) + { + std::cout << "listener SERVERMODE {port} | CLIENTMODE {serveripaddress} {serverport} SEND {FileName}" << std::endl; + return 1; + } + Block arguments; + for(int index=0;index &commands) +{ + Profiler profiler; + + if(commands.size()!=3) + { + std::cout << "Missing required parameters" << std::endl; + return; + } + int port = commands[2].toInt(); + std::cout << commands[1] << ":" << commands[2] << std::endl; + SocketServer socketServer(commands[2].toInt()); + socketServer.listen(); + std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl; +} + +/// @brief [0]=program, [1]=CLIENTMODE, [2]=serveripaddress, [3]=serverport, [4]=pathfilename +/// @param commands +void handleClient(Block &commands) +{ + Profiler profiler; + if(commands.size()!=5) + { + std::cout << "Missing required parameters" << std::endl; + return; + } + + ClientSocketSender clientSocketSender(commands[2],commands[3].toInt()); + bool returnCode = clientSocketSender.sendFile(commands[4]); + if(!returnCode) + { + std::cout << "The transfer failed." << std::endl; + } + else + { + std::cout << "Transfer complete" << std::endl; + } + std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl; +} diff --git a/listener/scraps.txt b/listener/scraps.txt new file mode 100644 index 0000000..9159032 --- /dev/null +++ b/listener/scraps.txt @@ -0,0 +1,435 @@ +// class ClientSocketSender +// { +// public: +// ClientSocketSender(String ipAddress,int port); +// virtual ~ClientSocketSender(); +// bool sendFile(String &pathFileName); +// bool isOkay(void); +// private: +// static constexpr int BUFFER_LENGTH=65536; +// void close(void); +// bool sendPacketIndicator(long bytesToSend); +// bool sendPacket(Array &buffer,long bytesToSend); +// bool sendPutIndicator(String fileName,long fileLength); +// bool sendQuit(void); + +// struct sockaddr_in mInternalSocketAddress; +// int mSocket; +// String mIPAddress; +// int mPort; +// }; + +// inline +// ClientSocketSender::ClientSocketSender(String ipAddress, int port) +// : mIPAddress(ipAddress), mPort(port) +// { +// mSocket = ::socket(AF_INET,SOCK_STREAM,0); +// if(!isOkay()) +// { +// std::cout << "Unable to initialize socket " << std::endl; +// return; +// } +// mInternalSocketAddress.sin_family = AF_INET; +// mInternalSocketAddress.sin_port= ::htons(mPort); +// int result = ::inet_pton(AF_INET, ipAddress.str(), &mInternalSocketAddress.sin_addr); +// if(result<0) +// { +// std::cout << "Unable to convert ipaddress to network address" << std::endl; +// close(); +// return; +// } +// result = ::connect(mSocket, (struct sockaddr*)&mInternalSocketAddress, sizeof(mInternalSocketAddress)); +// if(result<0) +// { +// close(); +// std::cout << "Unable to connect to host " << mIPAddress << ":" << mPort << std::endl; +// } +// } + +// inline +// ClientSocketSender::~ClientSocketSender() +// { +// close(); +// } + +// inline +// void ClientSocketSender::close(void) +// { +// if(-1!=mSocket) +// { +// ::close(mSocket); +// mSocket=-1; +// } +// } + +// inline +// bool ClientSocketSender::sendFile(String &pathFileName) +// { +// FileIO readFile(pathFileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadOnly, FileIO::CreationFlags::None); +// if(!readFile.isOkay()) +// { +// std::cout << "File open failed " << pathFileName << std::endl; +// return false; +// } +// readFile.setBufferLength(BUFFER_LENGTH); +// DWORD fileLength = readFile.size(); +// sendPutIndicator(pathFileName, fileLength); +// Array readBuffer; +// readBuffer.size(BUFFER_LENGTH); +// while(true) +// { +// size_t bytesRead = readFile.read(&readBuffer[0], readBuffer.size()); +// if(0==bytesRead) +// { +// std::cout << "No data was read from the file" << std::endl; +// break; +// } +// sendPacketIndicator(bytesRead); +// sendPacket(readBuffer, bytesRead); +// if(bytesRead parts = fileName.split('/'); +// String pureFileName = parts[parts.size()-1]; +// String putIndicator = "PUT|"; +// putIndicator+=pureFileName; +// putIndicator+="|"; +// putIndicator+=String().fromInt(fileLength); +// putIndicator+="\r\n"; +// ::send(mSocket, (char*)putIndicator, putIndicator.length(),0); +// return true; +// } + +// inline +// bool ClientSocketSender::sendQuit(void) +// { +// if(!isOkay())return false; +// String quitIndicator = "QUIT\r\n"; +// ::send(mSocket, (char*)quitIndicator, quitIndicator.length(),0); +// return true; +// } + +// inline +// bool ClientSocketSender::sendPacket(Array &buffer,long bytesToSend) +// { +// if(!isOkay())return false; +// ::send(mSocket, (char*)&buffer[0], bytesToSend,0); +// return true; +// } + +// inline +// bool ClientSocketSender::isOkay(void) +// { +// return -1==mSocket?false:true; +// } + +// *********************************************************************************************************************************************************** +// *********************************************************************************************************************************************************** +// *********************************************************************************************************************************************************** + +// class SocketConnectionReceiver +// { +// public: +// SocketConnectionReceiver(int socket, sockaddr_in inernalSocketAddress); +// virtual ~SocketConnectionReceiver(); +// void close(void); +// private: +// static constexpr int BUFFER_LENGTH=65536; // this is the buffer length for the socket +// void threadFunction(int data); +// bool handlePut(Block &commands); +// int readLine(String &line); +// long read(Array &buffer); +// String restoreFileName(Block block,DWORD startIndex,DWORD endIndex); + +// friend class SocketServer; +// char mBuffer[BUFFER_LENGTH] = {0}; +// int mSocket; +// sockaddr_in mInternalSocketAddress; +// }; + +// inline +// SocketConnectionReceiver::SocketConnectionReceiver(int socket, sockaddr_in internalSocketAddress) +// : mSocket(socket), mInternalSocketAddress(internalSocketAddress) +// { +// } + +// inline +// SocketConnectionReceiver::~SocketConnectionReceiver() +// { +// } + +// inline +// void SocketConnectionReceiver::close(void) +// { +// if(-1==mSocket)return; +// std::cout << "Closing connection " << mSocket << std::endl; +// ::close(mSocket); +// mSocket=-1; +// } + +// inline +// void SocketConnectionReceiver::threadFunction(int data) +// { +// String line; +// while(true) +// { +// readLine(line); +// if(0==line.length()) +// { +// std::cout << "Received an empty command" << std::endl; +// break; +// } +// // std::cout << "'" << (char*)line << "'" << std::endl; +// if(line=="QUIT" || line=="quit")break; +// Block commands = line.split('|'); +// if(0==commands.size())continue; +// std::cout << commands[0] << std::endl; +// commands[0].upper(); +// if(commands[0]=="PUT") +// { +// handlePut(commands); +// } +// else +// { +// std::cout << "Unrecognized command >" << line << "<" << std::endl; +// } +// } +// close(); +// return; +// } + +// /// @brief The client wants to put a file. put {filename} {lengthbytes} +// /// @param commands [0]=PUT, [1]=filename, [2]=total length +// /// This will read PCKT {length}. +// /// The connection will continue reading and writing until it receives PCKT 0 +// /// @return +// inline +// bool SocketConnectionReceiver::handlePut(Block &commands) +// { +// Array receiveBuffer; +// Block subCommands; +// String strLine; +// String fileName; +// long fileLength; +// long totalBytesRead=0; + +// fileName = commands[1]; +// fileLength = commands[commands.size()-1].toLong(); +// std::cout << "PUT" << " " << fileName << " " << fileLength << std::endl; +// FileIO writeFile(fileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadWrite,FileIO::CreationFlags::CreateAlways); +// if(!writeFile.isOkay()) +// { +// std::cout << "Error creating " << fileName << std::endl; +// return false; +// } + +// while(true) +// { +// readLine(strLine); +// strLine.makeBlock(subCommands, "|"); +// if(subCommands.size()!=2 || !(subCommands[0]=="PCKT")) +// { +// std::cout << "Unexpected command sequence" << std::endl; +// break; +// } +// int bufferLength = subCommands[1].toLong(); +// if(0==bufferLength) +// { +// std::cout << "Client indicated end of data" << std::endl; +// break; +// } +// receiveBuffer.size(bufferLength); +// long bytes_read = read(receiveBuffer); +// totalBytesRead+=bytes_read; +// if(bufferLength!=bytes_read) +// { +// std::cout << "Send/Receive size mismatch. The client indicated a data length of " << bufferLength << " but a data length of " << bytes_read << " was received"; +// break; +// } +// writeFile.write(&receiveBuffer[0], receiveBuffer.size()); +// int percent = ((double)totalBytesRead / (double)fileLength)*100.00; +// if(0==(percent%10)) +// { +// std::cout << "Transferred " << totalBytesRead << " of " << fileLength << " " << percent << " percent" << std::endl; +// } + +// } +// std::cout << "Transfer complete" << std::endl; +// std::cout << "Received " << totalBytesRead << std::endl; +// writeFile.close(); +// return totalBytesRead==fileLength; +// } + +// inline +// int SocketConnectionReceiver::readLine(String &line) +// { +// int bytes_read = 0; +// int total_bytes = 0; +// char ch; + +// char *lpLineBuffer = (char*)line; +// while (total_bytes < line.lengthBytes() - 1) +// { +// bytes_read = ::recv(mSocket, &ch, 1, 0); +// if (bytes_read <= 0) +// { +// return bytes_read; +// } +// if (ch=='\r') // Carriage return +// { +// recv(mSocket, &ch, 1, 0); // consume the line feed +// break; +// } +// lpLineBuffer[total_bytes++] = ch; +// } +// lpLineBuffer[total_bytes] = '\0'; +// return total_bytes; +// } + +// inline +// long SocketConnectionReceiver::read(Array &buffer) +// { +// long bytes_read = 0; +// long bytes_to_read = buffer.size(); +// long total_bytes_read =0; + +// char *lpLineBuffer = (char*)&buffer[0]; +// while(bytes_to_read>0) +// { +// bytes_read = ::recv(mSocket, lpLineBuffer, bytes_to_read, 0); +// lpLineBuffer+=bytes_read; +// bytes_to_read -= bytes_read; +// total_bytes_read += bytes_read; +// } +// return total_bytes_read; +// } + +// *********************************************************************************************************************************************************** +// *********************************************************************************************************************************************************** +// *********************************************************************************************************************************************************** + + +// class SocketServer +// { +// public: +// SocketServer(int port); +// virtual ~SocketServer(); +// void listen(void); +// void close(void); +// bool isOkay(void); +// private: + +// static constexpr int MAX_CONNECTIONS=10; // The maximum connections to be queued at a time +// bool mIsOkay; +// int mListenPort; +// int mSocketFileDescriptor; +// struct sockaddr_in mInternalSocketAddress; +// socklen_t mAddressLength = sizeof(mInternalSocketAddress); +// std::vector mExecutionThreads; +// }; + +// /// @brief This will construct the socket listener. You must then call listen() to listen for connections +// /// @param port +// inline +// SocketServer::SocketServer(int port) +// : mListenPort(port), mIsOkay(false), mSocketFileDescriptor(-1) +// { +// std::cout << "SocketServer()" << std::endl; +// int opt=-1; +// int result; + +// // create socket file descriptor +// mSocketFileDescriptor = ::socket(AF_INET,SOCK_STREAM,0); +// if(0==mSocketFileDescriptor)return; + +// // attach socket to port +// result = ::setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); +// if(result) +// { +// close(); +// return; +// } + +// // bind socket to network address and port +// mInternalSocketAddress.sin_family = AF_INET; +// mInternalSocketAddress.sin_addr.s_addr=INADDR_ANY; + + +// mInternalSocketAddress.sin_port = htons(mListenPort); +// result = ::bind(mSocketFileDescriptor,(struct sockaddr*)&mInternalSocketAddress,sizeof(mInternalSocketAddress)); +// if(result) +// { +// close(); +// return; +// } +// mIsOkay=true; +// } + +// inline +// SocketServer::~SocketServer() +// { +// std::cout << "~SocketServer()" << std::endl; +// close(); +// } + +// inline +// bool SocketServer::isOkay(void) +// { +// return mIsOkay; +// } + +// inline +// void SocketServer::listen(void) +// { +// while(isOkay()) +// { +// std::cout << "Listening on port " << mListenPort << std::endl; +// int result = ::listen(mSocketFileDescriptor, MAX_CONNECTIONS); +// if(result) +// { +// std::cout << "Error listening on port " << mListenPort << std::endl; +// close(); +// return; +// } +// struct sockaddr_in internalSocketAddress; +// socklen_t addressLength = sizeof(internalSocketAddress); + +// int socket = ::accept(mSocketFileDescriptor, (struct sockaddr*)&internalSocketAddress, &addressLength); +// if(result) +// { +// std::cout << "Error accepting connection " << mListenPort << std::endl; +// close(); +// return; +// } +// SocketConnectionReceiver socketConnectionReceiver(socket, internalSocketAddress); +// mExecutionThreads.push_back(std::thread(&SocketConnectionReceiver::threadFunction, &socketConnectionReceiver, 0)); +// } +// } + +// inline +// void SocketServer::close(void) +// { +// if(-1!=mSocketFileDescriptor) +// { +// mSocketFileDescriptor=-1; +// } +// }