diff -r 000000000000 -r af10295192d8 pppcompressionplugins/predictorcompression/SRC/DECOMP.CPP --- /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(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); + } + } + }