#include "TMessage.h"
#include "Compression.h"
#include "TVirtualStreamerInfo.h"
#include "Bytes.h"
#include "TFile.h"
#include "TProcessID.h"
#include "RZip.h"
Bool_t TMessage::fgEvolution = kFALSE;
ClassImp(TMessage)
TMessage::TMessage(UInt_t what, Int_t bufsiz) :
TBufferFile(TBuffer::kWrite, bufsiz + 2*sizeof(UInt_t))
{
UInt_t reserved = 0;
*this << reserved;
fWhat = what;
*this << what;
fClass = 0;
fCompress = 0;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
fInfos = 0;
fEvolution = kFALSE;
SetBit(kCannotHandleMemberWiseStreaming);
}
TMessage::TMessage(void *buf, Int_t bufsize) : TBufferFile(TBuffer::kRead, bufsize, buf)
{
fBufCur += sizeof(UInt_t);
*this >> fWhat;
fCompress = 0;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
fInfos = 0;
fEvolution = kFALSE;
if (fWhat & kMESS_ZIP) {
fBufComp = fBuffer;
fBufCompCur = fBuffer + bufsize;
fBuffer = 0;
Uncompress();
}
if (fWhat == kMESS_OBJECT) {
InitMap();
fClass = ReadClass();
SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
ResetMap();
} else {
fClass = 0;
}
}
TMessage::~TMessage()
{
delete [] fBufComp;
delete fInfos;
}
void TMessage::EnableSchemaEvolutionForAll(Bool_t enable)
{
fgEvolution = enable;
}
Bool_t TMessage::UsesSchemaEvolutionForAll()
{
return fgEvolution;
}
void TMessage::ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t )
{
if (fgEvolution || fEvolution) {
if (!fInfos) fInfos = new TList();
fInfos->Add(info);
}
}
void TMessage::Forward()
{
if (IsReading()) {
SetWriteMode();
SetBufferOffset(fBufSize);
SetBit(kCannotHandleMemberWiseStreaming);
if (fBufComp) {
fCompPos = fBufCur;
}
}
}
void TMessage::TagStreamerInfo(TVirtualStreamerInfo *info)
{
if (fgEvolution || fEvolution) {
if (!fInfos) fInfos = new TList();
fInfos->Add(info);
}
}
void TMessage::Reset()
{
SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
ResetMap();
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
}
void TMessage::SetLength() const
{
if (IsWriting()) {
char *buf = Buffer();
tobuf(buf, (UInt_t)(Length() - sizeof(UInt_t)));
if (fBufComp) {
buf = fBufComp;
tobuf(buf, (UInt_t)(CompLength() - sizeof(UInt_t)));
}
}
}
void TMessage::SetWhat(UInt_t what)
{
fWhat = what;
char *buf = Buffer();
buf += sizeof(UInt_t);
tobuf(buf, what);
if (fBufComp) {
buf = fBufComp;
buf += sizeof(UInt_t);
tobuf(buf, what | kMESS_ZIP);
}
}
void TMessage::SetCompressionAlgorithm(Int_t algorithm)
{
if (algorithm < 0 || algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
Int_t newCompress;
if (fCompress < 0) {
newCompress = 100 * algorithm + 1;
} else {
int level = fCompress % 100;
newCompress = 100 * algorithm + level;
}
if (newCompress != fCompress && fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
fCompress = newCompress;
}
void TMessage::SetCompressionLevel(Int_t level)
{
if (level < 0) level = 0;
if (level > 99) level = 99;
Int_t newCompress;
if (fCompress < 0) {
newCompress = level;
} else {
int algorithm = fCompress / 100;
if (algorithm >= ROOT::kUndefinedCompressionAlgorithm) algorithm = 0;
newCompress = 100 * algorithm + level;
}
if (newCompress != fCompress && fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
fCompress = newCompress;
}
void TMessage::SetCompressionSettings(Int_t settings)
{
if (settings != fCompress && fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
fCompress = settings;
}
Int_t TMessage::Compress()
{
Int_t compressionLevel = GetCompressionLevel();
Int_t compressionAlgorithm = GetCompressionAlgorithm();
if (compressionLevel <= 0) {
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
return 0;
}
if (fBufComp && fCompPos == fBufCur) {
return 0;
}
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
if (Length() <= (Int_t)(256 + 2*sizeof(UInt_t))) {
return 0;
}
Int_t hdrlen = 2*sizeof(UInt_t);
Int_t messlen = Length() - hdrlen;
Int_t nbuffers = 1 + (messlen - 1) / kMAXZIPBUF;
Int_t chdrlen = 3*sizeof(UInt_t);
Int_t buflen = TMath::Max(512, chdrlen + messlen + 9*nbuffers);
fBufComp = new char[buflen];
char *messbuf = Buffer() + hdrlen;
char *bufcur = fBufComp + chdrlen;
Int_t noutot = 0;
Int_t nzip = 0;
Int_t nout, bufmax;
for (Int_t i = 0; i < nbuffers; ++i) {
if (i == nbuffers - 1)
bufmax = messlen - nzip;
else
bufmax = kMAXZIPBUF;
R__zipMultipleAlgorithm(compressionLevel, &bufmax, messbuf, &bufmax, bufcur, &nout, compressionAlgorithm);
if (nout == 0 || nout >= messlen) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
return -1;
}
bufcur += nout;
noutot += nout;
messbuf += kMAXZIPBUF;
nzip += kMAXZIPBUF;
}
fBufCompCur = bufcur;
fCompPos = fBufCur;
bufcur = fBufComp;
tobuf(bufcur, (UInt_t)(CompLength() - sizeof(UInt_t)));
Int_t what = fWhat | kMESS_ZIP;
tobuf(bufcur, what);
tobuf(bufcur, Length());
return 0;
}
Int_t TMessage::Uncompress()
{
if (!fBufComp || !(fWhat & kMESS_ZIP))
return -1;
Int_t buflen;
Int_t hdrlen = 2*sizeof(UInt_t);
char *bufcur1 = fBufComp + hdrlen;
frombuf(bufcur1, &buflen);
UChar_t *bufcur = (UChar_t*)bufcur1;
Int_t nin, nbuf;
if(R__unzip_header(&nin, bufcur, &nbuf)!=0) {
Error("Uncompress", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
return -1;
}
fBuffer = new char[buflen];
fBufSize = buflen;
fBufCur = fBuffer + sizeof(UInt_t) + sizeof(fWhat);
fBufMax = fBuffer + fBufSize;
char *messbuf = fBuffer + hdrlen;
Int_t nout;
Int_t noutot = 0;
while (1) {
Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
if (hc!=0) break;
R__unzip(&nin, bufcur, &nbuf, (unsigned char*) messbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= buflen - hdrlen) break;
bufcur += nin;
messbuf += nout;
}
fWhat &= ~kMESS_ZIP;
fCompress = 1;
return 0;
}
void TMessage::WriteObject(const TObject *obj)
{
if (fgEvolution || fEvolution) {
if (fInfos)
fInfos->Clear();
else
fInfos = new TList();
}
fBitsPIDs.ResetAllBits();
WriteObjectAny(obj, TObject::Class());
}
UShort_t TMessage::WriteProcessID(TProcessID *pid)
{
if (fBitsPIDs.TestBitNumber(0)) return 0;
if (!pid)
pid = TProcessID::GetPID();
if (!pid) return 0;
fBitsPIDs.SetBitNumber(0);
UInt_t uid = pid->GetUniqueID();
fBitsPIDs.SetBitNumber(uid+1);
return 1;
}