pppcompressionplugins/predictorcompression/SRC/DECOMP.CPP
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pppcompressionplugins/predictorcompression/SRC/DECOMP.CPP	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,337 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Predictor-1 PPP decompressor (RFC 1978)
+// 
+//
+
+/**
+ @file DECOMP.CPP
+*/
+
+#include "PREDCOMP.H"
+
+CPppDeCompressor* CPredCompFactory::NewPppDeCompressorL(CPppCcp* aCcp, TInt aMaxFrameLength,const TUint8* aMode)
+/**
+Constructor, Allocating memory to class CPredDeCompressor.
+
+@return DeComp, a pointer to class CPredDeCompressor.
+*/
+	{
+	aMode = aMode;
+	CPredDeCompressor* DeComp = new (ELeave) CPredDeCompressor();
+	CleanupStack::PushL(TCleanupItem(CNifFactory::Cleanup,DeComp));
+	DeComp->ConstructL(this, aCcp, aMaxFrameLength);
+	CleanupStack::Pop();
+
+	return DeComp;
+	}
+
+void CPredDeCompressor::ResetDecompressor(TInt /*aLength*/, RMBufChain& /*aPacket*/)
+/**
+This function is used to reset the Decompressor.
+*/
+	{
+	// Initializes the guess table
+	Reset();
+	iReConfiguring = FALSE;
+//	__LOGTEXT_DEBUG(_L8("ResetDecompressor\r\n"));
+	}
+
+
+void CPredDeCompressor::ConstructL(CPredCompFactory* aFactory, CPppCcp* aCcp, TInt aMaxFrameLength)
+/**
+2nd Phase Construction
+*/
+	{
+	// Initializes the guess table
+	Reset();
+//	__LOGTEXT_DEBUG(_L8("CPredDeCompressor::ConstructL\r\n"));
+	//
+	// Allow space for Protocol header (up to 2 bytes)
+	//
+	iCompressedBuffer = HBufC8::NewMaxL(aMaxFrameLength + 2);
+	iDecompressBuffer = HBufC8::NewMaxL(aMaxFrameLength + 2);
+	iReConfiguring = FALSE;
+	
+	iCcp = aCcp;
+	iFactory = aFactory;
+	iFactory->Open();
+	}
+
+TBool CPredDeCompressor::Decompress(RMBufQ& aBufferQ)
+/**
+@return 0 if we have not been destructed whilst frames are still arriving else Reconstituted buffer into a chain
+*/
+	{
+	// In case we have not been destructed whilst frames are still arriving
+	if(iReConfiguring)
+		return(FALSE);
+	// Remove the first buffer in the chain so we can extract the
+	// uncompressed length see RFC 1978 3.2
+	RMBuf *buf = aBufferQ.Remove();
+	// Check the pointer is valid, because there is small probability to be it NULL
+	// And make sure the RFC 1978 header bytes are there
+	if (buf == NULL || buf->Length() < 5)
+		{
+		aBufferQ.Free();
+		return(FALSE);
+		}
+	// Get the uncompressed length & compressed/uncompressed bit
+	TUint16 uncompressedLength = BigEndian::Get16(buf->Ptr());	
+	// Make sure the top bit is cleared before we do the CRC
+	*buf->Ptr() &= ~0x80;
+	// Calculate the 16bit CRC
+	TPppFcs16 fcs;
+	// CRC the 2 length bytes
+	fcs.Calc(buf->Ptr(),buf->Ptr()+2);
+	// effectively remove them by adjusting the offset of the start of the buffer
+	buf->AdjustStart(2);
+	aBufferQ.Prepend(buf);
+
+	// Set some convenient references to the class buffers
+	TPtr8 src = iCompressedBuffer->Des();
+	TPtr8 dest = iDecompressBuffer->Des();
+	// Copy method needs max buffer size
+	src.SetMax();
+	// Remember, src might be changed to point directly into the MBuf on return
+	// Overall length should include the 16 bit CRC
+	TInt overallLength = FlattenBuf(src,aBufferQ);
+	// Set the length
+	src.SetLength(overallLength);
+	// Remove the CRC from the end and deduct 2 from the buffer
+	TUint16 crc = (TUint16) ((src[src.Length()-1] << 8) | src[src.Length()-2]);
+	src.SetLength(src.Length()-2);
+	// Prepare for decompression
+	dest.SetLength(0);
+	// Check the top bit to see if this frame is compressed
+	if(uncompressedLength & 0x8000)
+		{
+		// Decompress using RFC 1878 algorithm
+		DecompressRFC1978(src,dest);
+		}
+	else
+		{
+		// not compressed
+		dest = src;
+		// Run compressor over the source to keep the guess table in synch
+		// with the server.
+		// NULL parameter as we aren't interested in the output
+		CompressRFC1978(src,NULL);
+		}
+	// The length set by the decompressor should match the header length
+	if(dest.Length() != (uncompressedLength & ~0x8000))
+		{
+		// Reset the guess table
+//		__LOGTEXT_ALWAYS(_L8("Length Mismatch\r\n"));
+		// Call into PPP ccp
+		// Causes Configure Request to be sent and we get destructed
+		iCcp->ReConfigLink();
+		// Set this flag so we throw frames until we are destructed
+		iReConfiguring = TRUE;
+		// Make sure to free any MBuf still in aBufferQ. This can occur
+		// if FlattenBuf avoided copying it into the descriptor.
+		aBufferQ.Free();
+		return(FALSE);
+		}
+	// calculate the fcs on the uncompressed data
+	fcs.Calc(dest.Ptr(),dest.Ptr()+dest.Length());
+	if(fcs.Fcs() != crc)
+		{
+		// Call into PPP ccp
+		// Causes Configure Request to be sent and we get destructed
+		iCcp->ReConfigLink();
+		iReConfiguring = TRUE;
+//		__LOGTEXT3_ALWAYS(_L8("Fcs Fail calcFcs = %X crc = %X\r\n"),calcFcs,crc);
+//		__LOGTEXT3_ALWAYS(_L8("Fcs Fail orig length = %d overall length = %d\r\n"),(uncompressedLength & ~0x8000),overallLength);
+		// Make sure to free any MBuf still in aBufferQ. This can occur
+		// if FlattenBuf avoided copying it into the descriptor.
+		aBufferQ.Free();
+		return(FALSE);
+		}
+	// Re constitute the buffer into a chain
+	return(CopyNewFrameToChain(dest,aBufferQ));
+	}
+
+CPredDeCompressor::CPredDeCompressor()
+/**
+Constructor
+*/
+	{
+	return;
+	}
+
+CPredDeCompressor::~CPredDeCompressor()
+/**
+Destructor
+*/
+	{
+	if(iFactory)
+		iFactory->Close();
+	return;
+	}
+
+/**
+Copies the contents of aBufferQ into the given descriptor. If the entire packet
+fits into a single MBuf, aPtr is changed to point directly into the MBuf and
+it is not freed from aBufferQ. Otherwise, all MBufs are freed and aBufferQ
+returns empty.
+
+@param aPtr Descriptor pointing to a large enough descriptor to hold the data.
+  On return, the descriptor may be changed to point directly into the MBuf.
+@param aBufferQ Input data
+
+@return Length of data in the buffer
+*/
+TUint CPredDeCompressor::FlattenBuf(TPtr8& aPtr, RMBufQ& aBufferQ)
+	{
+	if (aBufferQ.First() == aBufferQ.Last())
+		{
+		// The BufferQ only holds a single MBuf; just point the descriptor
+		// directly into that MBuf, bypassing the copy step.  Remember to free
+		// that MBuf before finishing the decompress.
+		aPtr.Set(aBufferQ.First()->Ptr(), aBufferQ.First()->Length(), aBufferQ.First()->Length());
+		return aPtr.Length();
+	}
+	return CopyFrameIntoFlatBuf(aPtr, aBufferQ);
+	}
+
+/**
+Copies the data in the MBuf into the given descriptor.
+	
+@param aPtr Descriptor large enough to hold the data
+@param aBufferQ Input data
+	
+@return Length of data in the output buffer, or 0 on error
+*/
+TUint CPredDeCompressor::CopyFrameIntoFlatBuf(const TPtr8& aPtr, RMBufQ& aBufferQ)
+	{
+	const TUint	maxLength = aPtr.MaxLength();
+	TUint8*		ptr = const_cast<TUint8*>(aPtr.Ptr());
+	TUint		Offset = 0;
+
+	RMBuf* Temp;
+	while ((Temp = aBufferQ.Remove()) != NULL)
+		{
+		// Make sure we don't copy past the end of the buffer
+		if ((Offset + Temp->Length()) > maxLength)
+			{
+			LOG(PredLog::Printf(_L("Input packet too long\r\n")));
+			Offset = 0;	// This is the only indication of an error
+			break;
+			}
+		Mem::Copy(ptr+Offset, Temp->Ptr(), Temp->Length());
+		Offset += Temp->Length();
+		Temp->Free();
+		}
+
+	// Make sure to free the buffers in case we exited the loop early
+	aBufferQ.Free();
+	return Offset;
+	}
+
+
+/**
+Allocate a new chain and copy the decompressed frame into it
+
+@param aSrc Output descriptor
+@param aBufferQ Input data
+
+@return TRUE on an error
+*/
+TBool CPredDeCompressor::CopyNewFrameToChain(TDesC8& aSrc,RMBufQ& aBufferQ)
+	{
+	TBool RetCode=FALSE;
+	RMBufChain	NewChain;
+
+	TRAPD(Ret, NewChain.AllocL(aSrc.Length()));
+	if (Ret == KErrNone)
+		{
+		RetCode = TRUE;
+		NewChain.CopyIn(aSrc);
+
+		// Make sure to free any MBuf still in aBufferQ. This can occur
+		// if FlattenBuf avoided copying it into the descriptor.
+		aBufferQ.Free();
+		aBufferQ.Assign(NewChain);
+		}
+
+	return RetCode;
+	}
+
+
+void TRFC1978Table::DecompressRFC1978(const TDesC8& aSrc,TDes8& aDest)
+/**
+Decompression logic from RFC 1978
+Modified to use descriptors
+We only support predictor type 1 so the "final" code has been removed as suggested
+in the RFC
+
+@param aSrc Data to compress
+@param aDest Compressed output buffer
+*/
+	{
+	TInt srcIndex = 0;
+	TInt len = aSrc.Length();
+	while(len >= 9)
+		{
+		TUint8 flags = aSrc[srcIndex++];
+		TUint8 bitMask;
+		TInt j;
+		for(bitMask = 1,j = 0;j < 8 ;j++,bitMask <<= 1)
+			{
+			TUint8 dest;
+			if(flags & bitMask)
+				{
+				dest = iGuessTable[iHash];
+				}
+			else
+				{
+				dest = aSrc[srcIndex++];
+				iGuessTable[iHash] = dest;
+				len--;
+				}
+			aDest.Append(dest);
+			Hash(dest);
+			}
+		len--;
+		}
+
+	while(len)
+		{
+		TUint8 flags = aSrc[srcIndex++];
+		TUint8 bitMask;
+		TInt j;
+
+		len--;
+		for(bitMask = 1,j = 0;j < 8 ;j++,bitMask <<= 1)
+			{
+			TUint8 dest;
+			if(flags & bitMask)
+				{
+				dest = iGuessTable[iHash];
+				}
+			else
+				{
+				if(!len)
+					break;
+
+				dest = aSrc[srcIndex++];
+				iGuessTable[iHash] = dest;
+				len--;
+				}
+			aDest.Append(dest);
+			Hash(dest);
+			}
+		}
+	}