/*************************************************************************** ByteStream.cpp - description ------------------- begin : Thu Nov 29 2001 copyright : (C) 2001-2013 by Andrea Bulgarelli 2013-2914 by Andrea Bulgarelli, Andrea Zoli email : bulgarelli@iasfbo.inaf.it, zoli@iasfbo.inaf.it ***************************************************************************/ /*************************************************************************** * * * This program is free software for non commercial purpose * * and for public research institutes; you can redistribute it and/or * * modify it under the terms of the GNU General Public License. * * For commercial purpose see appropriate license terms * * * ***************************************************************************/ #include "ByteStream.h" #include "PacketLibDemo.h" #include "PacketException.h" #include "Utility.h" #include "lz4.h" #include "lz4hc.h" using namespace PacketLib; /// Returns a pointer of a field in the list of fields of this part of packet. /// \remarks mem_allocation = true indicates that the allocated memory must be released by the destroyer. /// \remarks memory_sharing=false In all methods of constructor or set type accepting byte*, it indicates that the swap is applied. /// In all methods of constructor or set type accepting ByteStreamPtr the swap is never applied. PacketLib::ByteStream::ByteStream(bool bigendian) : stream(0), byteInTheStream(0), bigendian(bigendian) { mem_allocation_constructor = true; setMemoryAllocated(false); mem_allocation_constructor = false; } PacketLib::ByteStream::ByteStream(dword dim, bool bigendian) : byteInTheStream(dim), bigendian(bigendian) { mem_allocation_constructor = true; stream = (byte*) new byte[dim]; setMemoryAllocated(true); mem_allocation_constructor = false; } PacketLib::ByteStream::ByteStream(byte* stream, dword dim, bool bigendian, bool memory_sharing) : stream(stream), byteInTheStream(dim), bigendian(bigendian) { mem_allocation_constructor = true; //if(!memory_sharing) // swapWordIfStreamIsLittleEndian(); /// \remarks memory_sharing == false means that the object is responsible for the memory setMemoryAllocated(!memory_sharing); mem_allocation_constructor = false; } PacketLib::ByteStream::ByteStream(ByteStreamPtr b0, dword start, dword end, bool memory_sharing) { mem_allocation_constructor = true; if(end == (dword)-1) end = b0->size(); byteInTheStream = end-start; this->stream = b0->stream+start; this->bigendian = b0->isBigendian(); //if(!memory_sharing) // swapWordIfStreamIsLittleEndian(); setMemoryAllocated(!memory_sharing); mem_allocation_constructor = false; } PacketLib::ByteStream::ByteStream(ByteStreamPtr b0, ByteStreamPtr b1, ByteStreamPtr b2) { mem_allocation_constructor = true; /// Streams are swapped dword dim = 0; if(b0 == 0 && b1 == 0 && b2 == 0) { setMemoryAllocated(false); byteInTheStream = 0; stream = 0; mem_allocation_constructor = false; return; } byteInTheStream = (b0!=0?b0->size():0) + (b1!=0?b1->size():0) + (b2!=0?b2->size():0); stream = (byte*) new byte[byteInTheStream]; this->bigendian = (b0!=0?b0->isBigendian():(b1!=0?b1->isBigendian():(b2!=0?b2->isBigendian():false))); if(b0 != 0) { memcpy(stream, b0->stream, b0->size()); dim += b0->size(); } if(b1 != 0) { memcpy(stream+dim, b1->stream, b1->size()); dim += b1->size(); } if(b2 != 0) { memcpy(stream+dim, b2->stream, b2->size()); dim += b2->size(); } setMemoryAllocated(true); mem_allocation_constructor = false; } PacketLib::ByteStream::~ByteStream() { if(mem_allocation) { delete[] stream; stream = 0; } } ByteStreamPtr PacketLib::ByteStream::compress(enum CompressionAlgorithms algorithmType, byte compressionLevel) { ByteStreamPtr b; switch(algorithmType) { case LZ4: { byte* buff = new byte[LZ4_compressBound(size())]; int buffsize = LZ4_compressHC2((const char*)stream, (char*)buff, size(), compressionLevel); if(!buffsize) { cout << "LZ4 compression error" << endl; return 0; } b = ByteStreamPtr(new ByteStream((byte*)buff, buffsize, bigendian)); break; } case NONE: { b = ByteStreamPtr(new ByteStream(stream, size(), bigendian)); break; } default: { return 0; } } #ifdef DEBUG cout << "Buffer decompressed size: " << size() << endl; cout << "Buffer compressed size: " << b->size() << endl; #endif return b; } ByteStreamPtr PacketLib::ByteStream::decompress(enum CompressionAlgorithms algorithmType, byte compressionLevel, dword dmax) { ByteStreamPtr b; UNUSED(compressionLevel); switch(algorithmType) { case NONE: { b = stream; break; } case LZ4: { byte* tmpbuff = new byte[dmax]; int buffsize = LZ4_decompress_safe((const char*)stream, (char*)tmpbuff, size(), dmax); if(!buffsize) { delete tmpbuff; throw new PacketException("LZ4 decompression error"); return 0; } if(buffsize < 0) { delete tmpbuff; throw new PacketException("LZ4 decompression error: the source stream is malformed"); } byte* decompbuff = new byte[buffsize]; memcpy(decompbuff, tmpbuff, buffsize); b = ByteStreamPtr(new ByteStream(decompbuff, buffsize, bigendian)); delete tmpbuff; break; } default: { return 0; } } #ifdef DEBUG cout << "dmax: " << dmax << endl; cout << "Buffer compressed size: " << size() << endl; cout << "Buffer decompressed size: " << b->size() << endl; #endif return b; } byte PacketLib::ByteStream::getByte( dword byteNumber) { DEMORET0; if(byteNumber <= byteInTheStream) return stream[byteNumber]; else return 0; } long PacketLib::ByteStream::getValue(dword start, word dim) { DEMORET0; byte b1, b2; if(start >= byteInTheStream) throw PacketException("PacketLib::ByteStream::getValue() start greater than the size of the ByteStream", 0); /// only 1 or 2 bytes if(dim == 0 || dim > 2) /// error return -1; if(bigendian) { b1 = stream[start]; if(dim==2) b2 = stream[start+1]; else b2 = 0; } else { if(dim==1) { if((start%2) == 0) b2 = stream[start+1]; else b2 = stream[start-1]; b1 = 0; } if(dim==2) { if((start%2) == 0) { /// even value b1=stream[start+1]; b2=stream[start]; } else { //b1 = (start-1)<0?0:stream[start-1]; //b2 = (start+2)>byteInTheStream?0:stream[start+2]; b1=(start+1)>=byteInTheStream?0:stream[start+1]; b2=stream[start]; } } } return b2 + b1*256; } ByteStreamPtr PacketLib::ByteStream::getSubByteStream(dword first, dword last) { DEMORET0; if(first > last) return NULL; if(last > byteInTheStream) return NULL; ByteStreamPtr b = ByteStreamPtr(new ByteStream((stream + first), last-first+1, bigendian, true)); return b; } ByteStreamPtr PacketLib::ByteStream::getSubByteStreamCopy(dword first, dword last) { DEMORET0; if(first > last) return NULL; if(last > byteInTheStream) return NULL; byte* streamtemp = (byte*) new byte[last-first+1]; for(dword i=0; i<last-first+1; i++) streamtemp[i] = stream[first+i]; return ByteStreamPtr(new ByteStream(streamtemp, last-first+1, bigendian, false)); } byte* PacketLib::ByteStream::getStream() { return stream; } byte* PacketLib::ByteStream::encode() { //swapWordIfStreamIsLittleEndian(); return stream; } void PacketLib::ByteStream::endOutputStream() { //swapWordIfStreamIsLittleEndian(); } dword PacketLib::ByteStream::size() { return byteInTheStream; } char* PacketLib::ByteStream::printStreamInHexadecimal() { return Utility::stringToHexadecimal(stream, byteInTheStream); } void PacketLib::ByteStream::setStreamCopy(byte* b, dword dim) { deleteStreamMemory(); byteInTheStream = dim; stream = (byte*) new byte[dim]; for(dword i=0; i<dim; i++) stream[i] = b[i]; //swapWordIfStreamIsLittleEndian(); setMemoryAllocated(true); } bool PacketLib::ByteStream::setStream(byte* b, dword dim, bool bigendian, bool memory_sharing) { deleteStreamMemory(); byteInTheStream = dim; this->bigendian = bigendian; this->stream = b; //if(!memory_sharing) swapWordIfStreamIsLittleEndian(); setMemoryAllocated(!memory_sharing); return true; } bool PacketLib::ByteStream::setStream(ByteStreamPtr b, dword first, dword last) { if(first > last) return false; if(last > b->size()) return false; deleteStreamMemory(); this->stream = (b->stream + first); this->byteInTheStream = last-first+1; this->bigendian = b->isBigendian(); setMemoryAllocated(false); return true; } bool PacketLib::ByteStream::getMemAllocation() { return mem_allocation; } bool PacketLib::ByteStream::isBigendian() const { return bigendian; } void PacketLib::ByteStream::setByte(dword start, word value) { stream[start] = value; } bool PacketLib::ByteStream::setWord(dword start, word value) { byte b1, b2; /// only even positions if(start%2 != 0) return false; /// It must not overtake the stream dimension if(start+1 > byteInTheStream) return false; /// Byte extraction /// \param LSByte b1 = (byte) value; /// \param MSByte b2 = (byte) (value >> 8); if(bigendian) { /// Swap stream[start] = b2; stream[start+1] = b1; } else { /// no Swap stream[start] = b1; stream[start+1] = b2; } return true; } void PacketLib::ByteStream::swapWordIfStreamIsLittleEndian() { if(!bigendian) { swapWord(); } } void PacketLib::ByteStream::swapWordIfStreamIsBigEndian() { if(bigendian) { swapWord(); } } void PacketLib::ByteStream::setMemoryAllocated(bool allocated) { mem_allocation = allocated; } void PacketLib::ByteStream::deleteStreamMemory() { if(!mem_allocation_constructor && mem_allocation) delete[] stream; } ByteStreamPtr PacketLib::ByteStream::getPaddedCopy(dword chunkSize, dword padSize) { if(byteInTheStream % chunkSize != 0) throw new PacketException("getPadCopy() error. Chunk size must be a divisor of ByteStream::size()."); dword nChunks = byteInTheStream / chunkSize; dword newChunkSize = chunkSize + padSize; ByteStreamPtr sPtr = ByteStreamPtr(new ByteStream(nChunks*(newChunkSize), bigendian)); byte* raw = sPtr->getStream(); for(dword i=0; i<nChunks; i++) memcpy(raw+i*newChunkSize, stream+i*chunkSize, chunkSize); return sPtr; } ByteStreamPtr PacketLib::ByteStream::getUnpaddedCopy(dword chunkSize, dword padSize) { if(byteInTheStream % chunkSize != 0) throw new PacketException("getUnpadCopy() error. Chunk size must be a divisor of ByteStream::size()."); if(chunkSize - padSize <= 0) throw new PacketException("getUnpadCopy() error. Chunk size - pad size gives a value <= 0."); dword nChunks = byteInTheStream / chunkSize; dword newChunkSize = chunkSize - padSize; ByteStreamPtr sPtr = ByteStreamPtr(new ByteStream(nChunks*(newChunkSize), bigendian)); byte* raw = sPtr->getStream(); for(dword i=0; i<nChunks; i++) memcpy(raw+i*newChunkSize, stream+i*chunkSize, newChunkSize); return sPtr; } void PacketLib::ByteStream::swapWord() { dword dim = byteInTheStream; for(dword i = 0; i< dim; i+=2) { /// For odd dimensions if((dim - i) != 1) { byte btemp = stream[i]; stream[i] = stream[i+1]; stream[i+1] = btemp; } } } void PacketLib::ByteStream::swapWordForIntel() { swapWordIfStreamIsBigEndian(); }