/src/mozilla-central/xpcom/string/nsReadableUtils.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsReadableUtils.h" |
8 | | |
9 | | #include <algorithm> |
10 | | |
11 | | #include "mozilla/CheckedInt.h" |
12 | | |
13 | | #include "nscore.h" |
14 | | #include "nsMemory.h" |
15 | | #include "nsString.h" |
16 | | #include "nsTArray.h" |
17 | | #include "nsUTF8Utils.h" |
18 | | |
19 | | using mozilla::MakeSpan; |
20 | | |
21 | | /** |
22 | | * A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator). |
23 | | * |
24 | | * @param aSource an string you will eventually be making a copy of |
25 | | * @return a new buffer (of the type specified by the second parameter) which you must free with |free|. |
26 | | * |
27 | | */ |
28 | | template <class FromStringT, class ToCharT> |
29 | | inline |
30 | | ToCharT* |
31 | | AllocateStringCopy(const FromStringT& aSource, ToCharT*) |
32 | 8 | { |
33 | 8 | // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity |
34 | 8 | return static_cast<ToCharT*>( |
35 | 8 | moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT))); |
36 | 8 | } Unexecuted instantiation: char* AllocateStringCopy<nsTSubstring<char16_t>, char>(nsTSubstring<char16_t> const&, char*) char* AllocateStringCopy<nsTSubstring<char>, char>(nsTSubstring<char> const&, char*) Line | Count | Source | 32 | 5 | { | 33 | 5 | // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity | 34 | 5 | return static_cast<ToCharT*>( | 35 | 5 | moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT))); | 36 | 5 | } |
char16_t* AllocateStringCopy<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t> const&, char16_t*) Line | Count | Source | 32 | 3 | { | 33 | 3 | // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity | 34 | 3 | return static_cast<ToCharT*>( | 35 | 3 | moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT))); | 36 | 3 | } |
Unexecuted instantiation: char16_t* AllocateStringCopy<nsTSubstring<char>, char16_t>(nsTSubstring<char> const&, char16_t*) |
37 | | |
38 | | |
39 | | char* |
40 | | ToNewCString(const nsAString& aSource) |
41 | 0 | { |
42 | 0 | char* dest = AllocateStringCopy(aSource, (char*)nullptr); |
43 | 0 | if (!dest) { |
44 | 0 | return nullptr; |
45 | 0 | } |
46 | 0 | |
47 | 0 | auto len = aSource.Length(); |
48 | 0 | LossyConvertUTF16toLatin1(aSource, MakeSpan(dest, len)); |
49 | 0 | dest[len] = 0; |
50 | 0 | return dest; |
51 | 0 | } |
52 | | |
53 | | char* |
54 | | ToNewUTF8String(const nsAString& aSource, uint32_t* aUTF8Count) |
55 | 0 | { |
56 | 0 | auto len = aSource.Length(); |
57 | 0 | // The uses of this function seem temporary enough that it's not |
58 | 0 | // worthwhile to be fancy about the allocation size. Let's just use |
59 | 0 | // the worst case. |
60 | 0 | // Times 3 plus 2, because ConvertUTF16toUTF8 requires times 3 plus 1 and |
61 | 0 | // then we have the terminator. |
62 | 0 | // Using CheckedInt<uint32_t>, because aUTF8Count is uint32_t* for |
63 | 0 | // historical reasons. |
64 | 0 | mozilla::CheckedInt<uint32_t> destLen(len); |
65 | 0 | destLen *= 3; |
66 | 0 | destLen += 2; |
67 | 0 | if (!destLen.isValid()) { |
68 | 0 | return nullptr; |
69 | 0 | } |
70 | 0 | size_t destLenVal = destLen.value(); |
71 | 0 | char* dest = static_cast<char*>(moz_xmalloc(destLenVal)); |
72 | 0 |
|
73 | 0 | size_t written = ConvertUTF16toUTF8(aSource, MakeSpan(dest, destLenVal)); |
74 | 0 | dest[written] = 0; |
75 | 0 |
|
76 | 0 | if (aUTF8Count) { |
77 | 0 | *aUTF8Count = written; |
78 | 0 | } |
79 | 0 |
|
80 | 0 | return dest; |
81 | 0 | } |
82 | | |
83 | | char* |
84 | | ToNewCString(const nsACString& aSource) |
85 | 5 | { |
86 | 5 | // no conversion needed, just allocate a buffer of the correct length and copy into it |
87 | 5 | |
88 | 5 | char* dest = AllocateStringCopy(aSource, (char*)nullptr); |
89 | 5 | if (!dest) { |
90 | 0 | return nullptr; |
91 | 0 | } |
92 | 5 | |
93 | 5 | auto len = aSource.Length(); |
94 | 5 | memcpy(dest, aSource.BeginReading(), len * sizeof(char)); |
95 | 5 | dest[len] = 0; |
96 | 5 | return dest; |
97 | 5 | } |
98 | | |
99 | | char16_t* |
100 | | ToNewUnicode(const nsAString& aSource) |
101 | 3 | { |
102 | 3 | // no conversion needed, just allocate a buffer of the correct length and copy into it |
103 | 3 | |
104 | 3 | char16_t* dest = AllocateStringCopy(aSource, (char16_t*)nullptr); |
105 | 3 | if (!dest) { |
106 | 0 | return nullptr; |
107 | 0 | } |
108 | 3 | |
109 | 3 | auto len = aSource.Length(); |
110 | 3 | memcpy(dest, aSource.BeginReading(), len * sizeof(char16_t)); |
111 | 3 | dest[len] = 0; |
112 | 3 | return dest; |
113 | 3 | } |
114 | | |
115 | | char16_t* |
116 | | ToNewUnicode(const nsACString& aSource) |
117 | 0 | { |
118 | 0 | char16_t* dest = AllocateStringCopy(aSource, (char16_t*)nullptr); |
119 | 0 | if (!dest) { |
120 | 0 | return nullptr; |
121 | 0 | } |
122 | 0 | |
123 | 0 | auto len = aSource.Length(); |
124 | 0 | ConvertLatin1toUTF16(aSource, MakeSpan(dest, len)); |
125 | 0 | dest[len] = 0; |
126 | 0 | return dest; |
127 | 0 | } |
128 | | |
129 | | char16_t* |
130 | | UTF8ToNewUnicode(const nsACString& aSource, uint32_t* aUTF16Count) |
131 | 0 | { |
132 | 0 | // Compute length plus one as required by ConvertUTF8toUTF16 |
133 | 0 | uint32_t lengthPlusOne = aSource.Length() + 1; // Can't overflow |
134 | 0 |
|
135 | 0 | mozilla::CheckedInt<size_t> allocLength(lengthPlusOne); |
136 | 0 | // Add space for zero-termination |
137 | 0 | allocLength += 1; |
138 | 0 | // We need UTF-16 units |
139 | 0 | allocLength *= sizeof(char16_t); |
140 | 0 |
|
141 | 0 | if (!allocLength.isValid()) { |
142 | 0 | return nullptr; |
143 | 0 | } |
144 | 0 | |
145 | 0 | char16_t* dest = (char16_t*)moz_xmalloc(allocLength.value()); |
146 | 0 |
|
147 | 0 | size_t written = ConvertUTF8toUTF16(aSource, MakeSpan(dest, lengthPlusOne)); |
148 | 0 | dest[written] = 0; |
149 | 0 |
|
150 | 0 | if (aUTF16Count) { |
151 | 0 | *aUTF16Count = written; |
152 | 0 | } |
153 | 0 |
|
154 | 0 | return dest; |
155 | 0 | } |
156 | | |
157 | | char16_t* |
158 | | CopyUnicodeTo(const nsAString& aSource, uint32_t aSrcOffset, char16_t* aDest, |
159 | | uint32_t aLength) |
160 | 0 | { |
161 | 0 | MOZ_ASSERT(aSrcOffset + aLength <= aSource.Length()); |
162 | 0 | memcpy(aDest, |
163 | 0 | aSource.BeginReading() + aSrcOffset, |
164 | 0 | size_t(aLength) * sizeof(char16_t)); |
165 | 0 | return aDest; |
166 | 0 | } |
167 | | |
168 | | void |
169 | | ToUpperCase(nsACString& aCString) |
170 | 12 | { |
171 | 12 | char* cp = aCString.BeginWriting(); |
172 | 12 | char* end = cp + aCString.Length(); |
173 | 36 | while (cp != end) { |
174 | 24 | char ch = *cp; |
175 | 24 | if (ch >= 'a' && ch <= 'z') { |
176 | 0 | *cp = ch - ('a' - 'A'); |
177 | 0 | } |
178 | 24 | ++cp; |
179 | 24 | } |
180 | 12 | } |
181 | | |
182 | | void |
183 | | ToUpperCase(const nsACString& aSource, nsACString& aDest) |
184 | 0 | { |
185 | 0 | aDest.SetLength(aSource.Length()); |
186 | 0 | const char* src = aSource.BeginReading(); |
187 | 0 | const char* end = src + aSource.Length(); |
188 | 0 | char* dst = aDest.BeginWriting(); |
189 | 0 | while (src != end) { |
190 | 0 | char ch = *src; |
191 | 0 | if (ch >= 'a' && ch <= 'z') { |
192 | 0 | *dst = ch - ('a' - 'A'); |
193 | 0 | } else { |
194 | 0 | *dst = ch; |
195 | 0 | } |
196 | 0 | ++src; |
197 | 0 | ++dst; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | void |
202 | | ToLowerCase(nsACString& aCString) |
203 | 6.91M | { |
204 | 6.91M | char* cp = aCString.BeginWriting(); |
205 | 6.91M | char* end = cp + aCString.Length(); |
206 | 113M | while (cp != end) { |
207 | 106M | char ch = *cp; |
208 | 106M | if (ch >= 'A' && ch <= 'Z') { |
209 | 296k | *cp = ch + ('a' - 'A'); |
210 | 296k | } |
211 | 106M | ++cp; |
212 | 106M | } |
213 | 6.91M | } |
214 | | |
215 | | void |
216 | | ToLowerCase(const nsACString& aSource, nsACString& aDest) |
217 | 30 | { |
218 | 30 | aDest.SetLength(aSource.Length()); |
219 | 30 | const char* src = aSource.BeginReading(); |
220 | 30 | const char* end = src + aSource.Length(); |
221 | 30 | char* dst = aDest.BeginWriting(); |
222 | 456 | while (src != end) { |
223 | 426 | char ch = *src; |
224 | 426 | if (ch >= 'A' && ch <= 'Z') { |
225 | 0 | *dst = ch + ('a' - 'A'); |
226 | 426 | } else { |
227 | 426 | *dst = ch; |
228 | 426 | } |
229 | 426 | ++src; |
230 | 426 | ++dst; |
231 | 426 | } |
232 | 30 | } |
233 | | |
234 | | bool |
235 | | ParseString(const nsACString& aSource, char aDelimiter, |
236 | | nsTArray<nsCString>& aArray) |
237 | 0 | { |
238 | 0 | nsACString::const_iterator start, end; |
239 | 0 | aSource.BeginReading(start); |
240 | 0 | aSource.EndReading(end); |
241 | 0 |
|
242 | 0 | uint32_t oldLength = aArray.Length(); |
243 | 0 |
|
244 | 0 | for (;;) { |
245 | 0 | nsACString::const_iterator delimiter = start; |
246 | 0 | FindCharInReadable(aDelimiter, delimiter, end); |
247 | 0 |
|
248 | 0 | if (delimiter != start) { |
249 | 0 | if (!aArray.AppendElement(Substring(start, delimiter))) { |
250 | 0 | aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength); |
251 | 0 | return false; |
252 | 0 | } |
253 | 0 | } |
254 | 0 | |
255 | 0 | if (delimiter == end) { |
256 | 0 | break; |
257 | 0 | } |
258 | 0 | start = ++delimiter; |
259 | 0 | if (start == end) { |
260 | 0 | break; |
261 | 0 | } |
262 | 0 | } |
263 | 0 |
|
264 | 0 | return true; |
265 | 0 | } |
266 | | |
267 | | template <class StringT, class IteratorT, class Comparator> |
268 | | bool |
269 | | FindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart, |
270 | | IteratorT& aSearchEnd, const Comparator& aCompare) |
271 | 5.28k | { |
272 | 5.28k | bool found_it = false; |
273 | 5.28k | |
274 | 5.28k | // only bother searching at all if we're given a non-empty range to search |
275 | 5.28k | if (aSearchStart != aSearchEnd) { |
276 | 5.27k | IteratorT aPatternStart, aPatternEnd; |
277 | 5.27k | aPattern.BeginReading(aPatternStart); |
278 | 5.27k | aPattern.EndReading(aPatternEnd); |
279 | 5.27k | |
280 | 5.27k | // outer loop keeps searching till we find it or run out of string to search |
281 | 8.54k | while (!found_it) { |
282 | 6.05k | // fast inner loop (that's what it's called, not what it is) looks for a potential match |
283 | 92.8k | while (aSearchStart != aSearchEnd && |
284 | 92.8k | aCompare(aPatternStart.get(), aSearchStart.get(), 1, 1)) { |
285 | 86.8k | ++aSearchStart; |
286 | 86.8k | } |
287 | 6.05k | |
288 | 6.05k | // if we broke out of the `fast' loop because we're out of string ... we're done: no match |
289 | 6.05k | if (aSearchStart == aSearchEnd) { |
290 | 2.78k | break; |
291 | 2.78k | } |
292 | 3.26k | |
293 | 3.26k | // otherwise, we're at a potential match, let's see if we really hit one |
294 | 3.26k | IteratorT testPattern(aPatternStart); |
295 | 3.26k | IteratorT testSearch(aSearchStart); |
296 | 3.26k | |
297 | 3.26k | // slow inner loop verifies the potential match (found by the `fast' loop) at the current position |
298 | 5.82k | for (;;) { |
299 | 5.82k | // we already compared the first character in the outer loop, |
300 | 5.82k | // so we'll advance before the next comparison |
301 | 5.82k | ++testPattern; |
302 | 5.82k | ++testSearch; |
303 | 5.82k | |
304 | 5.82k | // if we verified all the way to the end of the pattern, then we found it! |
305 | 5.82k | if (testPattern == aPatternEnd) { |
306 | 2.49k | found_it = true; |
307 | 2.49k | aSearchEnd = testSearch; // return the exact found range through the parameters |
308 | 2.49k | break; |
309 | 2.49k | } |
310 | 3.33k | |
311 | 3.33k | // if we got to end of the string we're searching before we hit the end of the |
312 | 3.33k | // pattern, we'll never find what we're looking for |
313 | 3.33k | if (testSearch == aSearchEnd) { |
314 | 5 | aSearchStart = aSearchEnd; |
315 | 5 | break; |
316 | 5 | } |
317 | 3.33k | |
318 | 3.33k | // else if we mismatched ... it's time to advance to the next search position |
319 | 3.33k | // and get back into the `fast' loop |
320 | 3.33k | if (aCompare(testPattern.get(), testSearch.get(), 1, 1)) { |
321 | 767 | ++aSearchStart; |
322 | 767 | break; |
323 | 767 | } |
324 | 3.33k | } |
325 | 3.26k | } |
326 | 5.27k | } |
327 | 5.28k | |
328 | 5.28k | return found_it; |
329 | 5.28k | } Unexecuted instantiation: bool FindInReadable_Impl<nsTSubstring<char16_t>, nsReadingIterator<char16_t>, nsTStringComparator<char16_t> >(nsTSubstring<char16_t> const&, nsReadingIterator<char16_t>&, nsReadingIterator<char16_t>&, nsTStringComparator<char16_t> const&) bool FindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsTStringComparator<char> >(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsTStringComparator<char> const&) Line | Count | Source | 271 | 5.28k | { | 272 | 5.28k | bool found_it = false; | 273 | 5.28k | | 274 | 5.28k | // only bother searching at all if we're given a non-empty range to search | 275 | 5.28k | if (aSearchStart != aSearchEnd) { | 276 | 5.27k | IteratorT aPatternStart, aPatternEnd; | 277 | 5.27k | aPattern.BeginReading(aPatternStart); | 278 | 5.27k | aPattern.EndReading(aPatternEnd); | 279 | 5.27k | | 280 | 5.27k | // outer loop keeps searching till we find it or run out of string to search | 281 | 8.54k | while (!found_it) { | 282 | 6.05k | // fast inner loop (that's what it's called, not what it is) looks for a potential match | 283 | 92.8k | while (aSearchStart != aSearchEnd && | 284 | 92.8k | aCompare(aPatternStart.get(), aSearchStart.get(), 1, 1)) { | 285 | 86.8k | ++aSearchStart; | 286 | 86.8k | } | 287 | 6.05k | | 288 | 6.05k | // if we broke out of the `fast' loop because we're out of string ... we're done: no match | 289 | 6.05k | if (aSearchStart == aSearchEnd) { | 290 | 2.78k | break; | 291 | 2.78k | } | 292 | 3.26k | | 293 | 3.26k | // otherwise, we're at a potential match, let's see if we really hit one | 294 | 3.26k | IteratorT testPattern(aPatternStart); | 295 | 3.26k | IteratorT testSearch(aSearchStart); | 296 | 3.26k | | 297 | 3.26k | // slow inner loop verifies the potential match (found by the `fast' loop) at the current position | 298 | 5.82k | for (;;) { | 299 | 5.82k | // we already compared the first character in the outer loop, | 300 | 5.82k | // so we'll advance before the next comparison | 301 | 5.82k | ++testPattern; | 302 | 5.82k | ++testSearch; | 303 | 5.82k | | 304 | 5.82k | // if we verified all the way to the end of the pattern, then we found it! | 305 | 5.82k | if (testPattern == aPatternEnd) { | 306 | 2.49k | found_it = true; | 307 | 2.49k | aSearchEnd = testSearch; // return the exact found range through the parameters | 308 | 2.49k | break; | 309 | 2.49k | } | 310 | 3.33k | | 311 | 3.33k | // if we got to end of the string we're searching before we hit the end of the | 312 | 3.33k | // pattern, we'll never find what we're looking for | 313 | 3.33k | if (testSearch == aSearchEnd) { | 314 | 5 | aSearchStart = aSearchEnd; | 315 | 5 | break; | 316 | 5 | } | 317 | 3.33k | | 318 | 3.33k | // else if we mismatched ... it's time to advance to the next search position | 319 | 3.33k | // and get back into the `fast' loop | 320 | 3.33k | if (aCompare(testPattern.get(), testSearch.get(), 1, 1)) { | 321 | 767 | ++aSearchStart; | 322 | 767 | break; | 323 | 767 | } | 324 | 3.33k | } | 325 | 3.26k | } | 326 | 5.27k | } | 327 | 5.28k | | 328 | 5.28k | return found_it; | 329 | 5.28k | } |
Unexecuted instantiation: bool FindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsCaseInsensitiveCStringComparator>(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsCaseInsensitiveCStringComparator const&) |
330 | | |
331 | | /** |
332 | | * This searches the entire string from right to left, and returns the first match found, if any. |
333 | | */ |
334 | | template <class StringT, class IteratorT, class Comparator> |
335 | | bool |
336 | | RFindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart, |
337 | | IteratorT& aSearchEnd, const Comparator& aCompare) |
338 | 8.72k | { |
339 | 8.72k | IteratorT patternStart, patternEnd, searchEnd = aSearchEnd; |
340 | 8.72k | aPattern.BeginReading(patternStart); |
341 | 8.72k | aPattern.EndReading(patternEnd); |
342 | 8.72k | |
343 | 8.72k | // Point to the last character in the pattern |
344 | 8.72k | --patternEnd; |
345 | 8.72k | // outer loop keeps searching till we run out of string to search |
346 | 286k | while (aSearchStart != searchEnd) { |
347 | 279k | // Point to the end position of the next possible match |
348 | 279k | --searchEnd; |
349 | 279k | |
350 | 279k | // Check last character, if a match, explore further from here |
351 | 279k | if (aCompare(patternEnd.get(), searchEnd.get(), 1, 1) == 0) { |
352 | 3.26k | // We're at a potential match, let's see if we really hit one |
353 | 3.26k | IteratorT testPattern(patternEnd); |
354 | 3.26k | IteratorT testSearch(searchEnd); |
355 | 3.26k | |
356 | 3.26k | // inner loop verifies the potential match at the current position |
357 | 5.74k | do { |
358 | 5.74k | // if we verified all the way to the end of the pattern, then we found it! |
359 | 5.74k | if (testPattern == patternStart) { |
360 | 2.48k | aSearchStart = testSearch; // point to start of match |
361 | 2.48k | aSearchEnd = ++searchEnd; // point to end of match |
362 | 2.48k | return true; |
363 | 2.48k | } |
364 | 3.26k | |
365 | 3.26k | // if we got to end of the string we're searching before we hit the end of the |
366 | 3.26k | // pattern, we'll never find what we're looking for |
367 | 3.26k | if (testSearch == aSearchStart) { |
368 | 50 | aSearchStart = aSearchEnd; |
369 | 50 | return false; |
370 | 50 | } |
371 | 3.21k | |
372 | 3.21k | // test previous character for a match |
373 | 3.21k | --testPattern; |
374 | 3.21k | --testSearch; |
375 | 3.21k | } while (aCompare(testPattern.get(), testSearch.get(), 1, 1) == 0); |
376 | 3.26k | } |
377 | 279k | } |
378 | 8.72k | |
379 | 8.72k | aSearchStart = aSearchEnd; |
380 | 6.18k | return false; |
381 | 8.72k | } Unexecuted instantiation: bool RFindInReadable_Impl<nsTSubstring<char16_t>, nsReadingIterator<char16_t>, nsTStringComparator<char16_t> >(nsTSubstring<char16_t> const&, nsReadingIterator<char16_t>&, nsReadingIterator<char16_t>&, nsTStringComparator<char16_t> const&) bool RFindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsTStringComparator<char> >(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsTStringComparator<char> const&) Line | Count | Source | 338 | 8.72k | { | 339 | 8.72k | IteratorT patternStart, patternEnd, searchEnd = aSearchEnd; | 340 | 8.72k | aPattern.BeginReading(patternStart); | 341 | 8.72k | aPattern.EndReading(patternEnd); | 342 | 8.72k | | 343 | 8.72k | // Point to the last character in the pattern | 344 | 8.72k | --patternEnd; | 345 | 8.72k | // outer loop keeps searching till we run out of string to search | 346 | 286k | while (aSearchStart != searchEnd) { | 347 | 279k | // Point to the end position of the next possible match | 348 | 279k | --searchEnd; | 349 | 279k | | 350 | 279k | // Check last character, if a match, explore further from here | 351 | 279k | if (aCompare(patternEnd.get(), searchEnd.get(), 1, 1) == 0) { | 352 | 3.26k | // We're at a potential match, let's see if we really hit one | 353 | 3.26k | IteratorT testPattern(patternEnd); | 354 | 3.26k | IteratorT testSearch(searchEnd); | 355 | 3.26k | | 356 | 3.26k | // inner loop verifies the potential match at the current position | 357 | 5.74k | do { | 358 | 5.74k | // if we verified all the way to the end of the pattern, then we found it! | 359 | 5.74k | if (testPattern == patternStart) { | 360 | 2.48k | aSearchStart = testSearch; // point to start of match | 361 | 2.48k | aSearchEnd = ++searchEnd; // point to end of match | 362 | 2.48k | return true; | 363 | 2.48k | } | 364 | 3.26k | | 365 | 3.26k | // if we got to end of the string we're searching before we hit the end of the | 366 | 3.26k | // pattern, we'll never find what we're looking for | 367 | 3.26k | if (testSearch == aSearchStart) { | 368 | 50 | aSearchStart = aSearchEnd; | 369 | 50 | return false; | 370 | 50 | } | 371 | 3.21k | | 372 | 3.21k | // test previous character for a match | 373 | 3.21k | --testPattern; | 374 | 3.21k | --testSearch; | 375 | 3.21k | } while (aCompare(testPattern.get(), testSearch.get(), 1, 1) == 0); | 376 | 3.26k | } | 377 | 279k | } | 378 | 8.72k | | 379 | 8.72k | aSearchStart = aSearchEnd; | 380 | 6.18k | return false; | 381 | 8.72k | } |
|
382 | | |
383 | | bool |
384 | | FindInReadable(const nsAString& aPattern, |
385 | | nsAString::const_iterator& aSearchStart, |
386 | | nsAString::const_iterator& aSearchEnd, |
387 | | const nsStringComparator& aComparator) |
388 | 0 | { |
389 | 0 | return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); |
390 | 0 | } |
391 | | |
392 | | bool |
393 | | FindInReadable(const nsACString& aPattern, |
394 | | nsACString::const_iterator& aSearchStart, |
395 | | nsACString::const_iterator& aSearchEnd, |
396 | | const nsCStringComparator& aComparator) |
397 | 5.28k | { |
398 | 5.28k | return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); |
399 | 5.28k | } |
400 | | |
401 | | bool |
402 | | CaseInsensitiveFindInReadable(const nsACString& aPattern, |
403 | | nsACString::const_iterator& aSearchStart, |
404 | | nsACString::const_iterator& aSearchEnd) |
405 | 0 | { |
406 | 0 | return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, |
407 | 0 | nsCaseInsensitiveCStringComparator()); |
408 | 0 | } |
409 | | |
410 | | bool |
411 | | RFindInReadable(const nsAString& aPattern, |
412 | | nsAString::const_iterator& aSearchStart, |
413 | | nsAString::const_iterator& aSearchEnd, |
414 | | const nsStringComparator& aComparator) |
415 | 0 | { |
416 | 0 | return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); |
417 | 0 | } |
418 | | |
419 | | bool |
420 | | RFindInReadable(const nsACString& aPattern, |
421 | | nsACString::const_iterator& aSearchStart, |
422 | | nsACString::const_iterator& aSearchEnd, |
423 | | const nsCStringComparator& aComparator) |
424 | 8.72k | { |
425 | 8.72k | return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); |
426 | 8.72k | } |
427 | | |
428 | | bool |
429 | | FindCharInReadable(char16_t aChar, nsAString::const_iterator& aSearchStart, |
430 | | const nsAString::const_iterator& aSearchEnd) |
431 | 0 | { |
432 | 0 | int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get(); |
433 | 0 |
|
434 | 0 | const char16_t* charFoundAt = |
435 | 0 | nsCharTraits<char16_t>::find(aSearchStart.get(), fragmentLength, aChar); |
436 | 0 | if (charFoundAt) { |
437 | 0 | aSearchStart.advance(charFoundAt - aSearchStart.get()); |
438 | 0 | return true; |
439 | 0 | } |
440 | 0 | |
441 | 0 | aSearchStart.advance(fragmentLength); |
442 | 0 | return false; |
443 | 0 | } |
444 | | |
445 | | bool |
446 | | FindCharInReadable(char aChar, nsACString::const_iterator& aSearchStart, |
447 | | const nsACString::const_iterator& aSearchEnd) |
448 | 66 | { |
449 | 66 | int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get(); |
450 | 66 | |
451 | 66 | const char* charFoundAt = |
452 | 66 | nsCharTraits<char>::find(aSearchStart.get(), fragmentLength, aChar); |
453 | 66 | if (charFoundAt) { |
454 | 0 | aSearchStart.advance(charFoundAt - aSearchStart.get()); |
455 | 0 | return true; |
456 | 0 | } |
457 | 66 | |
458 | 66 | aSearchStart.advance(fragmentLength); |
459 | 66 | return false; |
460 | 66 | } |
461 | | |
462 | | bool |
463 | | StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring) |
464 | 3.70k | { |
465 | 3.70k | nsAString::size_type src_len = aSource.Length(), |
466 | 3.70k | sub_len = aSubstring.Length(); |
467 | 3.70k | if (sub_len > src_len) { |
468 | 1.13k | return false; |
469 | 1.13k | } |
470 | 2.57k | return Substring(aSource, 0, sub_len).Equals(aSubstring); |
471 | 2.57k | } |
472 | | |
473 | | bool |
474 | | StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring, |
475 | | const nsStringComparator& aComparator) |
476 | 204k | { |
477 | 204k | nsAString::size_type src_len = aSource.Length(), |
478 | 204k | sub_len = aSubstring.Length(); |
479 | 204k | if (sub_len > src_len) { |
480 | 181k | return false; |
481 | 181k | } |
482 | 22.9k | return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); |
483 | 22.9k | } |
484 | | |
485 | | bool |
486 | | StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring) |
487 | 0 | { |
488 | 0 | nsACString::size_type src_len = aSource.Length(), |
489 | 0 | sub_len = aSubstring.Length(); |
490 | 0 | if (sub_len > src_len) { |
491 | 0 | return false; |
492 | 0 | } |
493 | 0 | return Substring(aSource, 0, sub_len).Equals(aSubstring); |
494 | 0 | } |
495 | | |
496 | | bool |
497 | | StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring, |
498 | | const nsCStringComparator& aComparator) |
499 | 0 | { |
500 | 0 | nsACString::size_type src_len = aSource.Length(), |
501 | 0 | sub_len = aSubstring.Length(); |
502 | 0 | if (sub_len > src_len) { |
503 | 0 | return false; |
504 | 0 | } |
505 | 0 | return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); |
506 | 0 | } |
507 | | |
508 | | bool |
509 | | StringEndsWith(const nsAString& aSource, const nsAString& aSubstring) |
510 | 0 | { |
511 | 0 | nsAString::size_type src_len = aSource.Length(), |
512 | 0 | sub_len = aSubstring.Length(); |
513 | 0 | if (sub_len > src_len) { |
514 | 0 | return false; |
515 | 0 | } |
516 | 0 | return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring); |
517 | 0 | } |
518 | | |
519 | | bool |
520 | | StringEndsWith(const nsAString& aSource, const nsAString& aSubstring, |
521 | | const nsStringComparator& aComparator) |
522 | 0 | { |
523 | 0 | nsAString::size_type src_len = aSource.Length(), |
524 | 0 | sub_len = aSubstring.Length(); |
525 | 0 | if (sub_len > src_len) { |
526 | 0 | return false; |
527 | 0 | } |
528 | 0 | return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, |
529 | 0 | aComparator); |
530 | 0 | } |
531 | | |
532 | | bool |
533 | | StringEndsWith(const nsACString& aSource, const nsACString& aSubstring) |
534 | 1 | { |
535 | 1 | nsACString::size_type src_len = aSource.Length(), |
536 | 1 | sub_len = aSubstring.Length(); |
537 | 1 | if (sub_len > src_len) { |
538 | 0 | return false; |
539 | 0 | } |
540 | 1 | return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring); |
541 | 1 | } |
542 | | |
543 | | bool |
544 | | StringEndsWith(const nsACString& aSource, const nsACString& aSubstring, |
545 | | const nsCStringComparator& aComparator) |
546 | 3 | { |
547 | 3 | nsACString::size_type src_len = aSource.Length(), |
548 | 3 | sub_len = aSubstring.Length(); |
549 | 3 | if (sub_len > src_len) { |
550 | 0 | return false; |
551 | 0 | } |
552 | 3 | return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, |
553 | 3 | aComparator); |
554 | 3 | } |
555 | | |
556 | | |
557 | | |
558 | | static const char16_t empty_buffer[1] = { '\0' }; |
559 | | |
560 | | const nsString& |
561 | | EmptyString() |
562 | 1.11M | { |
563 | 1.11M | static const nsDependentString sEmpty(empty_buffer); |
564 | 1.11M | |
565 | 1.11M | return sEmpty; |
566 | 1.11M | } |
567 | | |
568 | | const nsCString& |
569 | | EmptyCString() |
570 | 1.15M | { |
571 | 1.15M | static const nsDependentCString sEmpty((const char*)empty_buffer); |
572 | 1.15M | |
573 | 1.15M | return sEmpty; |
574 | 1.15M | } |
575 | | |
576 | | const nsString& |
577 | | VoidString() |
578 | 0 | { |
579 | 0 | static const nsString sNull(mozilla::detail::StringDataFlags::VOIDED); |
580 | 0 |
|
581 | 0 | return sNull; |
582 | 0 | } |
583 | | |
584 | | const nsCString& |
585 | | VoidCString() |
586 | 24 | { |
587 | 24 | static const nsCString sNull(mozilla::detail::StringDataFlags::VOIDED); |
588 | 24 | |
589 | 24 | return sNull; |
590 | 24 | } |
591 | | |
592 | | int32_t |
593 | | CompareUTF8toUTF16(const nsACString& aUTF8String, |
594 | | const nsAString& aUTF16String, |
595 | | bool* aErr) |
596 | 11.7k | { |
597 | 11.7k | const char* u8; |
598 | 11.7k | const char* u8end; |
599 | 11.7k | aUTF8String.BeginReading(u8); |
600 | 11.7k | aUTF8String.EndReading(u8end); |
601 | 11.7k | |
602 | 11.7k | const char16_t* u16; |
603 | 11.7k | const char16_t* u16end; |
604 | 11.7k | aUTF16String.BeginReading(u16); |
605 | 11.7k | aUTF16String.EndReading(u16end); |
606 | 11.7k | |
607 | 116k | for (;;) { |
608 | 116k | if (u8 == u8end) { |
609 | 11.7k | if (u16 == u16end) { |
610 | 11.7k | return 0; |
611 | 11.7k | } |
612 | 0 | return -1; |
613 | 0 | } |
614 | 105k | if (u16 == u16end) { |
615 | 0 | return 1; |
616 | 0 | } |
617 | 105k | // No need for ASCII optimization, since both NextChar() |
618 | 105k | // calls get inlined. |
619 | 105k | uint32_t scalar8 = UTF8CharEnumerator::NextChar(&u8, u8end, aErr); |
620 | 105k | uint32_t scalar16 = UTF16CharEnumerator::NextChar(&u16, u16end, aErr); |
621 | 105k | if (scalar16 == scalar8) { |
622 | 105k | continue; |
623 | 105k | } |
624 | 0 | if (scalar8 < scalar16) { |
625 | 0 | return -1; |
626 | 0 | } |
627 | 0 | return 1; |
628 | 0 | } |
629 | 11.7k | } |
630 | | |
631 | | void |
632 | | AppendUCS4ToUTF16(const uint32_t aSource, nsAString& aDest) |
633 | 0 | { |
634 | 0 | NS_ASSERTION(IS_VALID_CHAR(aSource), "Invalid UCS4 char"); |
635 | 0 | if (IS_IN_BMP(aSource)) { |
636 | 0 | aDest.Append(char16_t(aSource)); |
637 | 0 | } else { |
638 | 0 | aDest.Append(H_SURROGATE(aSource)); |
639 | 0 | aDest.Append(L_SURROGATE(aSource)); |
640 | 0 | } |
641 | 0 | } |