|
1 /* |
|
2 * Copyright (c) 2005-2008 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 "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: This file implements class CIpsPlgTextSearcher. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 |
|
21 #include "emailtrace.h" |
|
22 #include "ipsplgheaders.h" |
|
23 |
|
24 const TUint KKeywordsArrayGranularity = 8; |
|
25 const TInt KUnicodeConversionBufferSize = 100; |
|
26 |
|
27 // ================= MEMBER FUNCTIONS ==================== |
|
28 |
|
29 // ---------------------------------------------------------------------------- |
|
30 // CIpsPlgTextSearcher::NewL() |
|
31 // Symbian OS 2 phased constructor. |
|
32 // ---------------------------------------------------------------------------- |
|
33 // |
|
34 CIpsPlgTextSearcher* CIpsPlgTextSearcher::NewL( |
|
35 MIpsPlgTextSearcherObserver& aObserver ) |
|
36 { |
|
37 FUNC_LOG; |
|
38 CIpsPlgTextSearcher* self = CIpsPlgTextSearcher::NewLC( aObserver ); |
|
39 CleanupStack::Pop( self ); |
|
40 return self; |
|
41 } |
|
42 |
|
43 // ---------------------------------------------------------------------------- |
|
44 // CIpsPlgTextSearcher::NewLC() |
|
45 // Symbian OS 2 phased constructor. |
|
46 // ---------------------------------------------------------------------------- |
|
47 // |
|
48 CIpsPlgTextSearcher* CIpsPlgTextSearcher::NewLC( |
|
49 MIpsPlgTextSearcherObserver& aObserver ) |
|
50 { |
|
51 FUNC_LOG; |
|
52 CIpsPlgTextSearcher* self = |
|
53 new ( ELeave ) CIpsPlgTextSearcher( aObserver ); |
|
54 CleanupStack::PushL( self ); |
|
55 self->ConstructL(); |
|
56 return self; |
|
57 } |
|
58 |
|
59 // ---------------------------------------------------------------------------- |
|
60 // CIpsPlgTextSearcher::CIpsPlgTextSearcher() |
|
61 // Performs the first phase of two phase construction. |
|
62 // ---------------------------------------------------------------------------- |
|
63 // |
|
64 CIpsPlgTextSearcher::CIpsPlgTextSearcher( |
|
65 MIpsPlgTextSearcherObserver& aObserver ) |
|
66 : iObserver( aObserver ) |
|
67 { |
|
68 FUNC_LOG; |
|
69 } |
|
70 |
|
71 // ---------------------------------------------------------------------------- |
|
72 // CIpsPlgTextSearcher::ConstructL() |
|
73 // Performs the second phase construction. |
|
74 // ---------------------------------------------------------------------------- |
|
75 // |
|
76 void CIpsPlgTextSearcher::ConstructL() |
|
77 { |
|
78 FUNC_LOG; |
|
79 iSearchKeywords8 = |
|
80 new ( ELeave ) CDesC8ArrayFlat( KKeywordsArrayGranularity ); |
|
81 User::LeaveIfError ( iRFs.Connect() ); |
|
82 } |
|
83 |
|
84 // ---------------------------------------------------------------------------- |
|
85 // CIpsPlgTextSearcher::~CIpsPlgTextSearcher() |
|
86 // Destructor |
|
87 // ---------------------------------------------------------------------------- |
|
88 // |
|
89 CIpsPlgTextSearcher::~CIpsPlgTextSearcher() |
|
90 { |
|
91 FUNC_LOG; |
|
92 iKeywordSearchStatusArray.Close(); |
|
93 |
|
94 if( iSearchKeywords8 ) |
|
95 { |
|
96 iSearchKeywords8->Reset(); |
|
97 delete iSearchKeywords8; |
|
98 } |
|
99 |
|
100 iRFs.Close(); |
|
101 } |
|
102 |
|
103 // ---------------------------------------------------------------------------- |
|
104 // CIpsPlgTextSearcher::SetParametersL() |
|
105 // Sets the search parameters for the search. |
|
106 // ---------------------------------------------------------------------------- |
|
107 // |
|
108 void CIpsPlgTextSearcher::SetParametersL( |
|
109 const CDesCArray& aKeywords, |
|
110 TIpsPlgCriteriaOperation aOperator, |
|
111 TBool aCaseSensitive, |
|
112 TInt aSearchResultRecommendedSnippetLength ) |
|
113 { |
|
114 FUNC_LOG; |
|
115 iHaveParameters = ETrue; |
|
116 |
|
117 iSearchKeywords = &aKeywords; |
|
118 |
|
119 iOperator = aOperator; |
|
120 iCaseSensitive = aCaseSensitive; |
|
121 iSearchResultRecommendedSnippetLength = |
|
122 aSearchResultRecommendedSnippetLength; |
|
123 |
|
124 iKeywordSearchStatusArray.Reset(); |
|
125 TInt count( aKeywords.Count() ); |
|
126 for ( TInt i(0); i < count; i++ ) |
|
127 { |
|
128 TIpsPlgKeywordSearchStatus status; |
|
129 status.iFound = EFalse; |
|
130 status.iFoundAsNthWord = KErrNotFound; |
|
131 |
|
132 iKeywordSearchStatusArray.AppendL( status ); |
|
133 } |
|
134 } |
|
135 |
|
136 // ---------------------------------------------------------------------------- |
|
137 // CIpsPlgTextSearcher::Cleanup() |
|
138 // Cleans up internal data. Must be called before each new search is started. |
|
139 // Does not clean up the parameters set via SetParametersL. |
|
140 // ---------------------------------------------------------------------------- |
|
141 // |
|
142 void CIpsPlgTextSearcher::Cleanup() |
|
143 { |
|
144 FUNC_LOG; |
|
145 TInt count( iKeywordSearchStatusArray.Count() ); |
|
146 for ( TInt i(0); i < count; i++ ) |
|
147 { |
|
148 iKeywordSearchStatusArray[i].iFound = EFalse; |
|
149 iKeywordSearchStatusArray[i].iFoundAsNthWord = KErrNotFound; |
|
150 } |
|
151 } |
|
152 |
|
153 // ---------------------------------------------------------------------------- |
|
154 // CIpsPlgTextSearcher::SearchL() |
|
155 // ---------------------------------------------------------------------------- |
|
156 // |
|
157 TBool CIpsPlgTextSearcher::SearchL( const TDesC& aToBeSearchedDes ) |
|
158 { |
|
159 FUNC_LOG; |
|
160 __ASSERT_DEBUG( iHaveParameters, |
|
161 User::Panic( KIpsPlgPanicCategory, EIpsPlgNoParameters ) ); |
|
162 |
|
163 // when aToBeSearchedDes has no data, it can match * |
|
164 if( !aToBeSearchedDes.Length() ) |
|
165 { |
|
166 return EFalse; |
|
167 } |
|
168 |
|
169 iFirstMatchKeywordCharPos = KErrNotFound; |
|
170 |
|
171 TBool found( DoStringCompareWithKeywordsL( aToBeSearchedDes, *iSearchKeywords, |
|
172 iKeywordSearchStatusArray, iOperator, iCaseSensitive ) ); |
|
173 |
|
174 if ( found ) |
|
175 { |
|
176 // Parameters are not used in function |
|
177 iObserver.HitL( KNullDesC, KErrNone, EFalse, EFalse ); |
|
178 } |
|
179 return found; |
|
180 } |
|
181 |
|
182 // ---------------------------------------------------------------------------- |
|
183 // CIpsPlgTextSearcher::SearchL() |
|
184 // ---------------------------------------------------------------------------- |
|
185 // |
|
186 TBool CIpsPlgTextSearcher::SearchL( const TDesC8& aToBeSearchedDes ) |
|
187 { |
|
188 FUNC_LOG; |
|
189 __ASSERT_DEBUG( iHaveParameters, |
|
190 User::Panic( KIpsPlgPanicCategory, EIpsPlgNoParameters ) ); |
|
191 |
|
192 // when aToBeSearchedDes has no data, it can match * |
|
193 if( !aToBeSearchedDes.Length() ) |
|
194 { |
|
195 return EFalse; |
|
196 } |
|
197 |
|
198 // Create 8 bit versions from the keywords for better efficiency |
|
199 iSearchKeywords8->Reset(); |
|
200 TInt count( iSearchKeywords->Count() ); |
|
201 for ( TInt i(0); i < count; i++ ) |
|
202 { |
|
203 HBufC8* keyword8Bit = ConvertFromUnicodeL( iRFs, |
|
204 iSearchKeywords->MdcaPoint( i ), |
|
205 KCharacterSetIdentifierUtf8 ); |
|
206 CleanupStack::PushL( keyword8Bit ); |
|
207 iSearchKeywords8->AppendL( *keyword8Bit ); |
|
208 CleanupStack::PopAndDestroy( keyword8Bit ); |
|
209 } |
|
210 |
|
211 iFirstMatchKeywordCharPos = KErrNotFound; |
|
212 |
|
213 TBool found( DoStringCompareWithKeywordsL( aToBeSearchedDes, *iSearchKeywords8, |
|
214 iKeywordSearchStatusArray, iOperator, iCaseSensitive ) ); |
|
215 |
|
216 if ( found ) |
|
217 { |
|
218 // Parameters are not used in function |
|
219 iObserver.HitL( KNullDesC, KErrNone, EFalse, EFalse ); |
|
220 } |
|
221 return found; |
|
222 } |
|
223 |
|
224 // ---------------------------------------------------------------------------- |
|
225 // CIpsPlgTextSearcher::DoStringCompareWithKeywords() |
|
226 // ---------------------------------------------------------------------------- |
|
227 // |
|
228 TBool CIpsPlgTextSearcher::DoStringCompareWithKeywordsL( |
|
229 const TDesC& aToBeSearchedDes, |
|
230 const CDesCArray& aKeywords, |
|
231 RArray<TIpsPlgKeywordSearchStatus>& aKeywordSearchStatusArray, |
|
232 TIpsPlgCriteriaOperation aOperator, |
|
233 TBool aCaseSensitive ) |
|
234 { |
|
235 FUNC_LOG; |
|
236 // Compare the string will all the keywords |
|
237 TInt count( aKeywords.Count() ); |
|
238 if ( count != aKeywordSearchStatusArray.Count() ) |
|
239 { |
|
240 User::Leave( KErrArgument ); |
|
241 } |
|
242 for ( TInt i(0); i < count; i++ ) |
|
243 { |
|
244 if ( !aKeywordSearchStatusArray[i].iFound ) // keyword not yet found |
|
245 { |
|
246 TInt match; |
|
247 if ( aCaseSensitive ) |
|
248 { |
|
249 match = aToBeSearchedDes.Match( aKeywords[i] ); |
|
250 } |
|
251 else |
|
252 { |
|
253 match = aToBeSearchedDes.MatchC( aKeywords[i] ); |
|
254 } |
|
255 |
|
256 // KErrNotFound indicates that no match was found |
|
257 if ( match != KErrNotFound ) |
|
258 { |
|
259 aKeywordSearchStatusArray[i].iFound = ETrue; |
|
260 // The 1st found keyword will be also the snippet |
|
261 if ( iFirstMatchKeywordCharPos == KErrNotFound ) |
|
262 { |
|
263 |
|
264 if ( match == aToBeSearchedDes.Length() ) |
|
265 { |
|
266 iFirstMatchKeywordCharPos = 0; |
|
267 } |
|
268 else |
|
269 { |
|
270 iFirstMatchKeywordCharPos = match; |
|
271 } |
|
272 |
|
273 } |
|
274 |
|
275 if ( aOperator == EIpsPlgCriteriaOperationOR ) |
|
276 { |
|
277 // As soon as one keyword is found, the OR search can stop |
|
278 return ETrue; |
|
279 } |
|
280 } |
|
281 } |
|
282 } |
|
283 |
|
284 // Check if there is still need to continue searching. |
|
285 TBool keywordsFound; |
|
286 switch ( aOperator ) |
|
287 { |
|
288 case EIpsPlgCriteriaOperationAND: |
|
289 keywordsFound = ETrue; |
|
290 break; |
|
291 |
|
292 case EIpsPlgCriteriaOperationOR: |
|
293 keywordsFound = EFalse; |
|
294 break; |
|
295 |
|
296 default: |
|
297 keywordsFound = ETrue; // to avoid warning |
|
298 break; |
|
299 } |
|
300 |
|
301 // For AND search, all keywords must be found, thus if 1 is not found -> |
|
302 // No hit |
|
303 if( aOperator == EIpsPlgCriteriaOperationAND ) |
|
304 { |
|
305 for ( TInt j(0); j < count; j++ ) |
|
306 { |
|
307 if ( !aKeywordSearchStatusArray[j].iFound ) |
|
308 { |
|
309 return EFalse; |
|
310 } |
|
311 } |
|
312 } |
|
313 return keywordsFound; |
|
314 } |
|
315 |
|
316 // ---------------------------------------------------------------------------- |
|
317 // CIpsPlgTextSearcher::DoStringCompareWithKeywordsL() |
|
318 // ---------------------------------------------------------------------------- |
|
319 // |
|
320 TBool CIpsPlgTextSearcher::DoStringCompareWithKeywordsL( |
|
321 const TDesC8& aToBeSearchedDes, |
|
322 const CDesC8Array& aKeywords, |
|
323 RArray<TIpsPlgKeywordSearchStatus>& aKeywordSearchStatusArray, |
|
324 TIpsPlgCriteriaOperation aOperator, |
|
325 TBool aCaseSensitive ) |
|
326 { |
|
327 FUNC_LOG; |
|
328 TInt count( aKeywords.Count() ); |
|
329 if ( count != aKeywordSearchStatusArray.Count() ) |
|
330 { |
|
331 User::Leave( KErrArgument ); |
|
332 } |
|
333 // Compare the string will all the keywords |
|
334 for ( TInt i=0; i<aKeywords.Count(); i++ ) |
|
335 { |
|
336 if ( !aKeywordSearchStatusArray[i].iFound ) // keyword not yet found |
|
337 { |
|
338 TInt match; |
|
339 if ( aCaseSensitive ) |
|
340 { |
|
341 match = aToBeSearchedDes.Match( aKeywords[i] ); |
|
342 } |
|
343 else |
|
344 { |
|
345 match = aToBeSearchedDes.MatchC( aKeywords[i] ); |
|
346 } |
|
347 |
|
348 // KErrNotFound indicates that no match was found |
|
349 if ( match != KErrNotFound ) |
|
350 { |
|
351 aKeywordSearchStatusArray[i].iFound = ETrue; |
|
352 // The 1st found keyword will be also the snippet |
|
353 if ( iFirstMatchKeywordCharPos == KErrNotFound ) |
|
354 { |
|
355 iFirstMatchKeywordCharPos = match; |
|
356 } |
|
357 |
|
358 if ( aOperator == EIpsPlgCriteriaOperationOR ) |
|
359 { |
|
360 // As soon as one keyword is found, the OR search can stop |
|
361 return ETrue; |
|
362 } |
|
363 } |
|
364 } |
|
365 } |
|
366 |
|
367 // Check if there is still need to continue searching. |
|
368 TBool keywordsFound; |
|
369 switch ( aOperator ) |
|
370 { |
|
371 case EIpsPlgCriteriaOperationAND: |
|
372 keywordsFound = ETrue; |
|
373 break; |
|
374 |
|
375 case EIpsPlgCriteriaOperationOR: |
|
376 keywordsFound = EFalse; |
|
377 break; |
|
378 |
|
379 default: |
|
380 keywordsFound = ETrue; // to avoid warning |
|
381 break; |
|
382 } |
|
383 |
|
384 // For AND search, all keywords must be found, thus if 1 is not found -> |
|
385 // No hit |
|
386 if( aOperator == EIpsPlgCriteriaOperationAND ) |
|
387 { |
|
388 for ( TInt j(0); j < count; j++ ) |
|
389 { |
|
390 if ( !aKeywordSearchStatusArray[j].iFound ) |
|
391 { |
|
392 return EFalse; |
|
393 } |
|
394 } |
|
395 } |
|
396 return keywordsFound; |
|
397 } |
|
398 |
|
399 // ---------------------------------------------------------------------------- |
|
400 // CIpsPlgTextSearcher::CreateSnippetLC() |
|
401 // Creates the snippet from the 1st found keyword hit. 16 bit version. |
|
402 // ---------------------------------------------------------------------------- |
|
403 // |
|
404 HBufC* CIpsPlgTextSearcher::CreateSnippetLC( |
|
405 const TDesC& aToBeSearchedDes, |
|
406 TInt& aSnippetCharPos, |
|
407 TBool& aStartIncomplete, |
|
408 TBool& aEndIncomplete ) const |
|
409 { |
|
410 FUNC_LOG; |
|
411 TInt halfSnippetLen ( iSearchResultRecommendedSnippetLength / 2 ); |
|
412 |
|
413 TInt firstChar ( iFirstMatchKeywordCharPos - halfSnippetLen ); |
|
414 // if firstChar is negative, then we can give more space to lastChar |
|
415 TInt lastChar ( |
|
416 iFirstMatchKeywordCharPos + halfSnippetLen - Min( firstChar, 0) ); |
|
417 |
|
418 TInt searchDesLastChar ( aToBeSearchedDes.Length() ); |
|
419 |
|
420 // if lastChar is go out of the total length, put the firstChar head toward |
|
421 firstChar = |
|
422 Max( 0, firstChar - Max( 0, ( lastChar - searchDesLastChar ) ) ) ; |
|
423 |
|
424 aSnippetCharPos = halfSnippetLen + ( lastChar - searchDesLastChar ); |
|
425 |
|
426 aStartIncomplete = ETrue; |
|
427 if ( firstChar <= 0 ) |
|
428 { |
|
429 firstChar = 0; |
|
430 aStartIncomplete = EFalse; |
|
431 aSnippetCharPos = iFirstMatchKeywordCharPos; |
|
432 } |
|
433 |
|
434 aEndIncomplete = ETrue; |
|
435 if ( lastChar >= searchDesLastChar ) |
|
436 { |
|
437 lastChar = searchDesLastChar; |
|
438 aEndIncomplete = EFalse; |
|
439 } |
|
440 |
|
441 return aToBeSearchedDes.Mid( |
|
442 firstChar, |
|
443 Min( lastChar - firstChar, searchDesLastChar - firstChar ) ).AllocLC(); |
|
444 } |
|
445 |
|
446 // ---------------------------------------------------------------------------- |
|
447 // CIpsPlgTextSearcher::CreateSnippetLC() |
|
448 // Creates the snippet from the 1st found keyword hit. 8 bit version. |
|
449 // ---------------------------------------------------------------------------- |
|
450 // |
|
451 HBufC* CIpsPlgTextSearcher::CreateSnippetLC( |
|
452 const TDesC8& aToBeSearchedDes, |
|
453 TInt& aSnippetCharPos, |
|
454 TBool& aStartIncomplete, |
|
455 TBool& aEndIncomplete ) |
|
456 { |
|
457 FUNC_LOG; |
|
458 TInt halfSnippetLen ( iSearchResultRecommendedSnippetLength / 2 ); |
|
459 |
|
460 TInt firstChar ( iFirstMatchKeywordCharPos - halfSnippetLen ); |
|
461 TInt lastChar ( |
|
462 iFirstMatchKeywordCharPos + halfSnippetLen - Min( firstChar, 0) ); |
|
463 |
|
464 TInt searchDesLastChar ( aToBeSearchedDes.Length() ); |
|
465 |
|
466 firstChar = |
|
467 Max( 0, firstChar - Max( 0, ( lastChar - searchDesLastChar ) ) ) ; |
|
468 |
|
469 aSnippetCharPos = halfSnippetLen + ( lastChar - searchDesLastChar ); |
|
470 |
|
471 aStartIncomplete = ETrue; |
|
472 if ( firstChar <= 0 ) |
|
473 { |
|
474 firstChar = 0; |
|
475 aStartIncomplete = EFalse; |
|
476 aSnippetCharPos = iFirstMatchKeywordCharPos; |
|
477 } |
|
478 |
|
479 aEndIncomplete = ETrue; |
|
480 if ( lastChar >= searchDesLastChar ) |
|
481 { |
|
482 lastChar = searchDesLastChar; |
|
483 aEndIncomplete = EFalse; |
|
484 } |
|
485 |
|
486 HBufC8* snippet8 = aToBeSearchedDes.Mid( firstChar, |
|
487 Min( lastChar - firstChar, searchDesLastChar - firstChar ) ).AllocLC(); |
|
488 HBufC* snippet= ConvertToUnicodeL( iRFs, *snippet8, |
|
489 KCharacterSetIdentifierUtf8 ); |
|
490 CleanupStack::PopAndDestroy( snippet8 ); |
|
491 CleanupStack::PushL( snippet ); |
|
492 return snippet; |
|
493 } |
|
494 |
|
495 // ---------------------------------------------------------------------------- |
|
496 // CIpsPlgTextSearcher::ConvertFromUnicodeL() |
|
497 // Makes a conversion from unicode |
|
498 // ---------------------------------------------------------------------------- |
|
499 HBufC8* CIpsPlgTextSearcher::ConvertFromUnicodeL( |
|
500 RFs& aFs, |
|
501 const TDesC16& aUnicodeSource, |
|
502 TUint aTargetEncoding ) |
|
503 { |
|
504 FUNC_LOG; |
|
505 CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC(); |
|
506 if ( converter->PrepareToConvertToOrFromL(aTargetEncoding, aFs) |
|
507 != CCnvCharacterSetConverter::EAvailable ) |
|
508 { |
|
509 User::Leave( KErrNotSupported ); |
|
510 } |
|
511 |
|
512 TBuf8<KUnicodeConversionBufferSize> temp8Buffer; |
|
513 HBufC8* target = NULL; |
|
514 TPtrC source16Ptr( aUnicodeSource ); |
|
515 |
|
516 for( ;; ) // conversion loop |
|
517 { |
|
518 TInt state = CCnvCharacterSetConverter::KStateDefault; |
|
519 TInt returnValue = |
|
520 converter->ConvertFromUnicode( temp8Buffer, source16Ptr, state ); |
|
521 if ( returnValue == CCnvCharacterSetConverter::EErrorIllFormedInput ) |
|
522 { |
|
523 User::Leave( KErrCorrupt ); |
|
524 } |
|
525 else |
|
526 { |
|
527 if ( returnValue < 0 ) // future-proof against "TError" expanding |
|
528 { |
|
529 User::Leave( KErrGeneral ); |
|
530 } |
|
531 } |
|
532 |
|
533 if ( !target ) |
|
534 { |
|
535 target = temp8Buffer.AllocLC(); |
|
536 } |
|
537 else |
|
538 { |
|
539 HBufC8* tmp = |
|
540 target->ReAllocL( target->Length() + temp8Buffer.Length() ); |
|
541 CleanupStack::Pop( target ); |
|
542 target = tmp; |
|
543 CleanupStack::PushL( target ); |
|
544 target->Des().Append( temp8Buffer ); |
|
545 } |
|
546 |
|
547 if ( returnValue == 0 ) // All is converted without Errors |
|
548 { |
|
549 break; |
|
550 } |
|
551 |
|
552 // There is "returnValue" bytes not converted yet |
|
553 source16Ptr.Set( source16Ptr.Right( returnValue ) ); |
|
554 } |
|
555 CleanupStack::Pop( target ); // Ownership is transferred |
|
556 CleanupStack::PopAndDestroy( converter ); |
|
557 return target; |
|
558 } |
|
559 |
|
560 // ---------------------------------------------------------------------------- |
|
561 // CIpsPlgTextSearcher::ConvertToUnicodeL() |
|
562 // Makes a conversion into unicode |
|
563 // ---------------------------------------------------------------------------- |
|
564 HBufC16* CIpsPlgTextSearcher::ConvertToUnicodeL( |
|
565 RFs& aFs, |
|
566 const TDesC8& aSource, |
|
567 TUint aSourceEncoding ) |
|
568 { |
|
569 FUNC_LOG; |
|
570 CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC(); |
|
571 if ( converter->PrepareToConvertToOrFromL( aSourceEncoding, aFs ) |
|
572 != CCnvCharacterSetConverter::EAvailable ) |
|
573 { |
|
574 User::Leave( KErrNotSupported ); |
|
575 } |
|
576 |
|
577 TBuf<KUnicodeConversionBufferSize> temp16Buffer; |
|
578 HBufC* unicode = NULL; |
|
579 TPtrC8 source8Ptr( aSource ); |
|
580 |
|
581 for( ;; ) // conversion loop |
|
582 { |
|
583 TInt state = CCnvCharacterSetConverter::KStateDefault; |
|
584 |
|
585 TInt returnValue = |
|
586 converter->ConvertToUnicode( temp16Buffer, source8Ptr, state ); |
|
587 if ( returnValue == CCnvCharacterSetConverter::EErrorIllFormedInput ) |
|
588 { |
|
589 User::Leave( KErrCorrupt ); |
|
590 } |
|
591 else |
|
592 { |
|
593 if ( returnValue < 0 ) // future-proof against "TError" expanding |
|
594 { |
|
595 User::Leave( KErrGeneral ); |
|
596 } |
|
597 } |
|
598 |
|
599 if ( !unicode ) |
|
600 { |
|
601 unicode = temp16Buffer.AllocLC(); |
|
602 } |
|
603 else |
|
604 { |
|
605 HBufC* tmp = |
|
606 unicode->ReAllocL( unicode->Length() + temp16Buffer.Length() ); |
|
607 CleanupStack::Pop( unicode ); |
|
608 unicode = tmp; |
|
609 CleanupStack::PushL( unicode ); |
|
610 unicode->Des().Append( temp16Buffer ); |
|
611 } |
|
612 |
|
613 if ( returnValue == 0 ) // All is converted without Errors |
|
614 { |
|
615 break; |
|
616 } |
|
617 |
|
618 // There is "returnValue" bytes not converted yet |
|
619 source8Ptr.Set( source8Ptr.Right( returnValue ) ); |
|
620 } |
|
621 |
|
622 CleanupStack::Pop( unicode ); // Ownership is transferred |
|
623 CleanupStack::PopAndDestroy( converter ); |
|
624 return unicode; |
|
625 } |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 |
|
631 |