pppcompressionplugins/predictorcompression/SRC/DECOMP.CPP
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Predictor-1 PPP decompressor (RFC 1978)
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file DECOMP.CPP
       
    20 */
       
    21 
       
    22 #include "PREDCOMP.H"
       
    23 
       
    24 CPppDeCompressor* CPredCompFactory::NewPppDeCompressorL(CPppCcp* aCcp, TInt aMaxFrameLength,const TUint8* aMode)
       
    25 /**
       
    26 Constructor, Allocating memory to class CPredDeCompressor.
       
    27 
       
    28 @return DeComp, a pointer to class CPredDeCompressor.
       
    29 */
       
    30 	{
       
    31 	aMode = aMode;
       
    32 	CPredDeCompressor* DeComp = new (ELeave) CPredDeCompressor();
       
    33 	CleanupStack::PushL(TCleanupItem(CNifFactory::Cleanup,DeComp));
       
    34 	DeComp->ConstructL(this, aCcp, aMaxFrameLength);
       
    35 	CleanupStack::Pop();
       
    36 
       
    37 	return DeComp;
       
    38 	}
       
    39 
       
    40 void CPredDeCompressor::ResetDecompressor(TInt /*aLength*/, RMBufChain& /*aPacket*/)
       
    41 /**
       
    42 This function is used to reset the Decompressor.
       
    43 */
       
    44 	{
       
    45 	// Initializes the guess table
       
    46 	Reset();
       
    47 	iReConfiguring = FALSE;
       
    48 //	__LOGTEXT_DEBUG(_L8("ResetDecompressor\r\n"));
       
    49 	}
       
    50 
       
    51 
       
    52 void CPredDeCompressor::ConstructL(CPredCompFactory* aFactory, CPppCcp* aCcp, TInt aMaxFrameLength)
       
    53 /**
       
    54 2nd Phase Construction
       
    55 */
       
    56 	{
       
    57 	// Initializes the guess table
       
    58 	Reset();
       
    59 //	__LOGTEXT_DEBUG(_L8("CPredDeCompressor::ConstructL\r\n"));
       
    60 	//
       
    61 	// Allow space for Protocol header (up to 2 bytes)
       
    62 	//
       
    63 	iCompressedBuffer = HBufC8::NewMaxL(aMaxFrameLength + 2);
       
    64 	iDecompressBuffer = HBufC8::NewMaxL(aMaxFrameLength + 2);
       
    65 	iReConfiguring = FALSE;
       
    66 	
       
    67 	iCcp = aCcp;
       
    68 	iFactory = aFactory;
       
    69 	iFactory->Open();
       
    70 	}
       
    71 
       
    72 TBool CPredDeCompressor::Decompress(RMBufQ& aBufferQ)
       
    73 /**
       
    74 @return 0 if we have not been destructed whilst frames are still arriving else Reconstituted buffer into a chain
       
    75 */
       
    76 	{
       
    77 	// In case we have not been destructed whilst frames are still arriving
       
    78 	if(iReConfiguring)
       
    79 		return(FALSE);
       
    80 	// Remove the first buffer in the chain so we can extract the
       
    81 	// uncompressed length see RFC 1978 3.2
       
    82 	RMBuf *buf = aBufferQ.Remove();
       
    83 	// Check the pointer is valid, because there is small probability to be it NULL
       
    84 	// And make sure the RFC 1978 header bytes are there
       
    85 	if (buf == NULL || buf->Length() < 5)
       
    86 		{
       
    87 		aBufferQ.Free();
       
    88 		return(FALSE);
       
    89 		}
       
    90 	// Get the uncompressed length & compressed/uncompressed bit
       
    91 	TUint16 uncompressedLength = BigEndian::Get16(buf->Ptr());	
       
    92 	// Make sure the top bit is cleared before we do the CRC
       
    93 	*buf->Ptr() &= ~0x80;
       
    94 	// Calculate the 16bit CRC
       
    95 	TPppFcs16 fcs;
       
    96 	// CRC the 2 length bytes
       
    97 	fcs.Calc(buf->Ptr(),buf->Ptr()+2);
       
    98 	// effectively remove them by adjusting the offset of the start of the buffer
       
    99 	buf->AdjustStart(2);
       
   100 	aBufferQ.Prepend(buf);
       
   101 
       
   102 	// Set some convenient references to the class buffers
       
   103 	TPtr8 src = iCompressedBuffer->Des();
       
   104 	TPtr8 dest = iDecompressBuffer->Des();
       
   105 	// Copy method needs max buffer size
       
   106 	src.SetMax();
       
   107 	// Remember, src might be changed to point directly into the MBuf on return
       
   108 	// Overall length should include the 16 bit CRC
       
   109 	TInt overallLength = FlattenBuf(src,aBufferQ);
       
   110 	// Set the length
       
   111 	src.SetLength(overallLength);
       
   112 	// Remove the CRC from the end and deduct 2 from the buffer
       
   113 	TUint16 crc = (TUint16) ((src[src.Length()-1] << 8) | src[src.Length()-2]);
       
   114 	src.SetLength(src.Length()-2);
       
   115 	// Prepare for decompression
       
   116 	dest.SetLength(0);
       
   117 	// Check the top bit to see if this frame is compressed
       
   118 	if(uncompressedLength & 0x8000)
       
   119 		{
       
   120 		// Decompress using RFC 1878 algorithm
       
   121 		DecompressRFC1978(src,dest);
       
   122 		}
       
   123 	else
       
   124 		{
       
   125 		// not compressed
       
   126 		dest = src;
       
   127 		// Run compressor over the source to keep the guess table in synch
       
   128 		// with the server.
       
   129 		// NULL parameter as we aren't interested in the output
       
   130 		CompressRFC1978(src,NULL);
       
   131 		}
       
   132 	// The length set by the decompressor should match the header length
       
   133 	if(dest.Length() != (uncompressedLength & ~0x8000))
       
   134 		{
       
   135 		// Reset the guess table
       
   136 //		__LOGTEXT_ALWAYS(_L8("Length Mismatch\r\n"));
       
   137 		// Call into PPP ccp
       
   138 		// Causes Configure Request to be sent and we get destructed
       
   139 		iCcp->ReConfigLink();
       
   140 		// Set this flag so we throw frames until we are destructed
       
   141 		iReConfiguring = TRUE;
       
   142 		// Make sure to free any MBuf still in aBufferQ. This can occur
       
   143 		// if FlattenBuf avoided copying it into the descriptor.
       
   144 		aBufferQ.Free();
       
   145 		return(FALSE);
       
   146 		}
       
   147 	// calculate the fcs on the uncompressed data
       
   148 	fcs.Calc(dest.Ptr(),dest.Ptr()+dest.Length());
       
   149 	if(fcs.Fcs() != crc)
       
   150 		{
       
   151 		// Call into PPP ccp
       
   152 		// Causes Configure Request to be sent and we get destructed
       
   153 		iCcp->ReConfigLink();
       
   154 		iReConfiguring = TRUE;
       
   155 //		__LOGTEXT3_ALWAYS(_L8("Fcs Fail calcFcs = %X crc = %X\r\n"),calcFcs,crc);
       
   156 //		__LOGTEXT3_ALWAYS(_L8("Fcs Fail orig length = %d overall length = %d\r\n"),(uncompressedLength & ~0x8000),overallLength);
       
   157 		// Make sure to free any MBuf still in aBufferQ. This can occur
       
   158 		// if FlattenBuf avoided copying it into the descriptor.
       
   159 		aBufferQ.Free();
       
   160 		return(FALSE);
       
   161 		}
       
   162 	// Re constitute the buffer into a chain
       
   163 	return(CopyNewFrameToChain(dest,aBufferQ));
       
   164 	}
       
   165 
       
   166 CPredDeCompressor::CPredDeCompressor()
       
   167 /**
       
   168 Constructor
       
   169 */
       
   170 	{
       
   171 	return;
       
   172 	}
       
   173 
       
   174 CPredDeCompressor::~CPredDeCompressor()
       
   175 /**
       
   176 Destructor
       
   177 */
       
   178 	{
       
   179 	if(iFactory)
       
   180 		iFactory->Close();
       
   181 	return;
       
   182 	}
       
   183 
       
   184 /**
       
   185 Copies the contents of aBufferQ into the given descriptor. If the entire packet
       
   186 fits into a single MBuf, aPtr is changed to point directly into the MBuf and
       
   187 it is not freed from aBufferQ. Otherwise, all MBufs are freed and aBufferQ
       
   188 returns empty.
       
   189 
       
   190 @param aPtr Descriptor pointing to a large enough descriptor to hold the data.
       
   191   On return, the descriptor may be changed to point directly into the MBuf.
       
   192 @param aBufferQ Input data
       
   193 
       
   194 @return Length of data in the buffer
       
   195 */
       
   196 TUint CPredDeCompressor::FlattenBuf(TPtr8& aPtr, RMBufQ& aBufferQ)
       
   197 	{
       
   198 	if (aBufferQ.First() == aBufferQ.Last())
       
   199 		{
       
   200 		// The BufferQ only holds a single MBuf; just point the descriptor
       
   201 		// directly into that MBuf, bypassing the copy step.  Remember to free
       
   202 		// that MBuf before finishing the decompress.
       
   203 		aPtr.Set(aBufferQ.First()->Ptr(), aBufferQ.First()->Length(), aBufferQ.First()->Length());
       
   204 		return aPtr.Length();
       
   205 	}
       
   206 	return CopyFrameIntoFlatBuf(aPtr, aBufferQ);
       
   207 	}
       
   208 
       
   209 /**
       
   210 Copies the data in the MBuf into the given descriptor.
       
   211 	
       
   212 @param aPtr Descriptor large enough to hold the data
       
   213 @param aBufferQ Input data
       
   214 	
       
   215 @return Length of data in the output buffer, or 0 on error
       
   216 */
       
   217 TUint CPredDeCompressor::CopyFrameIntoFlatBuf(const TPtr8& aPtr, RMBufQ& aBufferQ)
       
   218 	{
       
   219 	const TUint	maxLength = aPtr.MaxLength();
       
   220 	TUint8*		ptr = const_cast<TUint8*>(aPtr.Ptr());
       
   221 	TUint		Offset = 0;
       
   222 
       
   223 	RMBuf* Temp;
       
   224 	while ((Temp = aBufferQ.Remove()) != NULL)
       
   225 		{
       
   226 		// Make sure we don't copy past the end of the buffer
       
   227 		if ((Offset + Temp->Length()) > maxLength)
       
   228 			{
       
   229 			LOG(PredLog::Printf(_L("Input packet too long\r\n")));
       
   230 			Offset = 0;	// This is the only indication of an error
       
   231 			break;
       
   232 			}
       
   233 		Mem::Copy(ptr+Offset, Temp->Ptr(), Temp->Length());
       
   234 		Offset += Temp->Length();
       
   235 		Temp->Free();
       
   236 		}
       
   237 
       
   238 	// Make sure to free the buffers in case we exited the loop early
       
   239 	aBufferQ.Free();
       
   240 	return Offset;
       
   241 	}
       
   242 
       
   243 
       
   244 /**
       
   245 Allocate a new chain and copy the decompressed frame into it
       
   246 
       
   247 @param aSrc Output descriptor
       
   248 @param aBufferQ Input data
       
   249 
       
   250 @return TRUE on an error
       
   251 */
       
   252 TBool CPredDeCompressor::CopyNewFrameToChain(TDesC8& aSrc,RMBufQ& aBufferQ)
       
   253 	{
       
   254 	TBool RetCode=FALSE;
       
   255 	RMBufChain	NewChain;
       
   256 
       
   257 	TRAPD(Ret, NewChain.AllocL(aSrc.Length()));
       
   258 	if (Ret == KErrNone)
       
   259 		{
       
   260 		RetCode = TRUE;
       
   261 		NewChain.CopyIn(aSrc);
       
   262 
       
   263 		// Make sure to free any MBuf still in aBufferQ. This can occur
       
   264 		// if FlattenBuf avoided copying it into the descriptor.
       
   265 		aBufferQ.Free();
       
   266 		aBufferQ.Assign(NewChain);
       
   267 		}
       
   268 
       
   269 	return RetCode;
       
   270 	}
       
   271 
       
   272 
       
   273 void TRFC1978Table::DecompressRFC1978(const TDesC8& aSrc,TDes8& aDest)
       
   274 /**
       
   275 Decompression logic from RFC 1978
       
   276 Modified to use descriptors
       
   277 We only support predictor type 1 so the "final" code has been removed as suggested
       
   278 in the RFC
       
   279 
       
   280 @param aSrc Data to compress
       
   281 @param aDest Compressed output buffer
       
   282 */
       
   283 	{
       
   284 	TInt srcIndex = 0;
       
   285 	TInt len = aSrc.Length();
       
   286 	while(len >= 9)
       
   287 		{
       
   288 		TUint8 flags = aSrc[srcIndex++];
       
   289 		TUint8 bitMask;
       
   290 		TInt j;
       
   291 		for(bitMask = 1,j = 0;j < 8 ;j++,bitMask <<= 1)
       
   292 			{
       
   293 			TUint8 dest;
       
   294 			if(flags & bitMask)
       
   295 				{
       
   296 				dest = iGuessTable[iHash];
       
   297 				}
       
   298 			else
       
   299 				{
       
   300 				dest = aSrc[srcIndex++];
       
   301 				iGuessTable[iHash] = dest;
       
   302 				len--;
       
   303 				}
       
   304 			aDest.Append(dest);
       
   305 			Hash(dest);
       
   306 			}
       
   307 		len--;
       
   308 		}
       
   309 
       
   310 	while(len)
       
   311 		{
       
   312 		TUint8 flags = aSrc[srcIndex++];
       
   313 		TUint8 bitMask;
       
   314 		TInt j;
       
   315 
       
   316 		len--;
       
   317 		for(bitMask = 1,j = 0;j < 8 ;j++,bitMask <<= 1)
       
   318 			{
       
   319 			TUint8 dest;
       
   320 			if(flags & bitMask)
       
   321 				{
       
   322 				dest = iGuessTable[iHash];
       
   323 				}
       
   324 			else
       
   325 				{
       
   326 				if(!len)
       
   327 					break;
       
   328 
       
   329 				dest = aSrc[srcIndex++];
       
   330 				iGuessTable[iHash] = dest;
       
   331 				len--;
       
   332 				}
       
   333 			aDest.Append(dest);
       
   334 			Hash(dest);
       
   335 			}
       
   336 		}
       
   337 	}