Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsTArray.h"
8 : #include "nsASCIIMask.h"
9 : #include "mozilla/CheckedInt.h"
10 :
11 : /**
12 : * nsTString::Find
13 : *
14 : * aOffset specifies starting index
15 : * aCount specifies number of string compares (iterations)
16 : */
17 :
18 : int32_t
19 38 : nsTString_CharT::Find( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
20 : {
21 : // this method changes the meaning of aOffset and aCount:
22 38 : Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
23 :
24 38 : int32_t result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase);
25 38 : if (result != kNotFound)
26 12 : result += aOffset;
27 38 : return result;
28 : }
29 :
30 : int32_t
31 37 : nsTString_CharT::Find( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
32 : {
33 37 : return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount);
34 : }
35 :
36 :
37 : /**
38 : * nsTString::RFind
39 : *
40 : * aOffset specifies starting index
41 : * aCount specifies number of string compares (iterations)
42 : */
43 :
44 : int32_t
45 49 : nsTString_CharT::RFind( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
46 : {
47 : // this method changes the meaning of aOffset and aCount:
48 49 : RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
49 :
50 49 : int32_t result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase);
51 49 : if (result != kNotFound)
52 13 : result += aOffset;
53 49 : return result;
54 : }
55 :
56 : int32_t
57 1 : nsTString_CharT::RFind( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const
58 : {
59 1 : return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount);
60 : }
61 :
62 :
63 : /**
64 : * nsTString::RFindChar
65 : */
66 :
67 : int32_t
68 144 : nsTString_CharT::RFindChar( char16_t aChar, int32_t aOffset, int32_t aCount) const
69 : {
70 144 : return nsBufferRoutines<CharT>::rfind_char(mData, mLength, aOffset, aChar, aCount);
71 : }
72 :
73 :
74 : /**
75 : * nsTString::FindCharInSet
76 : */
77 :
78 : int32_t
79 876 : nsTString_CharT::FindCharInSet( const char* aSet, int32_t aOffset ) const
80 : {
81 876 : if (aOffset < 0)
82 0 : aOffset = 0;
83 876 : else if (aOffset >= int32_t(mLength))
84 541 : return kNotFound;
85 :
86 335 : int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
87 335 : if (result != kNotFound)
88 6 : result += aOffset;
89 335 : return result;
90 : }
91 :
92 :
93 : /**
94 : * nsTString::RFindCharInSet
95 : */
96 :
97 : int32_t
98 0 : nsTString_CharT::RFindCharInSet( const CharT* aSet, int32_t aOffset ) const
99 : {
100 : // We want to pass a "data length" to ::RFindCharInSet
101 0 : if (aOffset < 0 || aOffset > int32_t(mLength))
102 0 : aOffset = mLength;
103 : else
104 0 : ++aOffset;
105 :
106 0 : return ::RFindCharInSet(mData, aOffset, aSet);
107 : }
108 :
109 :
110 : // it's a shame to replicate this code. it was done this way in the past
111 : // to help performance. this function also gets to keep the rickg style
112 : // indentation :-/
113 : int32_t
114 274 : nsTString_CharT::ToInteger( nsresult* aErrorCode, uint32_t aRadix ) const
115 : {
116 274 : CharT* cp=mData;
117 274 : int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect)
118 274 : int32_t result=0;
119 274 : bool negate=false;
120 274 : CharT theChar=0;
121 :
122 : //initial value, override if we find an integer
123 274 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
124 :
125 274 : if(cp) {
126 :
127 : //begin by skipping over leading chars that shouldn't be part of the number...
128 :
129 274 : CharT* endcp=cp+mLength;
130 274 : bool done=false;
131 :
132 814 : while((cp<endcp) && (!done)){
133 270 : switch(*cp++) {
134 : case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
135 : case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
136 0 : theRadix=16;
137 0 : done=true;
138 0 : break;
139 : case '0': case '1': case '2': case '3': case '4':
140 : case '5': case '6': case '7': case '8': case '9':
141 270 : done=true;
142 270 : break;
143 : case '-':
144 0 : negate=true; //fall through...
145 0 : break;
146 : case 'X': case 'x':
147 0 : theRadix=16;
148 0 : break;
149 : default:
150 0 : break;
151 : } //switch
152 : }
153 :
154 274 : if (done) {
155 :
156 : //integer found
157 270 : *aErrorCode = NS_OK;
158 :
159 270 : if (aRadix!=kAutoDetect) theRadix = aRadix; // override
160 :
161 : //now iterate the numeric chars and build our result
162 270 : CharT* first=--cp; //in case we have to back up.
163 270 : bool haveValue = false;
164 :
165 1338 : while(cp<endcp){
166 538 : int32_t oldresult = result;
167 :
168 538 : theChar=*cp++;
169 538 : if(('0'<=theChar) && (theChar<='9')){
170 534 : result = (theRadix * result) + (theChar-'0');
171 534 : haveValue = true;
172 : }
173 4 : else if((theChar>='A') && (theChar<='F')) {
174 0 : if(10==theRadix) {
175 0 : if(kAutoDetect==aRadix){
176 0 : theRadix=16;
177 0 : cp=first; //backup
178 0 : result=0;
179 0 : haveValue = false;
180 : }
181 : else {
182 0 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
183 0 : result=0;
184 0 : break;
185 : }
186 : }
187 : else {
188 0 : result = (theRadix * result) + ((theChar-'A')+10);
189 0 : haveValue = true;
190 : }
191 : }
192 4 : else if((theChar>='a') && (theChar<='f')) {
193 0 : if(10==theRadix) {
194 0 : if(kAutoDetect==aRadix){
195 0 : theRadix=16;
196 0 : cp=first; //backup
197 0 : result=0;
198 0 : haveValue = false;
199 : }
200 : else {
201 0 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
202 0 : result=0;
203 0 : break;
204 : }
205 : }
206 : else {
207 0 : result = (theRadix * result) + ((theChar-'a')+10);
208 0 : haveValue = true;
209 : }
210 : }
211 4 : else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) {
212 0 : continue;
213 : }
214 4 : else if((('#'==theChar) || ('+'==theChar)) && !haveValue) {
215 0 : continue;
216 : }
217 : else {
218 : //we've encountered a char that's not a legal number or sign
219 : break;
220 : }
221 :
222 534 : if (result < oldresult) {
223 : // overflow!
224 0 : *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
225 0 : result = 0;
226 0 : break;
227 : }
228 : } //while
229 270 : if(negate)
230 0 : result=-result;
231 : } //if
232 : }
233 274 : return result;
234 : }
235 :
236 :
237 : /**
238 : * nsTString::ToInteger64
239 : */
240 : int64_t
241 8 : nsTString_CharT::ToInteger64( nsresult* aErrorCode, uint32_t aRadix ) const
242 : {
243 8 : CharT* cp=mData;
244 8 : int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect)
245 8 : int64_t result=0;
246 8 : bool negate=false;
247 8 : CharT theChar=0;
248 :
249 : //initial value, override if we find an integer
250 8 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
251 :
252 8 : if(cp) {
253 :
254 : //begin by skipping over leading chars that shouldn't be part of the number...
255 :
256 8 : CharT* endcp=cp+mLength;
257 8 : bool done=false;
258 :
259 24 : while((cp<endcp) && (!done)){
260 8 : switch(*cp++) {
261 : case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
262 : case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
263 0 : theRadix=16;
264 0 : done=true;
265 0 : break;
266 : case '0': case '1': case '2': case '3': case '4':
267 : case '5': case '6': case '7': case '8': case '9':
268 8 : done=true;
269 8 : break;
270 : case '-':
271 0 : negate=true; //fall through...
272 0 : break;
273 : case 'X': case 'x':
274 0 : theRadix=16;
275 0 : break;
276 : default:
277 0 : break;
278 : } //switch
279 : }
280 :
281 8 : if (done) {
282 :
283 : //integer found
284 8 : *aErrorCode = NS_OK;
285 :
286 8 : if (aRadix!=kAutoDetect) theRadix = aRadix; // override
287 :
288 : //now iterate the numeric chars and build our result
289 8 : CharT* first=--cp; //in case we have to back up.
290 8 : bool haveValue = false;
291 :
292 56 : while(cp<endcp){
293 24 : int64_t oldresult = result;
294 :
295 24 : theChar=*cp++;
296 24 : if(('0'<=theChar) && (theChar<='9')){
297 24 : result = (theRadix * result) + (theChar-'0');
298 24 : haveValue = true;
299 : }
300 0 : else if((theChar>='A') && (theChar<='F')) {
301 0 : if(10==theRadix) {
302 0 : if(kAutoDetect==aRadix){
303 0 : theRadix=16;
304 0 : cp=first; //backup
305 0 : result=0;
306 0 : haveValue = false;
307 : }
308 : else {
309 0 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
310 0 : result=0;
311 0 : break;
312 : }
313 : }
314 : else {
315 0 : result = (theRadix * result) + ((theChar-'A')+10);
316 0 : haveValue = true;
317 : }
318 : }
319 0 : else if((theChar>='a') && (theChar<='f')) {
320 0 : if(10==theRadix) {
321 0 : if(kAutoDetect==aRadix){
322 0 : theRadix=16;
323 0 : cp=first; //backup
324 0 : result=0;
325 0 : haveValue = false;
326 : }
327 : else {
328 0 : *aErrorCode=NS_ERROR_ILLEGAL_VALUE;
329 0 : result=0;
330 0 : break;
331 : }
332 : }
333 : else {
334 0 : result = (theRadix * result) + ((theChar-'a')+10);
335 0 : haveValue = true;
336 : }
337 : }
338 0 : else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) {
339 0 : continue;
340 : }
341 0 : else if((('#'==theChar) || ('+'==theChar)) && !haveValue) {
342 0 : continue;
343 : }
344 : else {
345 : //we've encountered a char that's not a legal number or sign
346 : break;
347 : }
348 :
349 24 : if (result < oldresult) {
350 : // overflow!
351 0 : *aErrorCode = NS_ERROR_ILLEGAL_VALUE;
352 0 : result = 0;
353 0 : break;
354 : }
355 : } //while
356 8 : if(negate)
357 0 : result=-result;
358 : } //if
359 : }
360 8 : return result;
361 : }
362 :
363 :
364 : /**
365 : * nsTString::Mid
366 : */
367 :
368 : uint32_t
369 105 : nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
370 : {
371 105 : if (aStartPos == 0 && aLengthToCopy >= mLength)
372 0 : aResult = *this;
373 : else
374 105 : aResult = Substring(*this, aStartPos, aLengthToCopy);
375 :
376 105 : return aResult.mLength;
377 : }
378 :
379 :
380 : /**
381 : * nsTString::SetCharAt
382 : */
383 :
384 : bool
385 46 : nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex )
386 : {
387 46 : if (aIndex >= mLength)
388 0 : return false;
389 :
390 46 : if (!EnsureMutable())
391 0 : AllocFailed(mLength);
392 :
393 46 : mData[aIndex] = CharT(aChar);
394 46 : return true;
395 : }
396 :
397 :
398 : /**
399 : * nsTString::StripChars,StripChar,StripWhitespace
400 : */
401 :
402 : void
403 2 : nsTString_CharT::StripChars( const char* aSet )
404 : {
405 2 : if (!StripChars(aSet, mozilla::fallible)) {
406 0 : AllocFailed(mLength);
407 : }
408 2 : }
409 :
410 : bool
411 2 : nsTString_CharT::StripChars( const char* aSet, const fallible_t& )
412 : {
413 2 : if (!EnsureMutable()) {
414 0 : return false;
415 : }
416 :
417 2 : mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet);
418 2 : return true;
419 : }
420 :
421 : void
422 139 : nsTString_CharT::StripWhitespace()
423 : {
424 139 : if (!StripWhitespace(mozilla::fallible)) {
425 0 : AllocFailed(mLength);
426 : }
427 139 : }
428 :
429 : bool
430 139 : nsTString_CharT::StripWhitespace( const fallible_t& )
431 : {
432 139 : if (!EnsureMutable()) {
433 0 : return false;
434 : }
435 :
436 139 : StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace());
437 139 : return true;
438 : }
439 :
440 : /**
441 : * nsTString::ReplaceChar,ReplaceSubstring
442 : */
443 :
444 : void
445 5 : nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar )
446 : {
447 5 : if (!EnsureMutable()) // XXX do this lazily?
448 0 : AllocFailed(mLength);
449 :
450 40 : for (uint32_t i=0; i<mLength; ++i)
451 : {
452 35 : if (mData[i] == aOldChar)
453 4 : mData[i] = aNewChar;
454 : }
455 5 : }
456 :
457 : void
458 1 : nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar )
459 : {
460 1 : if (!EnsureMutable()) // XXX do this lazily?
461 0 : AllocFailed(mLength);
462 :
463 1 : char_type* data = mData;
464 1 : uint32_t lenRemaining = mLength;
465 :
466 1 : while (lenRemaining)
467 : {
468 1 : int32_t i = ::FindCharInSet(data, lenRemaining, aSet);
469 1 : if (i == kNotFound)
470 1 : break;
471 :
472 0 : data[i++] = aNewChar;
473 0 : data += i;
474 0 : lenRemaining -= i;
475 : }
476 1 : }
477 :
478 : void ReleaseData(void* aData, nsAString::DataFlags aFlags);
479 :
480 : void
481 2469 : nsTString_CharT::ReplaceSubstring(const char_type* aTarget,
482 : const char_type* aNewValue)
483 : {
484 4938 : ReplaceSubstring(nsTDependentString_CharT(aTarget),
485 7407 : nsTDependentString_CharT(aNewValue));
486 2469 : }
487 :
488 : bool
489 0 : nsTString_CharT::ReplaceSubstring(const char_type* aTarget,
490 : const char_type* aNewValue,
491 : const fallible_t& aFallible)
492 : {
493 0 : return ReplaceSubstring(nsTDependentString_CharT(aTarget),
494 0 : nsTDependentString_CharT(aNewValue),
495 0 : aFallible);
496 : }
497 :
498 : void
499 2469 : nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
500 : const self_type& aNewValue)
501 : {
502 2469 : if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) {
503 : // Note that this may wildly underestimate the allocation that failed, as
504 : // we could have been replacing multiple copies of aTarget.
505 0 : AllocFailed(mLength + (aNewValue.Length() - aTarget.Length()));
506 : }
507 2469 : }
508 :
509 : bool
510 2469 : nsTString_CharT::ReplaceSubstring(const self_type& aTarget,
511 : const self_type& aNewValue,
512 : const fallible_t&)
513 : {
514 2469 : if (aTarget.Length() == 0)
515 0 : return true;
516 :
517 : // Remember all of the non-matching parts.
518 4938 : AutoTArray<Segment, 16> nonMatching;
519 2469 : uint32_t i = 0;
520 2469 : mozilla::CheckedUint32 newLength;
521 : while (true)
522 : {
523 2469 : int32_t r = FindSubstring(mData + i, mLength - i, static_cast<const char_type*>(aTarget.Data()), aTarget.Length(), false);
524 2469 : int32_t until = (r == kNotFound) ? mLength - i : r;
525 2469 : nonMatching.AppendElement(Segment(i, until));
526 2469 : newLength += until;
527 2469 : if (r == kNotFound) {
528 2469 : break;
529 : }
530 :
531 0 : newLength += aNewValue.Length();
532 0 : i += r + aTarget.Length();
533 0 : if (i >= mLength) {
534 : // Add an auxiliary entry at the end of the list to help as an edge case
535 : // for the algorithms below.
536 0 : nonMatching.AppendElement(Segment(mLength, 0));
537 0 : break;
538 : }
539 0 : }
540 :
541 2469 : if (!newLength.isValid()) {
542 0 : return false;
543 : }
544 :
545 : // If there's only one non-matching segment, then the target string was not
546 : // found, and there's nothing to do.
547 2469 : if (nonMatching.Length() == 1) {
548 2469 : MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == mLength,
549 : "We should have the correct non-matching segment.");
550 2469 : return true;
551 : }
552 :
553 : // Make sure that we can mutate our buffer.
554 : // Note that we always allocate at least an mLength sized buffer, because the
555 : // rest of the algorithm relies on having access to all of the original
556 : // string. In other words, we over-allocate in the shrinking case.
557 : char_type* oldData;
558 : DataFlags oldFlags;
559 0 : if (!MutatePrep(XPCOM_MAX(mLength, newLength.value()), &oldData, &oldFlags))
560 0 : return false;
561 0 : if (oldData) {
562 : // Copy all of the old data to the new buffer.
563 0 : char_traits::copy(mData, oldData, mLength);
564 0 : ::ReleaseData(oldData, oldFlags);
565 : }
566 :
567 0 : if (aTarget.Length() >= aNewValue.Length()) {
568 : // In the shrinking case, start filling the buffer from the beginning.
569 0 : const uint32_t delta = (aTarget.Length() - aNewValue.Length());
570 0 : for (i = 1; i < nonMatching.Length(); ++i) {
571 : // When we move the i'th non-matching segment into position, we need to
572 : // account for the characters deleted by the previous |i| replacements by
573 : // subtracting |i * delta|.
574 0 : const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin;
575 0 : char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin - i * delta;
576 : // Write the i'th replacement immediately before the new i'th non-matching
577 : // segment.
578 0 : char_traits::copy(destinationSegmentPtr - aNewValue.Length(),
579 0 : aNewValue.Data(), aNewValue.Length());
580 0 : char_traits::move(destinationSegmentPtr, sourceSegmentPtr,
581 0 : nonMatching[i].mLength);
582 : }
583 : } else {
584 : // In the growing case, start filling the buffer from the end.
585 0 : const uint32_t delta = (aNewValue.Length() - aTarget.Length());
586 0 : for (i = nonMatching.Length() - 1; i > 0; --i) {
587 : // When we move the i'th non-matching segment into position, we need to
588 : // account for the characters added by the previous |i| replacements by
589 : // adding |i * delta|.
590 0 : const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin;
591 0 : char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin + i * delta;
592 0 : char_traits::move(destinationSegmentPtr, sourceSegmentPtr,
593 0 : nonMatching[i].mLength);
594 : // Write the i'th replacement immediately before the new i'th non-matching
595 : // segment.
596 0 : char_traits::copy(destinationSegmentPtr - aNewValue.Length(),
597 0 : aNewValue.Data(), aNewValue.Length());
598 : }
599 : }
600 :
601 : // Adjust the length and make sure the string is null terminated.
602 0 : mLength = newLength.value();
603 0 : mData[mLength] = char_type(0);
604 :
605 0 : return true;
606 : }
607 :
608 : /**
609 : * nsTString::Trim
610 : */
611 :
612 : void
613 2786 : nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes )
614 : {
615 : // the old implementation worried about aSet being null :-/
616 2786 : if (!aSet)
617 0 : return;
618 :
619 2786 : char_type* start = mData;
620 2786 : char_type* end = mData + mLength;
621 :
622 : // skip over quotes if requested
623 2786 : if (aIgnoreQuotes && mLength > 2 && mData[0] == mData[mLength - 1] &&
624 0 : (mData[0] == '\'' || mData[0] == '"'))
625 : {
626 0 : ++start;
627 0 : --end;
628 : }
629 :
630 2786 : uint32_t setLen = nsCharTraits<char>::length(aSet);
631 :
632 2786 : if (aTrimLeading)
633 : {
634 183 : uint32_t cutStart = start - mData;
635 183 : uint32_t cutLength = 0;
636 :
637 : // walk forward from start to end
638 195 : for (; start != end; ++start, ++cutLength)
639 : {
640 185 : int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen);
641 185 : if (pos == kNotFound)
642 179 : break;
643 : }
644 :
645 183 : if (cutLength)
646 : {
647 6 : Cut(cutStart, cutLength);
648 :
649 : // reset iterators
650 6 : start = mData + cutStart;
651 6 : end = mData + mLength - cutStart;
652 : }
653 : }
654 :
655 2786 : if (aTrimTrailing)
656 : {
657 2786 : uint32_t cutEnd = end - mData;
658 2786 : uint32_t cutLength = 0;
659 :
660 : // walk backward from end to start
661 2786 : --end;
662 3360 : for (; end >= start; --end, ++cutLength)
663 : {
664 3065 : int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen);
665 3065 : if (pos == kNotFound)
666 2778 : break;
667 : }
668 :
669 2786 : if (cutLength)
670 252 : Cut(cutEnd - cutLength, cutLength);
671 : }
672 : }
673 :
674 :
675 : /**
676 : * nsTString::CompressWhitespace.
677 : */
678 :
679 : void
680 75 : nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing )
681 : {
682 : // Quick exit
683 75 : if (mLength == 0) {
684 8 : return;
685 : }
686 :
687 67 : if (!EnsureMutable())
688 0 : AllocFailed(mLength);
689 :
690 67 : const ASCIIMaskArray& mask = mozilla::ASCIIMask::MaskWhitespace();
691 :
692 67 : char_type* to = mData;
693 67 : char_type* from = mData;
694 67 : char_type* end = mData + mLength;
695 :
696 : // Compresses runs of whitespace down to a normal space ' ' and convert
697 : // any whitespace to a normal space. This assumes that whitespace is
698 : // all standard 7-bit ASCII.
699 67 : bool skipWS = aTrimLeading;
700 1293 : while (from < end) {
701 613 : uint32_t theChar = *from++;
702 613 : if (mozilla::ASCIIMask::IsMasked(mask, theChar)) {
703 24 : if (!skipWS) {
704 24 : *to++ = ' ';
705 24 : skipWS = true;
706 : }
707 : } else {
708 589 : *to++ = theChar;
709 589 : skipWS = false;
710 : }
711 : }
712 :
713 : // If we need to trim the trailing whitespace, back up one character.
714 67 : if (aTrimTrailing && skipWS && to > mData) {
715 0 : to--;
716 : }
717 :
718 67 : *to = char_type(0); // add the null
719 67 : mLength = to - mData;
720 : }
721 :
722 :
723 : /**
724 : * nsTString::AssignWithConversion
725 : */
726 :
727 : void
728 49 : nsTString_CharT::AssignWithConversion( const incompatible_char_type* aData, int32_t aLength )
729 : {
730 : // for compatibility with the old string implementation, we need to allow
731 : // for a nullptr input buffer :-(
732 49 : if (!aData)
733 : {
734 0 : Truncate();
735 : }
736 : else
737 : {
738 49 : if (aLength < 0)
739 49 : aLength = nsCharTraits<incompatible_char_type>::length(aData);
740 :
741 49 : AssignWithConversion(Substring(aData, aLength));
742 : }
743 49 : }
|