Select Git revision
ByteStream.cpp
-
Andrea Zoli authoredAndrea Zoli authored
ByteStream.cpp 12.58 KiB
/***************************************************************************
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();
}