|
1 /* |
|
2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Implementation of class TCodParser. |
|
16 * |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 // INCLUDE FILES |
|
22 |
|
23 #include "CodParser.h" |
|
24 #include "CodData.h" |
|
25 #include "CodError.h" |
|
26 #include "CodPanic.h" |
|
27 #include "CodLogger.h" |
|
28 |
|
29 // ================= CONSTANTS ======================= |
|
30 |
|
31 // Characters. |
|
32 LOCAL_D const TText KCodSpace = 0x0020; ///< Space. |
|
33 LOCAL_D const TText KCodHorizTab = 0x0009; ///< Horizontal tab. |
|
34 LOCAL_D const TText KCodCarriageRet = 0x000d; ///< Carriage return. |
|
35 LOCAL_D const TText KCodLineFeed = 0x000a; ///< Line feed. |
|
36 LOCAL_D const TText KCodColon = ':'; ///< Colon. |
|
37 LOCAL_D const TText KCodLowControl = 0x001F; ///< Lower Control characters. |
|
38 LOCAL_D const TText KCodUpControl = 0x007F; ///< Upper Control character. |
|
39 |
|
40 // Attribute names. |
|
41 _LIT( KCodName, "COD-Name" ); ///< COD-Name. |
|
42 _LIT( KCodVendor, "COD-Vendor" ); ///< COD-Vendor. |
|
43 _LIT( KCodDescription, "COD-Description" ); ///< COD-Description. |
|
44 _LIT( KCodUrl, "COD-URL" ); ///< COD-URL. |
|
45 _LIT( KCodSize, "COD-Size" ); ///< COD-Size. |
|
46 _LIT( KCodType, "COD-Type" ); ///< COD-Type. |
|
47 _LIT( KCodInstallNotify, "COD-Install-Notify" ); ///< COD-Install-Notify. |
|
48 _LIT( KCodNextUrl, "COD-Next-URL" ); ///< COD-Next-URL. |
|
49 _LIT( KCodNextUrlAtError, "COD-Next-URLatError" ); ///< COD-Next_URLatError. |
|
50 _LIT( KCodInfoUrl, "COD-Info-URL" ); ///< COD-Info-URL. |
|
51 _LIT( KCodPrice, "COD-Price" ); ///< COD-Price. |
|
52 _LIT( KCodIcon, "COD-Icon" ); ///< COD-Icon. |
|
53 |
|
54 // ================= MEMBER FUNCTIONS ======================= |
|
55 |
|
56 // --------------------------------------------------------- |
|
57 // TCodParser::ParseL() |
|
58 // --------------------------------------------------------- |
|
59 // |
|
60 void TCodParser::ParseL( const TDesC& aBuf, CCodData& aData ) |
|
61 { |
|
62 CLOG(( EParse, 2, _L("-> TCodParser::ParseL") )); |
|
63 CDUMP(( EParse, 2, _S("Buf:"), _S(" "), \ |
|
64 (const TUint8*)aBuf.Ptr(), aBuf.Size() )); |
|
65 iError = KErrNone; |
|
66 iData = &aData; |
|
67 iBuf = &aBuf; |
|
68 iCurP = iBuf->Ptr(); |
|
69 iEndP = iCurP + iBuf->Length(); |
|
70 // Processing lines (attribute and value) until there is more lines to read. |
|
71 while ( AttrLineL() ) |
|
72 { |
|
73 // Some compilers require empty controlled statement block instead of |
|
74 // just a semicolon. |
|
75 } |
|
76 |
|
77 #ifdef __TEST_COD_LOG |
|
78 TPtrC ptr16; |
|
79 TPtrC8 ptr8; |
|
80 CLOG(( EParse, 3, _L("TCodParser::ParseL data:") )); |
|
81 ptr16.Set( aData.Name() ); |
|
82 CLOG(( EParse, 3, _L(" Name<%S>"), &ptr16 )); |
|
83 ptr16.Set( aData.Vendor() ); |
|
84 CLOG(( EParse, 3, _L(" Vendor<%S>"), &ptr16 )); |
|
85 ptr16.Set( aData.Description() ); |
|
86 CLOG(( EParse, 3, _L(" Desc<%S>"), &ptr16 )); |
|
87 CLOG(( EParse, 3, _L(" Size(%d)"), aData.Size() )); |
|
88 ptr8.Set( aData.InstallNotify() ); |
|
89 CLOG(( EParse, 3, _L8(" InstNotif<%S>"), &ptr8 )); |
|
90 ptr8.Set( aData.NextUrl() ); |
|
91 CLOG(( EParse, 3, _L8(" NextUrl<%S>"), &ptr8 )); |
|
92 ptr8.Set( aData.NextUrlAtError() ); |
|
93 CLOG(( EParse, 3, _L8(" NextUrlAtErr<%S>"), &ptr8 )); |
|
94 ptr8.Set( aData.InfoUrl() ); |
|
95 CLOG(( EParse, 3, _L8(" InfoUrl<%S>"), &ptr8 )); |
|
96 ptr16.Set( aData.Price() ); |
|
97 CLOG(( EParse, 3, _L(" Price<%S>"), &ptr16 )); |
|
98 ptr8.Set( aData.Icon() ); |
|
99 CLOG(( EParse, 3, _L8(" Icon<%S>"), &ptr8 )); |
|
100 #endif /* def __TEST_COD_LOG */ |
|
101 |
|
102 // NULL data for clarity. These are never used later, but don't keep |
|
103 // pointers to objects which are out of reach. |
|
104 iBuf = NULL; |
|
105 iData = NULL; |
|
106 iCurP = NULL; |
|
107 iEndP = NULL; |
|
108 User::LeaveIfError( iError ); |
|
109 CLOG(( EParse, 2, _L("<- TCodParser::ParseL") )); |
|
110 } |
|
111 |
|
112 // --------------------------------------------------------- |
|
113 // TCodParser::AttrLineL() |
|
114 // --------------------------------------------------------- |
|
115 // |
|
116 TBool TCodParser::AttrLineL() |
|
117 { |
|
118 SkipWhiteSpace(); // Skip lines which contain only WS and LF at the end. |
|
119 while ( IsEndOfLine() ) |
|
120 { |
|
121 NextLine(); |
|
122 SkipWhiteSpace(); |
|
123 } |
|
124 TBool ok( ETrue ); |
|
125 if ( iCurP < iEndP ) |
|
126 { |
|
127 // Still has something to read. |
|
128 switch( AttrName() ) |
|
129 { |
|
130 case ECodName: |
|
131 { |
|
132 if ( Colon() ) |
|
133 { |
|
134 ok = iData->SetNameL( AttrValue() ); |
|
135 EndOfLine(); |
|
136 } |
|
137 break; |
|
138 } |
|
139 |
|
140 case ECodVendor: |
|
141 { |
|
142 if ( Colon() ) |
|
143 { |
|
144 ok = iData->SetVendorL( AttrValue() ); |
|
145 EndOfLine(); |
|
146 } |
|
147 break; |
|
148 } |
|
149 |
|
150 case ECodDescription: |
|
151 { |
|
152 if ( Colon() ) |
|
153 { |
|
154 ok = iData->SetDescriptionL( AttrValue() ); |
|
155 EndOfLine(); |
|
156 } |
|
157 break; |
|
158 } |
|
159 |
|
160 case ECodSize: |
|
161 { |
|
162 if ( Colon() ) |
|
163 { |
|
164 // Parse as TUint - negative not allowed. |
|
165 TUint size; |
|
166 TLex lex( AttrValue() ); |
|
167 if ( !lex.Val( size ) ) |
|
168 { |
|
169 iData->SetSize( size ); |
|
170 } |
|
171 else |
|
172 { |
|
173 ok = EFalse; |
|
174 } |
|
175 EndOfLine(); |
|
176 } |
|
177 break; |
|
178 } |
|
179 |
|
180 case ECodInstallNotify: |
|
181 { |
|
182 if ( Colon() ) |
|
183 { |
|
184 ok = iData->SetInstallNotifyL( AttrValue() ); |
|
185 EndOfLine(); |
|
186 } |
|
187 break; |
|
188 } |
|
189 |
|
190 case ECodNextUrl: |
|
191 { |
|
192 if ( Colon() ) |
|
193 { |
|
194 ok = iData->SetNextUrlL( AttrValue() ); |
|
195 EndOfLine(); |
|
196 } |
|
197 break; |
|
198 } |
|
199 |
|
200 case ECodNextUrlAtError: |
|
201 { |
|
202 if ( Colon() ) |
|
203 { |
|
204 ok = iData->SetNextUrlAtErrorL( AttrValue() ); |
|
205 EndOfLine(); |
|
206 } |
|
207 break; |
|
208 } |
|
209 |
|
210 case ECodInfoUrl: |
|
211 { |
|
212 if ( Colon() ) |
|
213 { |
|
214 ok = iData->SetInfoUrlL( AttrValue() ); |
|
215 EndOfLine(); |
|
216 } |
|
217 break; |
|
218 } |
|
219 |
|
220 case ECodPrice: |
|
221 { |
|
222 if ( Colon() ) |
|
223 { |
|
224 ok = iData->SetPriceL( AttrValue() ); |
|
225 EndOfLine(); |
|
226 } |
|
227 break; |
|
228 } |
|
229 |
|
230 case ECodIcon: |
|
231 { |
|
232 if ( Colon() ) |
|
233 { |
|
234 ok = iData->SetIconL( AttrValue() ); |
|
235 EndOfLine(); |
|
236 } |
|
237 break; |
|
238 } |
|
239 |
|
240 case ECodUnknownAttr: |
|
241 { |
|
242 // Name unknown; check colon anyway (syntax check). |
|
243 ok = Colon(); |
|
244 // Rest of the line goes unchecked. |
|
245 break; |
|
246 } |
|
247 |
|
248 default: |
|
249 { |
|
250 // Unexpected value. |
|
251 CodPanic( ECodInternal ); |
|
252 } |
|
253 |
|
254 } |
|
255 if ( !ok ) |
|
256 { |
|
257 Error( KErrCodInvalidDescriptor ); |
|
258 } |
|
259 NextLine(); // Step past LF. |
|
260 return ETrue; // More lines to go. |
|
261 } |
|
262 else |
|
263 { |
|
264 // EOF reached; done. |
|
265 // Note: not expecting EOF in any other place than here (well-formed |
|
266 // COD has complete attrlines. If EOF is found some other place, it |
|
267 // is a syntax error. |
|
268 return EFalse; |
|
269 } |
|
270 } |
|
271 |
|
272 // --------------------------------------------------------- |
|
273 // TCodParser::AttrName() |
|
274 // --------------------------------------------------------- |
|
275 // |
|
276 |
|
277 TCodParser::TCodAttr TCodParser::AttrName() |
|
278 { |
|
279 TCodAttr attr( ECodUnknownAttr ); |
|
280 |
|
281 const TText* start = iCurP; |
|
282 while |
|
283 ( |
|
284 iCurP < iEndP && |
|
285 !IsControl() && |
|
286 !IsSeparator() && |
|
287 *iCurP != KCodCarriageRet && |
|
288 *iCurP != KCodLineFeed |
|
289 ) |
|
290 { |
|
291 iCurP++; |
|
292 } |
|
293 |
|
294 TPtrC token( start, iCurP - start ); |
|
295 if ( !token.Length() ) |
|
296 { |
|
297 Error( KErrCodInvalidDescriptor ); |
|
298 } |
|
299 else if ( !token.Compare( KCodName ) ) |
|
300 { |
|
301 attr = ECodName; |
|
302 } |
|
303 else if ( !token.Compare( KCodVendor ) ) |
|
304 { |
|
305 attr = ECodVendor; |
|
306 } |
|
307 else if ( !token.Compare( KCodDescription ) ) |
|
308 { |
|
309 attr = ECodDescription; |
|
310 } |
|
311 else if ( !token.Compare( KCodUrl ) ) |
|
312 { |
|
313 attr = ECodUrl; |
|
314 } |
|
315 else if ( !token.Compare( KCodSize ) ) |
|
316 { |
|
317 attr = ECodSize; |
|
318 } |
|
319 else if ( !token.Compare( KCodType ) ) |
|
320 { |
|
321 attr = ECodType; |
|
322 } |
|
323 else if ( !token.Compare( KCodInstallNotify ) ) |
|
324 { |
|
325 attr = ECodInstallNotify; |
|
326 } |
|
327 else if ( !token.Compare( KCodNextUrl ) ) |
|
328 { |
|
329 attr = ECodNextUrl; |
|
330 } |
|
331 else if ( !token.Compare( KCodNextUrlAtError ) ) |
|
332 { |
|
333 attr = ECodNextUrlAtError; |
|
334 } |
|
335 else if ( !token.Compare( KCodInfoUrl ) ) |
|
336 { |
|
337 attr = ECodInfoUrl; |
|
338 } |
|
339 else if ( !token.Compare( KCodPrice ) ) |
|
340 { |
|
341 attr = ECodPrice; |
|
342 } |
|
343 else if ( !token.Compare( KCodIcon ) ) |
|
344 { |
|
345 attr = ECodIcon; |
|
346 } |
|
347 |
|
348 CLOG(( EParse, 4, _L("TCodParser::AttrName token<%S> attr(%d)"), \ |
|
349 &token, attr )); |
|
350 return attr; |
|
351 } |
|
352 |
|
353 // --------------------------------------------------------- |
|
354 // TCodParser::AttrValue() |
|
355 // --------------------------------------------------------- |
|
356 // |
|
357 TPtrC TCodParser::AttrValue() |
|
358 { |
|
359 const TText* start = iCurP; |
|
360 const TText* trailingWs = NULL; |
|
361 while ( iCurP < iEndP && (IsValueChar() || IsWhiteSpace()) ) |
|
362 { |
|
363 if ( IsWhiteSpace() && !trailingWs ) |
|
364 { |
|
365 // Whitespace starts here; may be trailing WS. |
|
366 trailingWs = iCurP; |
|
367 } |
|
368 else if ( IsValueChar() ) |
|
369 { |
|
370 // Possible previous WS is not trailing: value chars follow. |
|
371 trailingWs = NULL; |
|
372 } |
|
373 iCurP++; |
|
374 } |
|
375 if ( trailingWs ) |
|
376 { |
|
377 // There was trailing WS. Back up to that position. |
|
378 iCurP = trailingWs; |
|
379 // Trailing WS should be trailing, not leading. This method expects |
|
380 // to be called with WS skipped first! |
|
381 __ASSERT_DEBUG( trailingWs > start, CodPanic( ECodInternal ) ); |
|
382 } |
|
383 TPtrC token( start, iCurP - start ); |
|
384 CLOG(( EParse, 4, _L("TCodParser::AttrValue token<%S>"), &token )); |
|
385 return token; |
|
386 } |
|
387 |
|
388 // --------------------------------------------------------- |
|
389 // TCodParser::SkipWhiteSpace() |
|
390 // --------------------------------------------------------- |
|
391 // |
|
392 void TCodParser::SkipWhiteSpace() |
|
393 { |
|
394 while ( iCurP < iEndP && IsWhiteSpace() ) |
|
395 { |
|
396 iCurP++; |
|
397 } |
|
398 } |
|
399 |
|
400 // --------------------------------------------------------- |
|
401 // TCodParser::NextLine() |
|
402 // --------------------------------------------------------- |
|
403 // |
|
404 void TCodParser::NextLine() |
|
405 { |
|
406 while ( iCurP < iEndP && *iCurP != KCodLineFeed ) |
|
407 { |
|
408 iCurP++; |
|
409 } |
|
410 if ( iCurP < iEndP ) // skip last LF. |
|
411 { |
|
412 iCurP++; |
|
413 } |
|
414 } |
|
415 |
|
416 // --------------------------------------------------------- |
|
417 // TCodParser::EndOfLine() |
|
418 // --------------------------------------------------------- |
|
419 // |
|
420 void TCodParser::EndOfLine() |
|
421 { |
|
422 while ( iCurP < iEndP ) |
|
423 { |
|
424 if ( *iCurP == KCodLineFeed ) |
|
425 { |
|
426 // LF found -> done. This is the lookahead. |
|
427 break; |
|
428 } |
|
429 else if ( *iCurP == KCodCarriageRet ) |
|
430 { |
|
431 // CR found -> may be CR LF (that's OK) or CR alone (error). |
|
432 if ( iCurP + 1 < iEndP && *(iCurP + 1) == KCodLineFeed ) |
|
433 { |
|
434 // CR LF found-> done. Lookahead is the LF. |
|
435 iCurP ++; |
|
436 break; |
|
437 } |
|
438 // CR without LF is unexpected. |
|
439 Error( KErrCodInvalidDescriptor ); |
|
440 } |
|
441 if ( IsValueChar() || IsControl() ) |
|
442 { |
|
443 // Valuechar or CTL unexpected. |
|
444 Error( KErrCodInvalidDescriptor ); |
|
445 } |
|
446 iCurP++; |
|
447 } |
|
448 } |
|
449 |
|
450 // --------------------------------------------------------- |
|
451 // TCodParser::Colon() |
|
452 // --------------------------------------------------------- |
|
453 // |
|
454 TBool TCodParser::Colon() |
|
455 { |
|
456 TBool colon( EFalse ); |
|
457 SkipWhiteSpace(); |
|
458 if ( iCurP < iEndP && *iCurP == KCodColon ) |
|
459 { |
|
460 // OK it's a colon. |
|
461 colon = ETrue; |
|
462 iCurP++; |
|
463 } |
|
464 else |
|
465 { |
|
466 // Expected a colon. |
|
467 Error( KErrCodInvalidDescriptor ); |
|
468 } |
|
469 SkipWhiteSpace(); |
|
470 return colon; |
|
471 } |
|
472 |
|
473 // --------------------------------------------------------- |
|
474 // TCodParser::IsValueChar() |
|
475 // --------------------------------------------------------- |
|
476 // |
|
477 TBool TCodParser::IsValueChar() const |
|
478 { |
|
479 __ASSERT_DEBUG( iCurP < iEndP, CodPanic( ECodBufferOverread ) ); |
|
480 return ( !(IsControl() || IsWhiteSpace()) ); |
|
481 } |
|
482 |
|
483 // --------------------------------------------------------- |
|
484 // TCodParser::IsControl() |
|
485 // --------------------------------------------------------- |
|
486 // |
|
487 TBool TCodParser::IsControl() const |
|
488 { |
|
489 __ASSERT_DEBUG( iCurP < iEndP, CodPanic( ECodBufferOverread ) ); |
|
490 return ( (*iCurP <= KCodLowControl) || (*iCurP == KCodUpControl) ); |
|
491 } |
|
492 |
|
493 // --------------------------------------------------------- |
|
494 // TCodParser::IsWhiteSpace() |
|
495 // --------------------------------------------------------- |
|
496 // |
|
497 TBool TCodParser::IsWhiteSpace() const |
|
498 { |
|
499 __ASSERT_DEBUG( iCurP < iEndP, CodPanic( ECodBufferOverread ) ); |
|
500 return ( (*iCurP == KCodSpace) || (*iCurP == KCodHorizTab) ); |
|
501 } |
|
502 |
|
503 // --------------------------------------------------------- |
|
504 // TCodParser::IsSeparator() |
|
505 // --------------------------------------------------------- |
|
506 // |
|
507 TBool TCodParser::IsSeparator() const |
|
508 { |
|
509 __ASSERT_DEBUG( iCurP < iEndP, CodPanic( ECodBufferOverread ) ); |
|
510 return |
|
511 ( |
|
512 IsWhiteSpace() || |
|
513 *iCurP == '(' || |
|
514 *iCurP == ')' || |
|
515 *iCurP == '<' || |
|
516 *iCurP == '>' || |
|
517 *iCurP == '@' || |
|
518 *iCurP == ',' || |
|
519 *iCurP == ';' || |
|
520 *iCurP == ':' || |
|
521 *iCurP == '\'' || |
|
522 *iCurP == '\"' || |
|
523 *iCurP == '/' || |
|
524 *iCurP == '[' || |
|
525 *iCurP == ']' || |
|
526 *iCurP == '?' || |
|
527 *iCurP == '=' || |
|
528 *iCurP == '{' || |
|
529 *iCurP == '}' |
|
530 ); |
|
531 } |
|
532 |
|
533 // --------------------------------------------------------- |
|
534 // TCodParser::IsEndOfLine() |
|
535 // --------------------------------------------------------- |
|
536 // |
|
537 TBool TCodParser::IsEndOfLine() const |
|
538 { |
|
539 const TText* CurP = iCurP; |
|
540 if ( CurP < iEndP && *CurP == KCodCarriageRet ) |
|
541 { |
|
542 CurP++; |
|
543 } |
|
544 if ( CurP < iEndP && *CurP == KCodLineFeed ) |
|
545 { |
|
546 return ETrue; |
|
547 } |
|
548 return EFalse; |
|
549 } |