|
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 } |