|
1 // descriptorJuggling.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "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 // Accenture - Initial contribution |
|
11 // |
|
12 #include <fshell/ltkutils.h> |
|
13 #include <fshell/descriptorutils.h> |
|
14 |
|
15 #include <u32std.h> |
|
16 const TUint16 KReplacementChar = 0xFFFD; |
|
17 const TUint16 KBom = 0xFEFF; |
|
18 _LIT8(KReplacementCharInUtf8, "\xEF\xBF\xBD"); |
|
19 using namespace LtkUtils; |
|
20 |
|
21 // This class is used to track state between invocations of AppendUtf8L(). |
|
22 namespace LtkUtils |
|
23 { |
|
24 class TUtf8State |
|
25 { |
|
26 public: |
|
27 TUtf8State(); |
|
28 |
|
29 public: |
|
30 TInt iFirstUnconvertedByte; |
|
31 TInt iBytesConsumedSoFar; |
|
32 TUint8 iUnconvertedBytesCount; |
|
33 TUint8 iUnconvertedBytes[3]; // A UTF-8 sequence is a maximum of 4 bytes long so there can only be a max of 3 bytes unconverted |
|
34 }; |
|
35 } // end namespace LtkUtils |
|
36 |
|
37 const TInt KStateCharCount = sizeof(LtkUtils::TUtf8State) / sizeof(TUint16); |
|
38 __ASSERT_COMPILE((sizeof(LtkUtils::TUtf8State) & 3) == 0); |
|
39 __ASSERT_COMPILE(KStateCharCount == 6); // Just checking I've done my maths right, it doesn't particularly have to be this size |
|
40 |
|
41 EXPORT_C TUint LtkUtils::HexLexL(TLex16& aLex) |
|
42 { |
|
43 TUint result; |
|
44 User::LeaveIfError(HexLex(aLex, result)); |
|
45 return result; |
|
46 } |
|
47 |
|
48 EXPORT_C TInt LtkUtils::HexLex(TLex16& aLex, TUint& aResult) |
|
49 { |
|
50 _LIT(KHexPrefix, "0x"); |
|
51 if (aLex.Remainder().Length() > 2) |
|
52 { |
|
53 TLexMark16 mark; |
|
54 aLex.Mark(mark); |
|
55 aLex.Inc(2); |
|
56 TPtrC prefix(aLex.MarkedToken(mark)); |
|
57 if (prefix == KHexPrefix) |
|
58 { |
|
59 TInt err = aLex.Val(aResult, EHex); |
|
60 if (err) aLex.UnGetToMark(mark); // Make sure we leave it at the original position if error |
|
61 return err; |
|
62 } |
|
63 else |
|
64 { |
|
65 aLex.UnGetToMark(mark); |
|
66 } |
|
67 } |
|
68 return aLex.Val(aResult, EDecimal); |
|
69 } |
|
70 |
|
71 EXPORT_C TUint LtkUtils::HexLexL(TLex8& aLex) |
|
72 { |
|
73 TUint result; |
|
74 User::LeaveIfError(HexLex(aLex, result)); |
|
75 return result; |
|
76 } |
|
77 |
|
78 EXPORT_C TInt LtkUtils::HexLex(TLex8& aLex, TUint& aResult) |
|
79 { |
|
80 _LIT8(KHexPrefix, "0x"); |
|
81 if (aLex.Remainder().Length() > 2) |
|
82 { |
|
83 TLexMark8 mark; |
|
84 aLex.Mark(mark); |
|
85 aLex.Inc(2); |
|
86 TPtrC8 prefix(aLex.MarkedToken(mark)); |
|
87 if (prefix == KHexPrefix) |
|
88 { |
|
89 TInt err = aLex.Val(aResult, EHex); |
|
90 if (err) aLex.UnGetToMark(mark); // Make sure we leave it at the original position if error |
|
91 return err; |
|
92 } |
|
93 else |
|
94 { |
|
95 aLex.UnGetToMark(mark); |
|
96 } |
|
97 } |
|
98 return aLex.Val(aResult, EDecimal); |
|
99 } |
|
100 |
|
101 EXPORT_C TInt LtkUtils::ReplaceText(TDes& aDescriptor, const TDesC& aFrom, const TDesC& aTo) |
|
102 { |
|
103 TInt numReplaced = 0; |
|
104 TInt pos = 0; |
|
105 const TInt lenDelta = -aFrom.Length() + aTo.Length(); |
|
106 while (ETrue) |
|
107 { |
|
108 TPtrC des(aDescriptor.Mid(pos)); |
|
109 TInt found = des.Find(aFrom); |
|
110 if (found == KErrNotFound) break; |
|
111 TInt idx = pos + found; |
|
112 if (aDescriptor.Length() + lenDelta > aDescriptor.MaxLength()) return KErrOverflow; |
|
113 aDescriptor.Replace(idx, aFrom.Length(), aTo); |
|
114 pos = idx + aTo.Length(); |
|
115 numReplaced++; |
|
116 } |
|
117 return numReplaced; |
|
118 } |
|
119 |
|
120 void EnsureCapacityL(HBufC*& aBuf, TInt aExtra) |
|
121 { |
|
122 if (aBuf->Length() + aExtra > aBuf->Des().MaxLength()) |
|
123 { |
|
124 aBuf = aBuf->ReAllocL(aBuf->Length() + aExtra); |
|
125 } |
|
126 } |
|
127 |
|
128 EXPORT_C TBool LtkUtils::HasPrefix(const TDesC16& aDes, const TDesC16& aPrefix) |
|
129 { |
|
130 return aDes.Left(aPrefix.Length()) == aPrefix; |
|
131 } |
|
132 |
|
133 EXPORT_C TBool LtkUtils::HasPrefix(const TDesC8& aDes, const TDesC8& aPrefix) |
|
134 { |
|
135 return aDes.Left(aPrefix.Length()) == aPrefix; |
|
136 } |
|
137 |
|
138 #define KB *1024 |
|
139 #define MB *1024*1024 |
|
140 #define GB *1024*1024*1024 |
|
141 |
|
142 EXPORT_C void LtkUtils::FormatSize(TDes16& aDes, TInt64 aSize) |
|
143 { |
|
144 _LIT(KBytes, " B"); |
|
145 _LIT(KKilobytes, " KB"); |
|
146 _LIT(KMegabytes, " MB"); |
|
147 _LIT(KGigabytes, " GB"); |
|
148 |
|
149 const TDesC* suff = &KBytes; |
|
150 TReal n = aSize; |
|
151 TInt factor = 1; |
|
152 |
|
153 TInt64 absSize = aSize; |
|
154 if (absSize < 0) absSize = -absSize; |
|
155 |
|
156 if (absSize >= 1 GB) |
|
157 { |
|
158 suff = &KGigabytes; |
|
159 factor = 1 GB; |
|
160 } |
|
161 else if (absSize >= 1 MB) |
|
162 { |
|
163 suff = &KMegabytes; |
|
164 factor = 1 MB; |
|
165 } |
|
166 else if (absSize >= 1 KB) |
|
167 { |
|
168 suff = &KKilobytes; |
|
169 factor = 1 KB; |
|
170 } |
|
171 |
|
172 n = n / (TReal)factor; |
|
173 TBool wholeNumUnits = (absSize & (factor-1)) == 0; // ie aSize % factor == 0 |
|
174 |
|
175 TRealFormat fmt(aDes.MaxLength(), wholeNumUnits ? 0 : 2); |
|
176 aDes.Num(n, fmt); |
|
177 aDes.Append(*suff); |
|
178 } |
|
179 |
|
180 |
|
181 EXPORT_C void LtkUtils::FormatSize(TDes8& aDes, TInt64 aSize) |
|
182 { |
|
183 TBuf<32> buf; |
|
184 FormatSize(buf, aSize); |
|
185 aDes.Copy(buf); |
|
186 } |
|
187 |
|
188 |
|
189 |
|
190 // RLtkBuf follows |
|
191 |
|
192 inline TDesC16::TDesC16(TInt aType,TInt aLength) |
|
193 :iLength(aLength|(aType<<KShiftDesType16)) |
|
194 {} |
|
195 |
|
196 inline TDes16::TDes16(TInt aType,TInt aLength,TInt aMaxLength) |
|
197 : TDesC16(aType,aLength),iMaxLength(aMaxLength) |
|
198 {} |
|
199 |
|
200 EXPORT_C LtkUtils::RLtkBuf16::RLtkBuf16() |
|
201 : TDes16(EPtr,0,0), iBuf(NULL) |
|
202 { |
|
203 } |
|
204 |
|
205 EXPORT_C LtkUtils::RLtkBuf16::RLtkBuf16(HBufC16* aBuf) |
|
206 { |
|
207 if(aBuf) |
|
208 { |
|
209 //Create EBufCPtr type descriptor that points to aHBuf |
|
210 // I'll take base_e32's word for it that this does the right thing... |
|
211 new(this) TPtr16(aBuf->Des()); |
|
212 } |
|
213 else |
|
214 { |
|
215 //Create zero-length RBuf16. It is EPtr type of descriptor that points to NULL. |
|
216 new(this) RLtkBuf16(); |
|
217 } |
|
218 } |
|
219 |
|
220 EXPORT_C HBufC16* LtkUtils::RLtkBuf16::ToHBuf() |
|
221 { |
|
222 // This transfers ownership |
|
223 HBufC16* result = iBuf; |
|
224 Assign(NULL); |
|
225 return result; |
|
226 } |
|
227 |
|
228 EXPORT_C HBufC16* LtkUtils::RLtkBuf16::GetHBuf() const |
|
229 { |
|
230 // This doesn't transfer ownership |
|
231 return iBuf; |
|
232 } |
|
233 |
|
234 EXPORT_C TInt LtkUtils::RLtkBuf16::ReAlloc(TInt aMaxLength) |
|
235 { |
|
236 if (!aMaxLength) // Reallocation to zero length |
|
237 { |
|
238 Close(); |
|
239 return KErrNone; |
|
240 } |
|
241 |
|
242 if (!iBuf) // Reallocation from zero length |
|
243 return Create(aMaxLength); |
|
244 |
|
245 // Need to maintain the UTF-8 state trickery |
|
246 TUtf8State* oldState = GetUtf8State(); |
|
247 if (oldState) |
|
248 { |
|
249 TUtf8State state = *oldState; |
|
250 HBufC16* newbuf = iBuf->ReAlloc(aMaxLength + KStateCharCount); |
|
251 if (!newbuf) return KErrNoMemory; |
|
252 Assign(newbuf); // This will set iMaxLength |
|
253 iMaxLength = iMaxLength - KStateCharCount; |
|
254 Mem::Copy((TAny*)(Ptr() + MaxLength()), &state, sizeof(TUtf8State)); |
|
255 } |
|
256 else |
|
257 { |
|
258 HBufC16* newbuf = iBuf->ReAlloc(aMaxLength); |
|
259 if (!newbuf) return KErrNoMemory; |
|
260 Assign(newbuf); |
|
261 } |
|
262 return KErrNone; |
|
263 } |
|
264 |
|
265 EXPORT_C void LtkUtils::RLtkBuf16::ReAllocL(TInt aMaxLength) |
|
266 { |
|
267 User::LeaveIfError(ReAlloc(aMaxLength)); |
|
268 } |
|
269 |
|
270 EXPORT_C void LtkUtils::RLtkBuf16::Assign(HBufC16* aBuf) |
|
271 { |
|
272 new(this) RLtkBuf16(aBuf); |
|
273 } |
|
274 |
|
275 EXPORT_C TInt LtkUtils::RLtkBuf16::Create(TInt aMaxLength) |
|
276 { |
|
277 if (aMaxLength) |
|
278 { |
|
279 HBufC16* buf = HBufC16::New(aMaxLength); |
|
280 if (!buf) return KErrNoMemory; |
|
281 Assign(buf); |
|
282 } |
|
283 else |
|
284 { |
|
285 Assign(NULL); |
|
286 } |
|
287 return KErrNone; |
|
288 } |
|
289 |
|
290 EXPORT_C void LtkUtils::RLtkBuf16::CreateL(TInt aMaxLength) |
|
291 { |
|
292 User::LeaveIfError(Create(aMaxLength)); |
|
293 } |
|
294 |
|
295 EXPORT_C void LtkUtils::RLtkBuf16::CreateLC(TInt aMaxLength) |
|
296 { |
|
297 CleanupClosePushL(*this); |
|
298 User::LeaveIfError(Create(aMaxLength)); |
|
299 } |
|
300 |
|
301 EXPORT_C void LtkUtils::RLtkBuf16::Close() |
|
302 { |
|
303 delete iBuf; |
|
304 Assign(NULL); |
|
305 } |
|
306 |
|
307 EXPORT_C void LtkUtils::RLtkBuf16::AppendL(const TDesC16& aText) |
|
308 { |
|
309 ReserveExtraL(aText.Length()); |
|
310 Append(aText); |
|
311 } |
|
312 |
|
313 EXPORT_C void LtkUtils::RLtkBuf16::AppendL(TChar aChar) |
|
314 { |
|
315 ReserveExtraL(1); |
|
316 Append(aChar); |
|
317 } |
|
318 |
|
319 EXPORT_C void LtkUtils::RLtkBuf16::ReplaceAllL(const TDesC16& aFrom, const TDesC16& aTo) |
|
320 { |
|
321 //TInt numReplaced = 0; |
|
322 TInt pos = 0; |
|
323 const TInt lenDelta = -aFrom.Length() + aTo.Length(); |
|
324 while (ETrue) |
|
325 { |
|
326 TPtrC16 des(Mid(pos)); |
|
327 TInt found = des.Find(aFrom); |
|
328 if (found == KErrNotFound) break; |
|
329 TInt idx = pos + found; |
|
330 TInt neededLen = Length() + lenDelta; |
|
331 if (neededLen > MaxLength()) |
|
332 { |
|
333 neededLen = Max(neededLen, MaxLength()*2); |
|
334 ReAllocL(neededLen); |
|
335 } |
|
336 Replace(idx, aFrom.Length(), aTo); |
|
337 pos = idx + aTo.Length(); |
|
338 //numReplaced++; |
|
339 } |
|
340 } |
|
341 |
|
342 EXPORT_C void LtkUtils::RLtkBuf16::ReplaceL(TInt aPos, TInt aLength, const TDesC16 &aDes) |
|
343 { |
|
344 const TInt lenDelta = -aLength + aDes.Length(); |
|
345 ReserveExtraL(lenDelta); |
|
346 Replace(aPos, aLength, aDes); |
|
347 } |
|
348 |
|
349 EXPORT_C TInt LtkUtils::RLtkBuf16::CreateMax(TInt aMaxLength) |
|
350 { |
|
351 TInt err = Create(aMaxLength); |
|
352 if (!err) SetLength(aMaxLength); |
|
353 return err; |
|
354 } |
|
355 |
|
356 EXPORT_C void LtkUtils::RLtkBuf16::CreateMaxL(TInt aMaxLength) |
|
357 { |
|
358 User::LeaveIfError(CreateMax(aMaxLength)); |
|
359 } |
|
360 |
|
361 class TOverflowDetect : public TDes16Overflow |
|
362 { |
|
363 public: |
|
364 TOverflowDetect() : iOverflowed(EFalse) {} |
|
365 virtual void Overflow(TDes16& /*aDes*/) { iOverflowed = ETrue; } |
|
366 |
|
367 TBool iOverflowed; |
|
368 }; |
|
369 |
|
370 EXPORT_C void LtkUtils::RLtkBuf16::AppendFormatL(TRefByValue<const TDesC16> aFmt, ...) |
|
371 { |
|
372 TInt origLen = Length(); |
|
373 for (;;) |
|
374 { |
|
375 VA_LIST args; |
|
376 VA_START(args, aFmt); |
|
377 TOverflowDetect overflow; |
|
378 AppendFormatList(aFmt, args, &overflow); |
|
379 VA_END(args); |
|
380 if (overflow.iOverflowed) |
|
381 { |
|
382 SetLength(origLen); // In case we got half-way through formatting |
|
383 ReAllocL(Max(16, MaxLength() * 2)); |
|
384 // And go round again |
|
385 } |
|
386 else |
|
387 { |
|
388 // We're done, no overflow |
|
389 break; |
|
390 } |
|
391 } |
|
392 } |
|
393 |
|
394 EXPORT_C void LtkUtils::RLtkBuf16::ReserveExtraL(TInt aExtraCapacity) |
|
395 { |
|
396 User::LeaveIfError(ReserveExtra(aExtraCapacity)); |
|
397 } |
|
398 |
|
399 EXPORT_C TInt LtkUtils::RLtkBuf16::ReserveExtra(TInt aExtraCapacity) |
|
400 { |
|
401 if (Length() + aExtraCapacity > MaxLength()) |
|
402 { |
|
403 TInt newlen = Max(Length() + aExtraCapacity, (MaxLength() * 3)/2); |
|
404 return ReAlloc(newlen); |
|
405 } |
|
406 return KErrNone; |
|
407 } |
|
408 |
|
409 inline TDesC8::TDesC8(TInt aType,TInt aLength) |
|
410 :iLength(aLength|(aType<<KShiftDesType8)) |
|
411 {} |
|
412 |
|
413 inline TDes8::TDes8(TInt aType,TInt aLength,TInt aMaxLength) |
|
414 : TDesC8(aType,aLength),iMaxLength(aMaxLength) |
|
415 {} |
|
416 |
|
417 EXPORT_C LtkUtils::RLtkBuf8::RLtkBuf8() |
|
418 : TDes8(EPtr,0,0), iBuf(NULL) |
|
419 { |
|
420 } |
|
421 |
|
422 EXPORT_C LtkUtils::RLtkBuf8::RLtkBuf8(HBufC8* aBuf) |
|
423 { |
|
424 if(aBuf) |
|
425 { |
|
426 //Create EBufCPtr type descriptor that points to aHBuf |
|
427 // I'll take base_e32's word for it that this does the right thing... |
|
428 new(this) TPtr8(aBuf->Des()); |
|
429 } |
|
430 else |
|
431 { |
|
432 //Create zero-length RBuf8. It is EPtr type of descriptor that points to NULL. |
|
433 new(this) RLtkBuf8(); |
|
434 } |
|
435 } |
|
436 |
|
437 EXPORT_C HBufC8* LtkUtils::RLtkBuf8::ToHBuf() |
|
438 { |
|
439 // This transfers ownership |
|
440 HBufC8* result = iBuf; |
|
441 Assign(NULL); |
|
442 return result; |
|
443 } |
|
444 |
|
445 EXPORT_C HBufC8* LtkUtils::RLtkBuf8::GetHBuf() const |
|
446 { |
|
447 // This doesn't transfer ownership |
|
448 return iBuf; |
|
449 } |
|
450 |
|
451 EXPORT_C TInt LtkUtils::RLtkBuf8::ReAlloc(TInt aMaxLength) |
|
452 { |
|
453 if (!aMaxLength) // Reallocation to zero length |
|
454 { |
|
455 Close(); |
|
456 return KErrNone; |
|
457 } |
|
458 |
|
459 if (!iBuf) // Reallocation from zero length |
|
460 return Create(aMaxLength); |
|
461 |
|
462 HBufC8* newbuf = iBuf->ReAlloc(aMaxLength); |
|
463 if (!newbuf) return KErrNoMemory; |
|
464 Assign(newbuf); |
|
465 return KErrNone; |
|
466 } |
|
467 |
|
468 EXPORT_C void LtkUtils::RLtkBuf8::ReAllocL(TInt aMaxLength) |
|
469 { |
|
470 User::LeaveIfError(ReAlloc(aMaxLength)); |
|
471 } |
|
472 |
|
473 EXPORT_C void LtkUtils::RLtkBuf8::Assign(HBufC8* aBuf) |
|
474 { |
|
475 new(this) RLtkBuf8(aBuf); |
|
476 } |
|
477 |
|
478 EXPORT_C TInt LtkUtils::RLtkBuf8::Create(TInt aMaxLength) |
|
479 { |
|
480 if (aMaxLength) |
|
481 { |
|
482 HBufC8* buf = HBufC8::New(aMaxLength); |
|
483 if (!buf) return KErrNoMemory; |
|
484 Assign(buf); |
|
485 } |
|
486 else |
|
487 { |
|
488 Assign(NULL); |
|
489 } |
|
490 return KErrNone; |
|
491 } |
|
492 |
|
493 EXPORT_C void LtkUtils::RLtkBuf8::CreateL(TInt aMaxLength) |
|
494 { |
|
495 User::LeaveIfError(Create(aMaxLength)); |
|
496 } |
|
497 |
|
498 EXPORT_C void LtkUtils::RLtkBuf8::CreateLC(TInt aMaxLength) |
|
499 { |
|
500 CleanupClosePushL(*this); |
|
501 User::LeaveIfError(Create(aMaxLength)); |
|
502 } |
|
503 |
|
504 EXPORT_C void LtkUtils::RLtkBuf8::Close() |
|
505 { |
|
506 delete iBuf; |
|
507 Assign(NULL); |
|
508 } |
|
509 |
|
510 EXPORT_C void LtkUtils::RLtkBuf8::AppendL(const TDesC8& aText) |
|
511 { |
|
512 ReserveExtraL(aText.Length()); |
|
513 Append(aText); |
|
514 } |
|
515 |
|
516 EXPORT_C void LtkUtils::RLtkBuf8::AppendL(TChar aChar) |
|
517 { |
|
518 ReserveExtraL(1); |
|
519 Append(aChar); |
|
520 } |
|
521 |
|
522 EXPORT_C void LtkUtils::RLtkBuf8::ReplaceAllL(const TDesC8& aFrom, const TDesC8& aTo) |
|
523 { |
|
524 //TInt numReplaced = 0; |
|
525 TInt pos = 0; |
|
526 const TInt lenDelta = -aFrom.Length() + aTo.Length(); |
|
527 while (ETrue) |
|
528 { |
|
529 TPtrC8 des(Mid(pos)); |
|
530 TInt found = des.Find(aFrom); |
|
531 if (found == KErrNotFound) break; |
|
532 TInt idx = pos + found; |
|
533 TInt neededLen = Length() + lenDelta; |
|
534 if (neededLen > MaxLength()) |
|
535 { |
|
536 neededLen = Max(neededLen, MaxLength()*2); |
|
537 ReAllocL(neededLen); |
|
538 } |
|
539 Replace(idx, aFrom.Length(), aTo); |
|
540 pos = idx + aTo.Length(); |
|
541 //numReplaced++; |
|
542 } |
|
543 } |
|
544 |
|
545 EXPORT_C void LtkUtils::RLtkBuf8::ReplaceL(TInt aPos, TInt aLength, const TDesC8& aDes) |
|
546 { |
|
547 const TInt lenDelta = -aLength + aDes.Length(); |
|
548 if (Length() + lenDelta > MaxLength()) |
|
549 { |
|
550 ReAllocL(Length() + lenDelta); |
|
551 } |
|
552 Replace(aPos, aLength, aDes); |
|
553 } |
|
554 |
|
555 EXPORT_C TInt LtkUtils::RLtkBuf8::CreateMax(TInt aMaxLength) |
|
556 { |
|
557 TInt err = Create(aMaxLength); |
|
558 if (!err) SetLength(aMaxLength); |
|
559 return err; |
|
560 } |
|
561 |
|
562 EXPORT_C void LtkUtils::RLtkBuf8::CreateMaxL(TInt aMaxLength) |
|
563 { |
|
564 User::LeaveIfError(CreateMax(aMaxLength)); |
|
565 } |
|
566 |
|
567 class TOverflowDetect8 : public TDes8Overflow |
|
568 { |
|
569 public: |
|
570 TOverflowDetect8() : iOverflowed(EFalse) {} |
|
571 virtual void Overflow(TDes8& /*aDes*/) { iOverflowed = ETrue; } |
|
572 |
|
573 TBool iOverflowed; |
|
574 }; |
|
575 |
|
576 EXPORT_C void LtkUtils::RLtkBuf8::AppendFormatL(TRefByValue<const TDesC8> aFmt, ...) |
|
577 { |
|
578 TInt origLen = Length(); |
|
579 for (;;) |
|
580 { |
|
581 VA_LIST args; |
|
582 VA_START(args, aFmt); |
|
583 TOverflowDetect8 overflow; |
|
584 AppendFormatList(aFmt, args, &overflow); |
|
585 VA_END(args); |
|
586 if (overflow.iOverflowed) |
|
587 { |
|
588 SetLength(origLen); // In case we got half-way through formatting |
|
589 ReAllocL(Max(16, MaxLength() * 2)); |
|
590 // And go round again |
|
591 } |
|
592 else |
|
593 { |
|
594 // We're done, no overflow |
|
595 break; |
|
596 } |
|
597 } |
|
598 } |
|
599 |
|
600 EXPORT_C void LtkUtils::RLtkBuf16::AppendL(const TDesC8& aText) |
|
601 { |
|
602 if (Length() + aText.Length() > MaxLength()) |
|
603 { |
|
604 ReAllocL(Length() + aText.Length()); |
|
605 } |
|
606 TPtr16 endBit((TUint16*)Ptr()+Length(), aText.Length(), aText.Length()); |
|
607 endBit.Copy(aText); |
|
608 SetLength(Length() + aText.Length()); |
|
609 } |
|
610 |
|
611 EXPORT_C void LtkUtils::RLtkBuf8::AppendL(const TDesC16& aText) |
|
612 { |
|
613 if (Length() + aText.Length() > MaxLength()) |
|
614 { |
|
615 ReAllocL(Length() + aText.Length()); |
|
616 } |
|
617 TPtr8 endBit((TUint8*)Ptr()+Length(), aText.Length(), aText.Length()); |
|
618 endBit.Copy(aText); |
|
619 SetLength(Length() + aText.Length()); |
|
620 } |
|
621 |
|
622 EXPORT_C void LtkUtils::RLtkBuf8::ReserveExtraL(TInt aExtraCapacity) |
|
623 { |
|
624 User::LeaveIfError(ReserveExtra(aExtraCapacity)); |
|
625 } |
|
626 |
|
627 EXPORT_C TInt LtkUtils::RLtkBuf8::ReserveExtra(TInt aExtraCapacity) |
|
628 { |
|
629 if (Length() + aExtraCapacity > MaxLength()) |
|
630 { |
|
631 TInt newlen = Max(Length() + aExtraCapacity, (MaxLength() * 3)/2); |
|
632 return ReAlloc(newlen); |
|
633 } |
|
634 return KErrNone; |
|
635 } |
|
636 |
|
637 EXPORT_C void LtkUtils::RLtkBuf8::CopyAsUtf8L(const TDesC16& aString) |
|
638 { |
|
639 // This algorithm is as per the unicode standard v5.2, section 3.9. |
|
640 // Interestingly, byte sequences C0-C1 and F5-FF are completely unused in UTF-8. |
|
641 // Means there won't be any telnet escape problems with 0xFFs... |
|
642 |
|
643 // This function supports the full UTF-16 spec including surrogate pairs, even though the rest of the OS doesn't. |
|
644 |
|
645 SetLength(0); |
|
646 const TInt len = aString.Length(); |
|
647 ReserveExtraL(len); // First guess assumes it's ASCII |
|
648 for (TInt i = 0; i < len; i++) |
|
649 { |
|
650 TUint16 ch = aString[i]; |
|
651 if (ch < 0x80) |
|
652 { |
|
653 // ASCII - one byte |
|
654 AppendL(ch); |
|
655 } |
|
656 else if (ch < 0x800) |
|
657 { |
|
658 // 2 byte |
|
659 TUint8 first = 0xC0 | ((ch & 0x7C0) >> 6); |
|
660 TUint8 second = 0x80 | (ch & 0x3F); |
|
661 AppendL(first); |
|
662 AppendL(second); |
|
663 } |
|
664 else if (Rng(0xD800, (TInt)ch, 0xDBFF)) |
|
665 { |
|
666 // Leading surrogate - a four byter |
|
667 //const TUint32 LEAD_OFFSET = 0xD800 - (0x10000 >> 10); |
|
668 const TUint32 SURROGATE_OFFSET = 0x10000u - (0xD800u << 10) - 0xDC00u; |
|
669 |
|
670 if (i+1 < len && Rng(0xDC00, (TInt)aString[i+1], 0xDFFF)) |
|
671 { |
|
672 TUint16 trailing = aString[i+1]; |
|
673 i++; |
|
674 TUint32 fullCh = ((TUint32)ch << 10) + trailing + SURROGATE_OFFSET; |
|
675 TUint8 first = 0xF0 | ((fullCh & 0x1C0000) >> 18); |
|
676 TUint8 second = 0x80 | ((fullCh & 0x030000) >> 16) | ((fullCh & 0xF000) >> 12); |
|
677 TUint8 third = 0x80 | ((fullCh & 0xFC0) >> 6); |
|
678 TUint8 fourth = 0x80 | (fullCh & 0x3F); |
|
679 AppendL(first); |
|
680 AppendL(second); |
|
681 AppendL(third); |
|
682 AppendL(fourth); |
|
683 } |
|
684 else |
|
685 { |
|
686 // An orphaned leading surrogate - not allowed to just encode it blindly |
|
687 AppendL(KReplacementCharInUtf8); |
|
688 } |
|
689 } |
|
690 else if (Rng(0xDC00, (TInt)ch, 0xDFFF)) |
|
691 { |
|
692 // Orphaned trailing surrogate |
|
693 AppendL(KReplacementCharInUtf8); |
|
694 } |
|
695 else |
|
696 { |
|
697 //Anything else that fits in 16 bits is a three byter. |
|
698 TUint8 first = 0xE0 | ((ch & 0xF000) >> 12); |
|
699 TUint8 second = 0x80 | ((ch & 0xFC0) >> 6); |
|
700 TUint8 third = 0x80 | (ch & 0x3F); |
|
701 AppendL(first); |
|
702 AppendL(second); |
|
703 AppendL(third); |
|
704 } |
|
705 } |
|
706 } |
|
707 |
|
708 EXPORT_C HBufC8* LtkUtils::Utf8L(const TDesC& aString) |
|
709 { |
|
710 RLtkBuf8 result; |
|
711 CleanupClosePushL(result); |
|
712 result.CopyAsUtf8L(aString); |
|
713 CleanupStack::Pop(&result); |
|
714 HBufC8* ptr = result.ToHBuf(); |
|
715 if (!ptr) ptr = HBufC8::NewL(1); // If aString was empty RLtkBuf won't bother creating an HBufC, but callers of this API would expect it |
|
716 return ptr; |
|
717 } |
|
718 |
|
719 EXPORT_C HBufC16* LtkUtils::DecodeUtf8L(const TDesC8& aUtf8EncodedText) |
|
720 { |
|
721 RLtkBuf16 result; |
|
722 result.CreateLC(aUtf8EncodedText.Length()); |
|
723 result.CopyFromUtf8L(aUtf8EncodedText); |
|
724 CleanupStack::Pop(&result); |
|
725 return result.ToHBuf(); |
|
726 } |
|
727 |
|
728 EXPORT_C void LtkUtils::RLtkBuf16::AppendUtf8L(const TDesC8& aUtf8EncodedText) |
|
729 { |
|
730 TInt dontCare; |
|
731 AppendUtf8L(aUtf8EncodedText, dontCare); |
|
732 } |
|
733 |
|
734 EXPORT_C void LtkUtils::RLtkBuf16::CopyFromUtf8L(const TDesC8& aUtf8EncodedText) |
|
735 { |
|
736 ClearUtf8State(); // Just in case, somehow, some old state is lying around |
|
737 Zero(); |
|
738 AppendUtf8L(aUtf8EncodedText); |
|
739 User::LeaveIfError(FinalizeUtf8()); |
|
740 } |
|
741 |
|
742 TUtf8State::TUtf8State() |
|
743 : iFirstUnconvertedByte(KErrNotFound), iBytesConsumedSoFar(0), iUnconvertedBytesCount(0) |
|
744 { |
|
745 } |
|
746 |
|
747 LtkUtils::TUtf8State* LtkUtils::RLtkBuf16::GetUtf8State() const |
|
748 { |
|
749 if (!iBuf) return NULL; |
|
750 TInt hbufMaxLength = iBuf->Des().MaxLength(); |
|
751 TInt ourMaxLength = iMaxLength; // Ie the max length field from TDes16 |
|
752 if (hbufMaxLength == ourMaxLength + KStateCharCount) |
|
753 { |
|
754 // Then we have some state stashed Beyond The Bytes We Know |
|
755 TUtf8State* state = (TUtf8State*)(Ptr() + ourMaxLength); |
|
756 return state; |
|
757 } |
|
758 return NULL; |
|
759 } |
|
760 |
|
761 void LtkUtils::RLtkBuf16::ClearUtf8State() |
|
762 { |
|
763 if (iBuf) |
|
764 { |
|
765 iMaxLength = iBuf->Des().MaxLength(); |
|
766 } |
|
767 } |
|
768 |
|
769 EXPORT_C TInt LtkUtils::RLtkBuf16::FinalizeUtf8() |
|
770 { |
|
771 TInt firstBadBytePosition; |
|
772 FinalizeUtf8(firstBadBytePosition); |
|
773 return firstBadBytePosition == KErrNotFound ? KErrNone : KErrCorrupt; |
|
774 } |
|
775 |
|
776 EXPORT_C void LtkUtils::RLtkBuf16::FinalizeUtf8(TInt& aFirstBadBytePosition) |
|
777 { |
|
778 TUtf8State* state = GetUtf8State(); |
|
779 if (!state) |
|
780 { |
|
781 aFirstBadBytePosition = KErrNotFound; |
|
782 return; |
|
783 } |
|
784 TInt firstUnconvertedByte = state->iFirstUnconvertedByte; |
|
785 if (state->iUnconvertedBytesCount != 0) |
|
786 { |
|
787 if (firstUnconvertedByte == KErrNotFound) firstUnconvertedByte = state->iBytesConsumedSoFar; |
|
788 ClearUtf8State(); |
|
789 Append(KReplacementChar); // Can't fail or leave, we know there was enough space for the TUtf8State |
|
790 } |
|
791 else |
|
792 { |
|
793 ClearUtf8State(); |
|
794 } |
|
795 aFirstBadBytePosition = firstUnconvertedByte; |
|
796 } |
|
797 |
|
798 EXPORT_C void LtkUtils::RLtkBuf16::AppendUtf8L(const TDesC8& aText, TInt& aFirstBadBytePosition) |
|
799 { |
|
800 // This may not be the fastest algorithm, but it should hopefully be fairly easy to read and debug |
|
801 // It's basically the inverse of RLtkBuf8::CopyAsUtf8L(). |
|
802 TUtf8State state; |
|
803 TUtf8State* oldState = GetUtf8State(); |
|
804 if (oldState) |
|
805 { |
|
806 state = *oldState; |
|
807 } |
|
808 aFirstBadBytePosition = KErrNotFound; |
|
809 |
|
810 const TInt textLen = aText.Length(); |
|
811 ReserveExtraL(textLen + KStateCharCount); // We will need at least this many characters, since a UTF-8 byte can never expand to less that 1 character. |
|
812 TUint16* bufPtr = (TUint16*)Ptr() + Length(); |
|
813 TUint16* endPtr = (TUint16*)Ptr() + MaxLength(); |
|
814 const TInt initialLeftoverSize = state.iUnconvertedBytesCount; |
|
815 TUint8 const* readPtr = initialLeftoverSize ? state.iUnconvertedBytes : aText.Ptr(); |
|
816 TUint8 const*const endFragmentPtr = (readPtr + state.iUnconvertedBytesCount); |
|
817 |
|
818 for (TInt i = 0-state.iUnconvertedBytesCount; i < textLen; i++) |
|
819 { |
|
820 // Negative i means we're starting in the unconverted bytes left over from the last append |
|
821 TUint8 ch = *readPtr++; |
|
822 TInt validSequenceLength = 1; |
|
823 TInt sequenceLength = 0; |
|
824 // One of the benefits of UTF-8 is that you can know the sequence length just by looking at the first byte |
|
825 if ((ch & 0x80) == 0) sequenceLength = 1; |
|
826 else if ((ch & 0xE0) == 0xC0) sequenceLength = 2; |
|
827 else if ((ch & 0xF0) == 0xE0) sequenceLength = 3; |
|
828 else if ((ch & 0xF8) == 0xF0) sequenceLength = 4; |
|
829 else |
|
830 { |
|
831 validSequenceLength = 0; |
|
832 } |
|
833 |
|
834 TUint32 fullchar = 0; |
|
835 TInt availableSequenceLength = Min(sequenceLength, textLen - i); |
|
836 if (i >= 0 && availableSequenceLength == sequenceLength) |
|
837 { |
|
838 // The normal case, no need to be careful about readptr |
|
839 // This is the optimised code path |
|
840 switch (sequenceLength) |
|
841 { |
|
842 case 0: |
|
843 validSequenceLength = 0; // For optimisation purposes we don't bother setting this until now |
|
844 break; |
|
845 case 1: |
|
846 fullchar = ch; |
|
847 break; |
|
848 case 2: |
|
849 { |
|
850 TUint8 second = *readPtr++; |
|
851 if ((second & 0xC0) == 0x80) validSequenceLength++; |
|
852 fullchar = ((ch & 0x1F) << 6) | (second & 0x3F); |
|
853 break; |
|
854 } |
|
855 case 3: |
|
856 { |
|
857 TUint8 second = *readPtr++; |
|
858 TUint8 third = *readPtr++; |
|
859 if ((second & 0xC0) == 0x80) |
|
860 { |
|
861 validSequenceLength++; |
|
862 if ((third & 0xC0) == 0x80) validSequenceLength++; |
|
863 } |
|
864 fullchar = ((ch & 0x0F) << 12) | ((second & 0x3F) << 6) | (third & 0x3F); |
|
865 break; |
|
866 } |
|
867 case 4: |
|
868 { |
|
869 TUint8 second = *readPtr++; |
|
870 TUint8 third = *readPtr++; |
|
871 TUint8 fourth = *readPtr++; |
|
872 if ((second & 0xC0) == 0x80) |
|
873 { |
|
874 validSequenceLength++; |
|
875 if ((third & 0xC0) == 0x80) |
|
876 { |
|
877 validSequenceLength++; |
|
878 if ((fourth & 0xC0) == 0x80) validSequenceLength++; |
|
879 } |
|
880 } |
|
881 fullchar = ((ch & 0x07) << 18) | ((second & 0x3F) << 12) | ((third & 0x3F) << 6) | (fourth & 0x3F); |
|
882 break; |
|
883 } |
|
884 default: |
|
885 ASSERT(EFalse); |
|
886 } |
|
887 |
|
888 if (validSequenceLength != availableSequenceLength || validSequenceLength == 0) |
|
889 { |
|
890 // Failed sequence |
|
891 fullchar = KReplacementChar; |
|
892 if (state.iFirstUnconvertedByte == KErrNotFound) |
|
893 { |
|
894 // If we're still in the leftovers i will be negative and hopefully give us the right answer |
|
895 state.iFirstUnconvertedByte = state.iBytesConsumedSoFar + state.iUnconvertedBytesCount + i; |
|
896 } |
|
897 if (aFirstBadBytePosition == KErrNotFound) |
|
898 { |
|
899 // Ugh i could be less than zero if we bailed in the leftovers. We'll say zero, even though that's strictly not correct |
|
900 // Not a lot we can do because from the point of view of aFirstBadBytePosition we implicitly accepted the leftover bytes |
|
901 // at the end of the previous AppendUtf8L() call |
|
902 aFirstBadBytePosition = (i < 0) ? 0 : i; |
|
903 } |
|
904 if (validSequenceLength > 0) i += validSequenceLength-1; // No point testing the bytes we know to be valid following bytes, because they can't by definition be valid starting bytes (it would be within the spec to do so, but would mean we'd not be following best-practice regarding maximal subexpression replacement) |
|
905 readPtr -= (availableSequenceLength - validSequenceLength); // Rewind readPtr over the additional bytes it read |
|
906 } |
|
907 else |
|
908 { |
|
909 i += sequenceLength-1; // Skip over the remaining chars in the sequence |
|
910 } |
|
911 } |
|
912 else // Do it byte-by-byte and slowly |
|
913 { |
|
914 // Validate as many bytes as we have available |
|
915 TUint8 sequence[4]; |
|
916 sequence[0] = ch; |
|
917 for (TInt j = 1; j < availableSequenceLength; j++) |
|
918 { |
|
919 if (readPtr == endFragmentPtr) readPtr = aText.Ptr(); |
|
920 sequence[j] = *readPtr++; |
|
921 if ((sequence[j] & 0xC0) == 0x80) |
|
922 { |
|
923 validSequenceLength++; |
|
924 } |
|
925 else |
|
926 { |
|
927 break; |
|
928 } |
|
929 } |
|
930 if (readPtr == endFragmentPtr) readPtr = aText.Ptr(); |
|
931 |
|
932 if (validSequenceLength != availableSequenceLength) |
|
933 { |
|
934 // Failed sequence |
|
935 fullchar = KReplacementChar; |
|
936 if (state.iFirstUnconvertedByte == KErrNotFound) |
|
937 { |
|
938 // If we're still in the leftovers i will be negative and hopefully give us the right answer |
|
939 state.iFirstUnconvertedByte = state.iBytesConsumedSoFar + state.iUnconvertedBytesCount + i; |
|
940 } |
|
941 if (aFirstBadBytePosition == KErrNotFound) |
|
942 { |
|
943 // Ugh i could be less than zero if we bailed in the leftovers. We'll say zero, even though that's strictly not correct |
|
944 // Not a lot we can do because from the point of view of aFirstBadBytePosition we implicitly accepted the leftover bytes |
|
945 // at the end of the previous AppendUtf8L() call |
|
946 aFirstBadBytePosition = (i < 0) ? 0 : i; |
|
947 } |
|
948 if (validSequenceLength > 0) i += validSequenceLength-1; // No point testing the bytes we know to be valid following bytes, because they can't by definition be valid starting bytes (it would be within the spec to do so, but would mean we'd not be following best-practice regarding maximal subexpression replacement) |
|
949 } |
|
950 else if (availableSequenceLength < sequenceLength) |
|
951 { |
|
952 // Then cache what we do have in the leftovers, that wasn't already |
|
953 TInt sequencePosNotFromLeftovers = 0; |
|
954 if (i < 0) |
|
955 { |
|
956 sequencePosNotFromLeftovers = -i; |
|
957 } |
|
958 Mem::Copy(&state.iUnconvertedBytes[state.iUnconvertedBytesCount], &sequence[sequencePosNotFromLeftovers], availableSequenceLength-sequencePosNotFromLeftovers); |
|
959 state.iUnconvertedBytesCount = availableSequenceLength; |
|
960 i += availableSequenceLength-1; // Skip over the remaining chars in the sequence |
|
961 continue; |
|
962 } |
|
963 else |
|
964 { |
|
965 // We've got everything, and it all validates |
|
966 switch (sequenceLength) |
|
967 { |
|
968 case 1: |
|
969 fullchar = ch; |
|
970 break; |
|
971 case 2: |
|
972 fullchar = ((sequence[0] & 0x1F) << 6) | (sequence[1] & 0x3F); |
|
973 break; |
|
974 case 3: |
|
975 fullchar = ((sequence[0] & 0x0F) << 12) | ((sequence[1] & 0x3F) << 6) | (sequence[2] & 0x3F); |
|
976 break; |
|
977 case 4: |
|
978 fullchar = ((sequence[0] & 0x07) << 18) | ((sequence[1] & 0x3F) << 12) | ((sequence[2] & 0x3F) << 6) | (sequence[3] & 0x3F); |
|
979 break; |
|
980 } |
|
981 |
|
982 state.iUnconvertedBytesCount = 0; // By definition we must have used up all the leftovers |
|
983 i += sequenceLength-1; // Skip over the remaining chars in the sequence |
|
984 } |
|
985 } |
|
986 |
|
987 if (fullchar == KBom && state.iBytesConsumedSoFar == 0 && (i + 1 - sequenceLength) <= 0) |
|
988 { |
|
989 // Byte order marks are ignored, so long as they're the first thing in the buffer (and this is the first buffer) |
|
990 // Otherwise they are considered to be valid zero-width non-breaking spaces (ZWNBSPs) |
|
991 continue; |
|
992 } |
|
993 |
|
994 // If we reach here we have a char to append |
|
995 if (bufPtr == endPtr) |
|
996 { |
|
997 // if bufPtr equals endPtr we're at the end of the buffer and need to realloc it |
|
998 SetLength(iMaxLength); |
|
999 ReserveExtraL(1); |
|
1000 bufPtr = (TUint16*)Ptr() + Length(); |
|
1001 endPtr = (TUint16*)Ptr() + MaxLength(); |
|
1002 } |
|
1003 *bufPtr++ = fullchar; |
|
1004 } |
|
1005 |
|
1006 // Finished handling all the bytes in aText, update some state |
|
1007 SetLength(bufPtr - Ptr()); |
|
1008 TInt bytesAddedToLeftovers = state.iUnconvertedBytesCount - initialLeftoverSize; |
|
1009 state.iBytesConsumedSoFar += textLen - bytesAddedToLeftovers; // Bytes in the leftovers haven't technically been consumed yet |
|
1010 // Now save the state on the end of the buffer - any reallocs must have maintained the state, but there might not have been any state to start with |
|
1011 if (oldState == NULL) |
|
1012 { |
|
1013 ASSERT(iBuf == NULL || iMaxLength == iBuf->Des().MaxLength()); |
|
1014 ReserveExtraL(KStateCharCount); |
|
1015 iMaxLength = iMaxLength - KStateCharCount; |
|
1016 } |
|
1017 Mem::Copy((TAny*)(Ptr() + iMaxLength), &state, sizeof(TUtf8State)); |
|
1018 } |