|
1 // Copyright (c) 2001-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 // |
|
15 |
|
16 #include <e32base.h> |
|
17 #include <stringpool.h> |
|
18 #include <wspdecoder.h> |
|
19 |
|
20 // Constants |
|
21 const TUint8 KWapQuote = 0x7F; |
|
22 const TUint8 KCarryBitMask = 0x80; |
|
23 #define KTopBitMask KCarryBitMask |
|
24 const TUint8 KTop3BitSet = 0x70; |
|
25 const TUint8 KQuoteChar = '\"'; |
|
26 |
|
27 // Panic category |
|
28 _LIT(KUriPanicCategory,"WSPDECODER"); |
|
29 |
|
30 |
|
31 //*********************************************************************** |
|
32 // TWspHeaderSegmenter |
|
33 //**********************************************************************/ |
|
34 |
|
35 |
|
36 /** |
|
37 NextL iterates through the buffer. Each call returns a TWspField in the paramater. |
|
38 |
|
39 @param aHeader Out - a TWspField containing the header <name,value> pair. |
|
40 @warning The TWspField::iHdrName will be opened internally. |
|
41 It must be closed by the caller before this class is destroyed. |
|
42 @return KErrNone if next field is returned |
|
43 KErrNotFound at the end of the buffer - no TWspField param returned |
|
44 KErrCorrupt if segmenting does not parse correctly |
|
45 @leave RStringPool::OpenFStringL StringPool leave code if opening string fails. |
|
46 */ |
|
47 EXPORT_C TInt TWspHeaderSegmenter::NextL(TWspField& aHeader) |
|
48 { |
|
49 // have we run out of buffer? |
|
50 if (iOffset >= iBuffer.Length()) |
|
51 return KErrNotFound; |
|
52 |
|
53 // Set decoder to current buffer |
|
54 TWspPrimitiveDecoder decoder(iBuffer.Mid(iOffset)); |
|
55 TInt bufLen = 0; |
|
56 |
|
57 |
|
58 // Get the Field Name |
|
59 switch(decoder.VarType()) |
|
60 { |
|
61 case TWspPrimitiveDecoder::EString: |
|
62 { |
|
63 TPtrC8 name; |
|
64 bufLen = decoder.String(name); |
|
65 if (bufLen < KErrNone) return bufLen; |
|
66 aHeader.iHdrName = iPool.OpenFStringL(name); |
|
67 } |
|
68 break; |
|
69 |
|
70 case TWspPrimitiveDecoder::E7BitVal: |
|
71 { |
|
72 TUint8 name; |
|
73 bufLen = decoder.Val7Bit(name); |
|
74 if (bufLen < KErrNone) return bufLen; |
|
75 |
|
76 aHeader.iHdrName = iPool.StringF(name, iStringTable); |
|
77 } |
|
78 break; |
|
79 |
|
80 default: // header name can't be anything else |
|
81 return KErrCorrupt; |
|
82 } |
|
83 |
|
84 // move our pointer past header name |
|
85 iOffset += bufLen; |
|
86 |
|
87 |
|
88 // Get the value buffer by figuring out the type, then set the pointer to span the entire |
|
89 // value. Note - further parsing will happen later to pull out specific value data. |
|
90 switch(decoder.VarType()) |
|
91 { |
|
92 case TWspPrimitiveDecoder::ELengthVal: |
|
93 { |
|
94 TInt len; |
|
95 bufLen = decoder.LengthVal(len); |
|
96 bufLen += len; |
|
97 } |
|
98 break; |
|
99 case TWspPrimitiveDecoder::EQuotedString: |
|
100 case TWspPrimitiveDecoder::EString: |
|
101 { |
|
102 TPtrC8 strBuf; |
|
103 bufLen = decoder.String(strBuf); |
|
104 } |
|
105 break; |
|
106 case TWspPrimitiveDecoder::E7BitVal: |
|
107 bufLen = 1; |
|
108 break; |
|
109 default: |
|
110 return KErrCorrupt; |
|
111 } |
|
112 |
|
113 if (bufLen < 0) |
|
114 return bufLen; |
|
115 |
|
116 if (iOffset + bufLen > iBuffer.Length()) |
|
117 return KErrCorrupt; |
|
118 |
|
119 aHeader.iValBuffer.Set(iBuffer.Mid(iOffset, bufLen)); |
|
120 iOffset += bufLen; |
|
121 return KErrNone; |
|
122 } |
|
123 |
|
124 |
|
125 // |
|
126 // WAP-WSP 8.4.1.2 |
|
127 // |
|
128 |
|
129 /** |
|
130 Looks at the byte currently pointed at in this buffer and returns the type. |
|
131 |
|
132 @return TWspHeaderType - the type of this data octet |
|
133 */ |
|
134 EXPORT_C TWspPrimitiveDecoder::TWspHeaderType TWspPrimitiveDecoder::VarType() const |
|
135 { |
|
136 TWspHeaderType type = ENotSet; |
|
137 |
|
138 // Check that the offset has not overflowed the buffer |
|
139 if( iOffset >= iBuffer.Length() ) |
|
140 return type; |
|
141 |
|
142 TInt octet = iBuffer[iOffset]; |
|
143 |
|
144 if (octet >= 0 && octet <= 31) |
|
145 type = ELengthVal; |
|
146 else if (octet == 34) |
|
147 type = EQuotedString; |
|
148 else if (octet >= 32 && octet <= 127) |
|
149 type = EString; |
|
150 else if (octet >= 128 && octet <= 255) |
|
151 type = E7BitVal; |
|
152 |
|
153 return type; |
|
154 } |
|
155 |
|
156 |
|
157 /** |
|
158 Returns length of the data following this byte. |
|
159 |
|
160 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal |
|
161 @post internal offset gets updated to move past this primitive |
|
162 @param aVal Out - the length encoded in this byte that indicates the size of the |
|
163 data that follows. |
|
164 @return postive number indicating the number of bytes read from the buffer |
|
165 KErrCorrupt if data is not formatted correctly. |
|
166 */ |
|
167 EXPORT_C TInt TWspPrimitiveDecoder::LengthVal(TInt& aVal) |
|
168 { |
|
169 // have we run out of buffer? |
|
170 if (iOffset >= iBuffer.Length()) |
|
171 return KErrCorrupt; |
|
172 |
|
173 TInt bufLen = 0; |
|
174 aVal = iBuffer[iOffset++]; |
|
175 |
|
176 if (aVal == 31) |
|
177 { |
|
178 TUint32 uintVarLen = 0; |
|
179 bufLen = UintVar(uintVarLen); |
|
180 if (bufLen < KErrNone) return bufLen; |
|
181 aVal = (TInt)uintVarLen; |
|
182 } |
|
183 |
|
184 // add the 1 byte read at to get first aVal |
|
185 ++bufLen; |
|
186 return bufLen; |
|
187 } |
|
188 |
|
189 |
|
190 /** |
|
191 Returns a TPtrC holding the string the buffer currently points at without the NULL |
|
192 termination. If the String type is a quoted string then the quotes are not included |
|
193 in the returned buffer. |
|
194 |
|
195 @pre iBuffer[iOffset] must be valid, VarType() == TWspType::EString |
|
196 @post internal offset gets updated to move past this primitive |
|
197 @param aString Out - the string |
|
198 @return postive number indicating the number of bytes read from the buffer |
|
199 KErrCorrupt if data is not formatted correctly. |
|
200 */ |
|
201 EXPORT_C TInt TWspPrimitiveDecoder::String(TPtrC8& aString) |
|
202 { |
|
203 TWspHeaderType type = VarType(); |
|
204 if( type != EString && type != EQuotedString) |
|
205 return KErrCorrupt; |
|
206 |
|
207 TInt nullIndex = iBuffer.Mid(iOffset).Locate('\0'); |
|
208 if( nullIndex == KErrNotFound ) |
|
209 return KErrCorrupt; |
|
210 |
|
211 // Set buffer to data not including the NULL terminator |
|
212 TPtrC8 buf = iBuffer.Mid(iOffset, nullIndex); |
|
213 |
|
214 // is there a WAP Quote (0x7F) or a " at the start - step over it |
|
215 TInt bufferOffset = 0; |
|
216 const TUint8 firstByte = iBuffer[iOffset]; |
|
217 if( firstByte == KQuoteChar || firstByte == KWapQuote ) |
|
218 ++bufferOffset; |
|
219 |
|
220 // Set the descriptor with the correct buffer segment |
|
221 aString.Set(buf.Mid(bufferOffset)); |
|
222 |
|
223 // Step over the NULL |
|
224 ++nullIndex; |
|
225 |
|
226 // update the offset |
|
227 iOffset += nullIndex; |
|
228 |
|
229 return nullIndex; |
|
230 } |
|
231 |
|
232 /** |
|
233 Returns a token, a short int or an octet value with the top bit cleared |
|
234 |
|
235 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::E7BitVal |
|
236 @post internal offset gets updated to move past this primitive |
|
237 @param aVal Out - the 7 bit value with top bit cleared |
|
238 @return postive number indicating the number of bytes read from the buffer |
|
239 KErrCorrupt if data is not formatted correctly. |
|
240 */ |
|
241 EXPORT_C TInt TWspPrimitiveDecoder::Val7Bit(TUint8& aVal) |
|
242 { |
|
243 // have we run out of buffer? |
|
244 if (iOffset >= iBuffer.Length()) |
|
245 return KErrCorrupt; |
|
246 |
|
247 aVal = (TUint8)(iBuffer[iOffset] & KWapQuote); |
|
248 ++iOffset; |
|
249 |
|
250 // 1 byte read |
|
251 return 1; |
|
252 } |
|
253 |
|
254 |
|
255 /** |
|
256 Returns an Integer - could be short or long. |
|
257 |
|
258 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or |
|
259 VarType() == TWspHeaderType::E7BitVal |
|
260 @post internal offset gets updated to move past this primitive |
|
261 @param aVal Out - the long int |
|
262 @return postive number indicating the number of bytes read from the buffer |
|
263 KErrCorrupt if data is not formatted correctly. |
|
264 */ |
|
265 EXPORT_C TInt TWspPrimitiveDecoder::Integer(TUint32& aVal) |
|
266 { |
|
267 // have we run out of buffer? |
|
268 if (iOffset >= iBuffer.Length()) |
|
269 return KErrCorrupt; |
|
270 |
|
271 TInt bufLen = 0; |
|
272 |
|
273 // read the first byte |
|
274 aVal = iBuffer[iOffset]; |
|
275 |
|
276 // short integers have the top bit set |
|
277 if (aVal & KTopBitMask) |
|
278 { |
|
279 aVal &= KWapQuote; |
|
280 ++iOffset; |
|
281 ++bufLen; |
|
282 } |
|
283 else |
|
284 { |
|
285 bufLen = LongInt(aVal); |
|
286 } |
|
287 |
|
288 return bufLen; |
|
289 } |
|
290 |
|
291 /** |
|
292 Returns a long int the buffer is currently pointing at. |
|
293 |
|
294 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal |
|
295 @post internal offset gets updated to move past this primitive |
|
296 @param aVal Out - the long int |
|
297 @return postive number indicating the number of bytes read from the buffer |
|
298 KErrCorrupt if data is not formatted correctly. |
|
299 */ |
|
300 EXPORT_C TInt TWspPrimitiveDecoder::LongInt(TUint32& aVal) |
|
301 { |
|
302 // have we run out of buffer? |
|
303 if (iOffset >= iBuffer.Length()) |
|
304 return KErrCorrupt; |
|
305 |
|
306 __ASSERT_DEBUG(aVal <= KMaxTUint, User::Panic(KUriPanicCategory, EWspDecoderLongIntOverflow)); |
|
307 // initialize |
|
308 aVal = 0; |
|
309 |
|
310 // Get num bytes encoding [len] [byte1] ... [byten] |
|
311 // we are positioned at that location in the source descriptor |
|
312 TUint8 numBytes = 0; |
|
313 TInt bufLen = Val7Bit(numBytes); |
|
314 if (bufLen < KErrNone) return bufLen; |
|
315 |
|
316 // len can be up to 30 and verify we have enough buffer |
|
317 if (numBytes > 30 || numBytes > iBuffer.Mid(iOffset).Length()) |
|
318 return KErrCorrupt; |
|
319 |
|
320 // Loop over the buffer, taking each byte and shifting it in count times. |
|
321 for (TInt count = 0; count < numBytes ; ++count) |
|
322 aVal = (aVal << 8) + iBuffer[iOffset++]; |
|
323 |
|
324 return (bufLen + numBytes); |
|
325 } |
|
326 |
|
327 /** |
|
328 Returns a TUint32 |
|
329 |
|
330 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or |
|
331 VarType() == TWspHeaderType::E7BitVal |
|
332 @post internal offset gets updated to move past this primitive |
|
333 @param aVal Out - the TUint32 decoded |
|
334 @return postive number indicating the number of bytes read from the buffer |
|
335 KErrCorrupt if data is not formatted correctly. |
|
336 */ |
|
337 EXPORT_C TInt TWspPrimitiveDecoder::UintVar(TUint32& aVal) |
|
338 { |
|
339 // have we run out of buffer? |
|
340 if (iOffset >= iBuffer.Length()) |
|
341 return KErrCorrupt; |
|
342 |
|
343 // initialize return val |
|
344 aVal = 0; |
|
345 |
|
346 // maximum length for a uintvar is 5 |
|
347 TInt lenLeft = Min(iBuffer.Mid(iOffset).Length(), 5); |
|
348 |
|
349 // get the first octet |
|
350 TUint8 byte = iBuffer[iOffset++]; |
|
351 TInt numBytes = 1; |
|
352 |
|
353 --lenLeft; |
|
354 |
|
355 // Check if any of the top 3 bits, ignoring the very top 'continue' bit, are set. |
|
356 // Later if we see that this is a 5 byte number - we'll know it is corrupt. |
|
357 // Encoding uses 7 bits/number 7x5=35 and we only support a maxiumum number |
|
358 // of 32 bits. |
|
359 TBool topThreeBitsSet = byte & KTop3BitSet; |
|
360 |
|
361 // copy over data from the byte into our return value (the top bit is a carry bit) |
|
362 aVal = byte & KWapQuote; |
|
363 |
|
364 // while the 'continue' bit is set and we have more data |
|
365 while ((byte & KCarryBitMask) && (lenLeft > 0)) |
|
366 { |
|
367 // shift our last value up |
|
368 aVal <<= 7; |
|
369 // get the next byte |
|
370 byte = iBuffer[iOffset++]; |
|
371 // copy it over to the lowest byte |
|
372 aVal |= byte & KWapQuote; |
|
373 --lenLeft; |
|
374 ++numBytes; |
|
375 } |
|
376 |
|
377 // last octet has continue bit set ... NOT allowed Or |
|
378 // this was encoded wrong - can't have a number bigger than 32 bits |
|
379 if ((byte & KCarryBitMask) || (numBytes == 5 && topThreeBitsSet)) |
|
380 return KErrCorrupt; |
|
381 |
|
382 // number of bytes read |
|
383 return numBytes; |
|
384 } |
|
385 |
|
386 |
|
387 /** |
|
388 Returns a formatted version string |
|
389 |
|
390 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal |
|
391 @post internal offset gets updated to move past this primitive |
|
392 @param aPool In - an opened string pool |
|
393 @param aVer Out - a formatted version string. Caller must close this string. |
|
394 @return postive number indicating the number of bytes read from the buffer |
|
395 KErrCorrupt if data is not formatted correctly. |
|
396 */ |
|
397 EXPORT_C TInt TWspPrimitiveDecoder::VersionL(RStringPool aPool, RStringF& aVer) |
|
398 { |
|
399 const TInt KMaxBufLength=5; |
|
400 TInt bufLen = 0; |
|
401 TInt byte = iBuffer[iOffset]; |
|
402 if (!(byte & KTopBitMask)) |
|
403 { |
|
404 TPtrC8 str; |
|
405 bufLen = String(str); |
|
406 if (bufLen < KErrNone) return KErrCorrupt; |
|
407 aVer = aPool.OpenFStringL(str); |
|
408 } |
|
409 else |
|
410 { |
|
411 // Major 0-7 , Minor 0-15 [xxx][yyyy] |
|
412 TUint8 val; |
|
413 bufLen = Val7Bit(val); |
|
414 if (bufLen < KErrNone) return KErrCorrupt; |
|
415 |
|
416 |
|
417 TInt minVer = val & 0x0F; |
|
418 TInt majVer = val & 0xF0; |
|
419 majVer >>= 4; |
|
420 |
|
421 if (majVer < 0 || majVer > 7) |
|
422 return KErrCorrupt; |
|
423 |
|
424 TBuf8<KMaxBufLength> buf; |
|
425 if (minVer == 0x0F) |
|
426 { |
|
427 _LIT8(KVersionFormat, "%D"); |
|
428 buf.Format(KVersionFormat, majVer); |
|
429 } |
|
430 else |
|
431 { |
|
432 _LIT8(KVersionFormat, "%D.%D"); |
|
433 buf.Format(KVersionFormat, majVer, minVer); |
|
434 } |
|
435 aVer = aPool.OpenFStringL(buf); |
|
436 } |
|
437 |
|
438 return bufLen; |
|
439 } |
|
440 |
|
441 /** |
|
442 Returns a TDateTime offset from January 1, 1970 - WAP WSP Section 8.4.2.3 Panics if |
|
443 the time val is greater then the maximum allowable integer size (32 bits). |
|
444 |
|
445 @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal |
|
446 @post internal offset gets updated to move past this primitive |
|
447 @param aDateTime Out - a WAP Date |
|
448 @return postive number indicating the number of bytes read from the buffer |
|
449 KErrCorrupt if data is not formatted correctly. |
|
450 */ |
|
451 EXPORT_C TInt TWspPrimitiveDecoder::Date(TDateTime& aDateTime) |
|
452 { |
|
453 TUint32 secVal; |
|
454 TInt bufLen = LongInt(secVal); |
|
455 __ASSERT_ALWAYS(bufLen <= KMaxTInt, User::Panic(KUriPanicCategory, EWspDecoderDateOverflow)); |
|
456 if (bufLen < KErrNone) return bufLen; |
|
457 |
|
458 TDateTime dt(1970,EJanuary,0,0,0,0,0); |
|
459 TTime time(dt); |
|
460 |
|
461 TInt sec = STATIC_CAST(TInt, secVal); |
|
462 time += TTimeIntervalSeconds(sec); |
|
463 aDateTime = time.DateTime(); |
|
464 |
|
465 return bufLen; |
|
466 } |