// @(#)root/net:$Name: $:$Id: TMessage.cxx,v 1.6 2004/05/07 09:51:58 brun Exp $
// Author: Fons Rademakers 19/12/96
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TMessage //
// //
// Message buffer class used for serializing objects and sending them //
// over a network. This class inherits from TBuffer the basic I/O //
// serializer. //
// //
//////////////////////////////////////////////////////////////////////////
#include "TMessage.h"
#include "Bytes.h"
#include "TFile.h"
extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
const Int_t kMAXBUF = 0xffffff;
ClassImp(TMessage)
//______________________________________________________________________________
TMessage::TMessage(UInt_t what) : TBuffer(kWrite)
{
// Create a TMessage object for storing objects. The "what" integer
// describes the type of message. Predifined ROOT system message types
// can be found in MessageTypes.h. Make sure your own message types are
// unique from the ROOT defined message types (i.e. 0 - 10000 are
// reserved by ROOT). In case you OR "what" with kMESS_ACK, the message
// will wait for an acknowledgement from the remote side. This makes
// the sending process synchronous. In case you OR "what" with kMESS_ZIP,
// the message will be compressed in TSocket using the zip algorithm
// (only if message is > 256 bytes).
// space at the beginning of the message reserved for the message length
UInt_t reserved = 0;
*this << reserved;
fWhat = what;
*this << what;
fClass = 0;
fCompress = 0;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
//______________________________________________________________________________
TMessage::TMessage(void *buf, Int_t bufsize) : TBuffer(kRead, bufsize, buf)
{
// Create a TMessage object for reading objects. The objects will be
// read from buf. Use the What() method to get the message type.
// skip space at the beginning of the message reserved for the message length
fBufCur += sizeof(UInt_t);
*this >> fWhat;
fCompress = 0;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
if (fWhat & kMESS_ZIP) {
// if buffer has kMESS_ZIP set, move it to fBufComp and uncompress
fBufComp = fBuffer;
fBufCompCur = fBuffer + bufsize;
fBuffer = 0;
Uncompress();
}
if (fWhat == kMESS_OBJECT) {
InitMap();
fClass = ReadClass(); // get first the class stored in message
SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
ResetMap();
} else {
fClass = 0;
}
}
//______________________________________________________________________________
TMessage::~TMessage()
{
// Clean up compression buffer.
delete [] fBufComp;
}
//______________________________________________________________________________
void TMessage::Forward()
{
// Change a buffer that was received into one that can be send, i.e.
// forward a just received message.
if (IsReading()) {
SetWriteMode();
SetBufferOffset(fBufSize);
if (fBufComp) {
fCompPos = fBufCur;
}
}
}
//______________________________________________________________________________
void TMessage::Reset()
{
// Reset the message buffer so we can use (i.e. fill) it again.
SetBufferOffset(sizeof(UInt_t) + sizeof(fWhat));
ResetMap();
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
}
//______________________________________________________________________________
void TMessage::SetLength() const
{
// Set the message length at the beginning of the message buffer.
// This method is only called by TSocket::Send().
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)
{
// Using this method one can change the message type a-posteriory.
// In case you OR "what" with kMESS_ACK, the message will wait for
// an acknowledgement from the remote side. This makes the sending
// process synchronous.
fWhat = what;
char *buf = Buffer();
buf += sizeof(UInt_t); // skip reserved length space
tobuf(buf, what);
if (fBufComp) {
buf = fBufComp;
buf += sizeof(UInt_t); // skip reserved length space
tobuf(buf, what | kMESS_ZIP);
}
}
//______________________________________________________________________________
void TMessage::SetCompressionLevel(Int_t level)
{
// Set the message compression level. Can be between 0 and 9 with 0
// being no compression and 9 maximum compression. In general the default
// level of 1 is the best compromise between achieved compression and
// cpu time. Compression will only happen when the message is > 256 bytes.
if (level < 0) level = 0;
if (level > 9) level = 9;
if (level != fCompress && fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
fCompress = level;
}
//______________________________________________________________________________
Int_t TMessage::Compress()
{
// Compress the message. The message will only be compressed if the
// compression level > 0 and the if the message is > 256 bytes.
// Returns -1 in case of error (when compression fails or
// when the message increases in size in some pathological cases),
// otherwise returns 0.
if (fCompress == 0) {
// no compression specified
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
return 0;
}
if (fBufComp && fCompPos == fBufCur) {
// the message was already compressed
return 0;
}
// remove any existing compressed buffer before compressing modified message
if (fBufComp) {
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
}
if (Length() <= (Int_t)(256 + 2*sizeof(UInt_t))) {
// this message is too small to be compressed
return 0;
}
Int_t hdrlen = 2*sizeof(UInt_t);
Int_t messlen = Length() - hdrlen;
Int_t nbuffers = messlen / kMAXBUF;
Int_t chdrlen = 3*sizeof(UInt_t); // compressed buffer header length
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)
bufmax = messlen - nzip;
else
bufmax = kMAXBUF;
R__zip(fCompress, &bufmax, messbuf, &bufmax, bufcur, &nout);
if (nout == 0 || nout >= messlen) {
//this happens when the buffer cannot be compressed
delete [] fBufComp;
fBufComp = 0;
fBufCompCur = 0;
fCompPos = 0;
return -1;
}
bufcur += nout;
noutot += nout;
messbuf += kMAXBUF;
nzip += kMAXBUF;
}
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()); // original uncompressed buffer length
return 0;
}
//______________________________________________________________________________
Int_t TMessage::Uncompress()
{
// Uncompress the message. The message will only be uncompressed when
// kMESS_ZIP is set. Returns -1 in case of error, 0 otherwise.
if (!fBufComp || !(fWhat & kMESS_ZIP))
return -1;
Int_t buflen;
Int_t hdrlen = 2*sizeof(UInt_t);
UChar_t *bufcur = (UChar_t*)fBufComp + hdrlen;
frombuf((char *&)bufcur, &buflen);
fBuffer = new char[buflen];
fBufSize = buflen;
fBufCur = fBuffer + sizeof(UInt_t) + sizeof(fWhat);
fBufMax = fBuffer + fBufSize;
char *messbuf = fBuffer + hdrlen;
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, messbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= buflen - hdrlen) break;
bufcur += nin;
messbuf += nout;
}
fWhat &= ~kMESS_ZIP;
fCompress = 1;
return 0;
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.