Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/ArrayUtils.h"
7 : #include "mozilla/FloatingPoint.h"
8 :
9 : #include "txXSLTNumber.h"
10 : #include "nsGkAtoms.h"
11 : #include "txCore.h"
12 : #include <math.h>
13 : #include "txExpr.h"
14 : #include "txXSLTPatterns.h"
15 : #include "txIXPathContext.h"
16 : #include "txXPathTreeWalker.h"
17 :
18 : #include <algorithm>
19 :
20 0 : nsresult txXSLTNumber::createNumber(Expr* aValueExpr, txPattern* aCountPattern,
21 : txPattern* aFromPattern, LevelType aLevel,
22 : Expr* aGroupSize, Expr* aGroupSeparator,
23 : Expr* aFormat, txIEvalContext* aContext,
24 : nsAString& aResult)
25 : {
26 0 : aResult.Truncate();
27 0 : nsresult rv = NS_OK;
28 :
29 : // Parse format
30 0 : txList counters;
31 0 : nsAutoString head, tail;
32 : rv = getCounters(aGroupSize, aGroupSeparator, aFormat, aContext, counters,
33 0 : head, tail);
34 0 : NS_ENSURE_SUCCESS(rv, rv);
35 :
36 : // Create list of values to format
37 0 : txList values;
38 0 : nsAutoString valueString;
39 : rv = getValueList(aValueExpr, aCountPattern, aFromPattern, aLevel,
40 0 : aContext, values, valueString);
41 0 : NS_ENSURE_SUCCESS(rv, rv);
42 :
43 0 : if (!valueString.IsEmpty()) {
44 0 : aResult = valueString;
45 :
46 0 : return NS_OK;
47 : }
48 :
49 : // Create resulting string
50 0 : aResult = head;
51 0 : bool first = true;
52 0 : txListIterator valueIter(&values);
53 0 : txListIterator counterIter(&counters);
54 0 : valueIter.resetToEnd();
55 : int32_t value;
56 0 : txFormattedCounter* counter = 0;
57 0 : while ((value = NS_PTR_TO_INT32(valueIter.previous()))) {
58 0 : if (counterIter.hasNext()) {
59 0 : counter = (txFormattedCounter*)counterIter.next();
60 : }
61 :
62 0 : if (!first) {
63 0 : aResult.Append(counter->mSeparator);
64 : }
65 :
66 0 : counter->appendNumber(value, aResult);
67 0 : first = false;
68 : }
69 :
70 0 : aResult.Append(tail);
71 :
72 0 : txListIterator iter(&counters);
73 0 : while (iter.hasNext()) {
74 0 : delete (txFormattedCounter*)iter.next();
75 : }
76 :
77 0 : return NS_OK;
78 : }
79 :
80 : nsresult
81 0 : txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
82 : txPattern* aFromPattern, LevelType aLevel,
83 : txIEvalContext* aContext, txList& aValues,
84 : nsAString& aValueString)
85 : {
86 0 : aValueString.Truncate();
87 0 : nsresult rv = NS_OK;
88 :
89 : // If the value attribute exists then use that
90 0 : if (aValueExpr) {
91 0 : RefPtr<txAExprResult> result;
92 0 : rv = aValueExpr->evaluate(aContext, getter_AddRefs(result));
93 0 : NS_ENSURE_SUCCESS(rv, rv);
94 :
95 0 : double value = result->numberValue();
96 :
97 0 : if (mozilla::IsInfinite(value) || mozilla::IsNaN(value) ||
98 : value < 0.5) {
99 0 : txDouble::toString(value, aValueString);
100 0 : return NS_OK;
101 : }
102 :
103 0 : aValues.add(NS_INT32_TO_PTR((int32_t)floor(value + 0.5)));
104 0 : return NS_OK;
105 : }
106 :
107 :
108 : // Otherwise use count/from/level
109 :
110 0 : txPattern* countPattern = aCountPattern;
111 0 : nsAutoPtr<txPattern> newCountPattern;
112 0 : const txXPathNode& currNode = aContext->getContextNode();
113 :
114 : // Parse count- and from-attributes
115 :
116 0 : if (!aCountPattern) {
117 : txNodeTest* nodeTest;
118 0 : uint16_t nodeType = txXPathNodeUtils::getNodeType(currNode);
119 0 : switch (nodeType) {
120 : case txXPathNodeType::ELEMENT_NODE:
121 : {
122 : nsCOMPtr<nsIAtom> localName =
123 0 : txXPathNodeUtils::getLocalName(currNode);
124 0 : int32_t namespaceID = txXPathNodeUtils::getNamespaceID(currNode);
125 0 : nodeTest = new txNameTest(0, localName, namespaceID,
126 0 : txXPathNodeType::ELEMENT_NODE);
127 0 : break;
128 : }
129 : case txXPathNodeType::TEXT_NODE:
130 : case txXPathNodeType::CDATA_SECTION_NODE:
131 : {
132 0 : nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
133 0 : break;
134 : }
135 : case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
136 : {
137 : txNodeTypeTest* typeTest;
138 0 : typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
139 0 : nsAutoString nodeName;
140 0 : txXPathNodeUtils::getNodeName(currNode, nodeName);
141 0 : typeTest->setNodeName(nodeName);
142 0 : nodeTest = typeTest;
143 0 : break;
144 : }
145 : case txXPathNodeType::COMMENT_NODE:
146 : {
147 0 : nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
148 0 : break;
149 : }
150 : case txXPathNodeType::DOCUMENT_NODE:
151 : case txXPathNodeType::ATTRIBUTE_NODE:
152 : default:
153 : {
154 : // this won't match anything as we walk up the tree
155 : // but it's what the spec says to do
156 0 : nodeTest = new txNameTest(0, nsGkAtoms::_asterisk, 0,
157 0 : nodeType);
158 0 : break;
159 : }
160 : }
161 0 : MOZ_ASSERT(nodeTest);
162 0 : countPattern = newCountPattern = new txStepPattern(nodeTest, false);
163 : }
164 :
165 :
166 : // Generate list of values depending on the value of the level-attribute
167 :
168 : // level = "single"
169 0 : if (aLevel == eLevelSingle) {
170 0 : txXPathTreeWalker walker(currNode);
171 0 : do {
172 0 : if (aFromPattern && !walker.isOnNode(currNode)) {
173 : bool matched;
174 0 : rv = aFromPattern->matches(walker.getCurrentPosition(),
175 0 : aContext, matched);
176 0 : NS_ENSURE_SUCCESS(rv, rv);
177 :
178 0 : if (matched) {
179 0 : break;
180 : }
181 : }
182 :
183 : bool matched;
184 0 : rv = countPattern->matches(walker.getCurrentPosition(), aContext,
185 0 : matched);
186 0 : NS_ENSURE_SUCCESS(rv, rv);
187 :
188 0 : if (matched) {
189 : int32_t count;
190 0 : rv = getSiblingCount(walker, countPattern, aContext, &count);
191 0 : NS_ENSURE_SUCCESS(rv, rv);
192 :
193 0 : aValues.add(NS_INT32_TO_PTR(count));
194 0 : break;
195 : }
196 :
197 : } while (walker.moveToParent());
198 :
199 : // Spec says to only match ancestors that are decendants of the
200 : // ancestor that matches the from-pattern, so keep going to make
201 : // sure that there is an ancestor that does.
202 0 : if (aFromPattern && aValues.getLength()) {
203 : bool hasParent;
204 0 : while ((hasParent = walker.moveToParent())) {
205 : bool matched;
206 0 : rv = aFromPattern->matches(walker.getCurrentPosition(),
207 0 : aContext, matched);
208 0 : NS_ENSURE_SUCCESS(rv, rv);
209 :
210 0 : if (matched) {
211 0 : break;
212 : }
213 : }
214 :
215 0 : if (!hasParent) {
216 0 : aValues.clear();
217 : }
218 : }
219 : }
220 : // level = "multiple"
221 0 : else if (aLevel == eLevelMultiple) {
222 : // find all ancestor-or-selfs that matches count until...
223 0 : txXPathTreeWalker walker(currNode);
224 0 : bool matchedFrom = false;
225 0 : do {
226 0 : if (aFromPattern && !walker.isOnNode(currNode)) {
227 0 : rv = aFromPattern->matches(walker.getCurrentPosition(),
228 0 : aContext, matchedFrom);
229 0 : NS_ENSURE_SUCCESS(rv, rv);
230 :
231 0 : if (matchedFrom) {
232 : //... we find one that matches from
233 0 : break;
234 : }
235 : }
236 :
237 : bool matched;
238 0 : rv = countPattern->matches(walker.getCurrentPosition(), aContext,
239 0 : matched);
240 0 : NS_ENSURE_SUCCESS(rv, rv);
241 :
242 0 : if (matched) {
243 : int32_t count;
244 0 : rv = getSiblingCount(walker, countPattern, aContext, &count);
245 0 : NS_ENSURE_SUCCESS(rv, rv);
246 :
247 0 : aValues.add(NS_INT32_TO_PTR(count));
248 : }
249 : } while (walker.moveToParent());
250 :
251 : // Spec says to only match ancestors that are decendants of the
252 : // ancestor that matches the from-pattern, so if none did then
253 : // we shouldn't search anything
254 0 : if (aFromPattern && !matchedFrom) {
255 0 : aValues.clear();
256 : }
257 : }
258 : // level = "any"
259 0 : else if (aLevel == eLevelAny) {
260 0 : int32_t value = 0;
261 0 : bool matchedFrom = false;
262 :
263 0 : txXPathTreeWalker walker(currNode);
264 0 : do {
265 0 : if (aFromPattern && !walker.isOnNode(currNode)) {
266 0 : rv = aFromPattern->matches(walker.getCurrentPosition(),
267 0 : aContext, matchedFrom);
268 0 : NS_ENSURE_SUCCESS(rv, rv);
269 :
270 0 : if (matchedFrom) {
271 0 : break;
272 : }
273 : }
274 :
275 : bool matched;
276 0 : rv = countPattern->matches(walker.getCurrentPosition(), aContext,
277 0 : matched);
278 0 : NS_ENSURE_SUCCESS(rv, rv);
279 :
280 0 : if (matched) {
281 0 : ++value;
282 : }
283 :
284 : } while (getPrevInDocumentOrder(walker));
285 :
286 : // Spec says to only count nodes that follows the first node that
287 : // matches the from pattern. So so if none did then we shouldn't
288 : // count any
289 0 : if (aFromPattern && !matchedFrom) {
290 0 : value = 0;
291 : }
292 :
293 0 : if (value) {
294 0 : aValues.add(NS_INT32_TO_PTR(value));
295 : }
296 : }
297 :
298 0 : return NS_OK;
299 : }
300 :
301 :
302 : nsresult
303 0 : txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
304 : Expr* aFormat, txIEvalContext* aContext,
305 : txList& aCounters, nsAString& aHead,
306 : nsAString& aTail)
307 : {
308 0 : aHead.Truncate();
309 0 : aTail.Truncate();
310 :
311 0 : nsresult rv = NS_OK;
312 :
313 0 : nsAutoString groupSeparator;
314 0 : int32_t groupSize = 0;
315 0 : if (aGroupSize && aGroupSeparator) {
316 0 : nsAutoString sizeStr;
317 0 : rv = aGroupSize->evaluateToString(aContext, sizeStr);
318 0 : NS_ENSURE_SUCCESS(rv, rv);
319 :
320 0 : double size = txDouble::toDouble(sizeStr);
321 0 : groupSize = (int32_t)size;
322 0 : if ((double)groupSize != size) {
323 0 : groupSize = 0;
324 : }
325 :
326 0 : rv = aGroupSeparator->evaluateToString(aContext, groupSeparator);
327 0 : NS_ENSURE_SUCCESS(rv, rv);
328 : }
329 :
330 0 : nsAutoString format;
331 0 : if (aFormat) {
332 0 : rv = aFormat->evaluateToString(aContext, format);
333 0 : NS_ENSURE_SUCCESS(rv, rv);
334 : }
335 :
336 0 : uint32_t formatLen = format.Length();
337 0 : uint32_t formatPos = 0;
338 0 : char16_t ch = 0;
339 :
340 : // start with header
341 0 : while (formatPos < formatLen &&
342 0 : !isAlphaNumeric(ch = format.CharAt(formatPos))) {
343 0 : aHead.Append(ch);
344 0 : ++formatPos;
345 : }
346 :
347 : // If there are no formatting tokens we need to create a default one.
348 0 : if (formatPos == formatLen) {
349 : txFormattedCounter* defaultCounter;
350 0 : rv = txFormattedCounter::getCounterFor(NS_LITERAL_STRING("1"), groupSize,
351 0 : groupSeparator, defaultCounter);
352 0 : NS_ENSURE_SUCCESS(rv, rv);
353 :
354 0 : defaultCounter->mSeparator.Assign('.');
355 0 : rv = aCounters.add(defaultCounter);
356 0 : if (NS_FAILED(rv)) {
357 : // XXX ErrorReport: out of memory
358 0 : delete defaultCounter;
359 0 : return rv;
360 : }
361 :
362 0 : return NS_OK;
363 : }
364 :
365 0 : while (formatPos < formatLen) {
366 0 : nsAutoString sepToken;
367 : // parse separator token
368 0 : if (!aCounters.getLength()) {
369 : // Set the first counters separator to default value so that if
370 : // there is only one formatting token and we're formatting a
371 : // value-list longer then one we use the default separator. This
372 : // won't be used when formatting the first value anyway.
373 0 : sepToken.Assign('.');
374 : }
375 : else {
376 0 : while (formatPos < formatLen &&
377 0 : !isAlphaNumeric(ch = format.CharAt(formatPos))) {
378 0 : sepToken.Append(ch);
379 0 : ++formatPos;
380 : }
381 : }
382 :
383 : // if we're at the end of the string then the previous token was the tail
384 0 : if (formatPos == formatLen) {
385 0 : aTail = sepToken;
386 0 : return NS_OK;
387 : }
388 :
389 : // parse formatting token
390 0 : nsAutoString numToken;
391 0 : while (formatPos < formatLen &&
392 0 : isAlphaNumeric(ch = format.CharAt(formatPos))) {
393 0 : numToken.Append(ch);
394 0 : ++formatPos;
395 : }
396 :
397 0 : txFormattedCounter* counter = 0;
398 : rv = txFormattedCounter::getCounterFor(numToken, groupSize,
399 0 : groupSeparator, counter);
400 0 : if (NS_FAILED(rv)) {
401 0 : txListIterator iter(&aCounters);
402 0 : while (iter.hasNext()) {
403 0 : delete (txFormattedCounter*)iter.next();
404 : }
405 0 : aCounters.clear();
406 0 : return rv;
407 : }
408 :
409 : // Add to list of counters
410 0 : counter->mSeparator = sepToken;
411 0 : rv = aCounters.add(counter);
412 0 : if (NS_FAILED(rv)) {
413 : // XXX ErrorReport: out of memory
414 0 : txListIterator iter(&aCounters);
415 0 : while (iter.hasNext()) {
416 0 : delete (txFormattedCounter*)iter.next();
417 : }
418 0 : aCounters.clear();
419 0 : return rv;
420 : }
421 : }
422 :
423 0 : return NS_OK;
424 : }
425 :
426 : nsresult
427 0 : txXSLTNumber::getSiblingCount(txXPathTreeWalker& aWalker,
428 : txPattern* aCountPattern,
429 : txIMatchContext* aContext,
430 : int32_t* aCount)
431 : {
432 0 : int32_t value = 1;
433 0 : while (aWalker.moveToPreviousSibling()) {
434 : bool matched;
435 0 : nsresult rv = aCountPattern->matches(aWalker.getCurrentPosition(),
436 0 : aContext, matched);
437 0 : NS_ENSURE_SUCCESS(rv, rv);
438 :
439 0 : if (matched) {
440 0 : ++value;
441 : }
442 : }
443 :
444 0 : *aCount = value;
445 :
446 0 : return NS_OK;
447 : }
448 :
449 : bool
450 0 : txXSLTNumber::getPrevInDocumentOrder(txXPathTreeWalker& aWalker)
451 : {
452 0 : if (aWalker.moveToPreviousSibling()) {
453 0 : while (aWalker.moveToLastChild()) {
454 : // do nothing
455 : }
456 0 : return true;
457 : }
458 0 : return aWalker.moveToParent();
459 : }
460 :
461 : struct CharRange {
462 : char16_t lower; // inclusive
463 : char16_t upper; // inclusive
464 :
465 0 : bool operator<(const CharRange& other) const {
466 0 : return upper < other.lower;
467 : }
468 : };
469 :
470 0 : bool txXSLTNumber::isAlphaNumeric(char16_t ch)
471 : {
472 : static const CharRange alphanumericRanges[] = {
473 : { 0x0030, 0x0039 },
474 : { 0x0041, 0x005A },
475 : { 0x0061, 0x007A },
476 : { 0x00AA, 0x00AA },
477 : { 0x00B2, 0x00B3 },
478 : { 0x00B5, 0x00B5 },
479 : { 0x00B9, 0x00BA },
480 : { 0x00BC, 0x00BE },
481 : { 0x00C0, 0x00D6 },
482 : { 0x00D8, 0x00F6 },
483 : { 0x00F8, 0x021F },
484 : { 0x0222, 0x0233 },
485 : { 0x0250, 0x02AD },
486 : { 0x02B0, 0x02B8 },
487 : { 0x02BB, 0x02C1 },
488 : { 0x02D0, 0x02D1 },
489 : { 0x02E0, 0x02E4 },
490 : { 0x02EE, 0x02EE },
491 : { 0x037A, 0x037A },
492 : { 0x0386, 0x0386 },
493 : { 0x0388, 0x038A },
494 : { 0x038C, 0x038C },
495 : { 0x038E, 0x03A1 },
496 : { 0x03A3, 0x03CE },
497 : { 0x03D0, 0x03D7 },
498 : { 0x03DA, 0x03F3 },
499 : { 0x0400, 0x0481 },
500 : { 0x048C, 0x04C4 },
501 : { 0x04C7, 0x04C8 },
502 : { 0x04CB, 0x04CC },
503 : { 0x04D0, 0x04F5 },
504 : { 0x04F8, 0x04F9 },
505 : { 0x0531, 0x0556 },
506 : { 0x0559, 0x0559 },
507 : { 0x0561, 0x0587 },
508 : { 0x05D0, 0x05EA },
509 : { 0x05F0, 0x05F2 },
510 : { 0x0621, 0x063A },
511 : { 0x0640, 0x064A },
512 : { 0x0660, 0x0669 },
513 : { 0x0671, 0x06D3 },
514 : { 0x06D5, 0x06D5 },
515 : { 0x06E5, 0x06E6 },
516 : { 0x06F0, 0x06FC },
517 : { 0x0710, 0x0710 },
518 : { 0x0712, 0x072C },
519 : { 0x0780, 0x07A5 },
520 : { 0x0905, 0x0939 },
521 : { 0x093D, 0x093D },
522 : { 0x0950, 0x0950 },
523 : { 0x0958, 0x0961 },
524 : { 0x0966, 0x096F },
525 : { 0x0985, 0x098C },
526 : { 0x098F, 0x0990 },
527 : { 0x0993, 0x09A8 },
528 : { 0x09AA, 0x09B0 },
529 : { 0x09B2, 0x09B2 },
530 : { 0x09B6, 0x09B9 },
531 : { 0x09DC, 0x09DD },
532 : { 0x09DF, 0x09E1 },
533 : { 0x09E6, 0x09F1 },
534 : { 0x09F4, 0x09F9 },
535 : { 0x0A05, 0x0A0A },
536 : { 0x0A0F, 0x0A10 },
537 : { 0x0A13, 0x0A28 },
538 : { 0x0A2A, 0x0A30 },
539 : { 0x0A32, 0x0A33 },
540 : { 0x0A35, 0x0A36 },
541 : { 0x0A38, 0x0A39 },
542 : { 0x0A59, 0x0A5C },
543 : { 0x0A5E, 0x0A5E },
544 : { 0x0A66, 0x0A6F },
545 : { 0x0A72, 0x0A74 },
546 : { 0x0A85, 0x0A8B },
547 : { 0x0A8D, 0x0A8D },
548 : { 0x0A8F, 0x0A91 },
549 : { 0x0A93, 0x0AA8 },
550 : { 0x0AAA, 0x0AB0 },
551 : { 0x0AB2, 0x0AB3 },
552 : { 0x0AB5, 0x0AB9 },
553 : { 0x0ABD, 0x0ABD },
554 : { 0x0AD0, 0x0AD0 },
555 : { 0x0AE0, 0x0AE0 },
556 : { 0x0AE6, 0x0AEF },
557 : { 0x0B05, 0x0B0C },
558 : { 0x0B0F, 0x0B10 },
559 : { 0x0B13, 0x0B28 },
560 : { 0x0B2A, 0x0B30 },
561 : { 0x0B32, 0x0B33 },
562 : { 0x0B36, 0x0B39 },
563 : { 0x0B3D, 0x0B3D },
564 : { 0x0B5C, 0x0B5D },
565 : { 0x0B5F, 0x0B61 },
566 : { 0x0B66, 0x0B6F },
567 : { 0x0B85, 0x0B8A },
568 : { 0x0B8E, 0x0B90 },
569 : { 0x0B92, 0x0B95 },
570 : { 0x0B99, 0x0B9A },
571 : { 0x0B9C, 0x0B9C },
572 : { 0x0B9E, 0x0B9F },
573 : { 0x0BA3, 0x0BA4 },
574 : { 0x0BA8, 0x0BAA },
575 : { 0x0BAE, 0x0BB5 },
576 : { 0x0BB7, 0x0BB9 },
577 : { 0x0BE7, 0x0BF2 },
578 : { 0x0C05, 0x0C0C },
579 : { 0x0C0E, 0x0C10 },
580 : { 0x0C12, 0x0C28 },
581 : { 0x0C2A, 0x0C33 },
582 : { 0x0C35, 0x0C39 },
583 : { 0x0C60, 0x0C61 },
584 : { 0x0C66, 0x0C6F },
585 : { 0x0C85, 0x0C8C },
586 : { 0x0C8E, 0x0C90 },
587 : { 0x0C92, 0x0CA8 },
588 : { 0x0CAA, 0x0CB3 },
589 : { 0x0CB5, 0x0CB9 },
590 : { 0x0CDE, 0x0CDE },
591 : { 0x0CE0, 0x0CE1 },
592 : { 0x0CE6, 0x0CEF },
593 : { 0x0D05, 0x0D0C },
594 : { 0x0D0E, 0x0D10 },
595 : { 0x0D12, 0x0D28 },
596 : { 0x0D2A, 0x0D39 },
597 : { 0x0D60, 0x0D61 },
598 : { 0x0D66, 0x0D6F },
599 : { 0x0D85, 0x0D96 },
600 : { 0x0D9A, 0x0DB1 },
601 : { 0x0DB3, 0x0DBB },
602 : { 0x0DBD, 0x0DBD },
603 : { 0x0DC0, 0x0DC6 },
604 : { 0x0E01, 0x0E30 },
605 : { 0x0E32, 0x0E33 },
606 : { 0x0E40, 0x0E46 },
607 : { 0x0E50, 0x0E59 },
608 : { 0x0E81, 0x0E82 },
609 : { 0x0E84, 0x0E84 },
610 : { 0x0E87, 0x0E88 },
611 : { 0x0E8A, 0x0E8A },
612 : { 0x0E8D, 0x0E8D },
613 : { 0x0E94, 0x0E97 },
614 : { 0x0E99, 0x0E9F },
615 : { 0x0EA1, 0x0EA3 },
616 : { 0x0EA5, 0x0EA5 },
617 : { 0x0EA7, 0x0EA7 },
618 : { 0x0EAA, 0x0EAB },
619 : { 0x0EAD, 0x0EB0 },
620 : { 0x0EB2, 0x0EB3 },
621 : { 0x0EBD, 0x0EBD },
622 : { 0x0EC0, 0x0EC4 },
623 : { 0x0EC6, 0x0EC6 },
624 : { 0x0ED0, 0x0ED9 },
625 : { 0x0EDC, 0x0EDD },
626 : { 0x0F00, 0x0F00 },
627 : { 0x0F20, 0x0F33 },
628 : { 0x0F40, 0x0F47 },
629 : { 0x0F49, 0x0F6A },
630 : { 0x0F88, 0x0F8B },
631 : { 0x1000, 0x1021 },
632 : { 0x1023, 0x1027 },
633 : { 0x1029, 0x102A },
634 : { 0x1040, 0x1049 },
635 : { 0x1050, 0x1055 },
636 : { 0x10A0, 0x10C5 },
637 : { 0x10D0, 0x10F6 },
638 : { 0x1100, 0x1159 },
639 : { 0x115F, 0x11A2 },
640 : { 0x11A8, 0x11F9 },
641 : { 0x1200, 0x1206 },
642 : { 0x1208, 0x1246 },
643 : { 0x1248, 0x1248 },
644 : { 0x124A, 0x124D },
645 : { 0x1250, 0x1256 },
646 : { 0x1258, 0x1258 },
647 : { 0x125A, 0x125D },
648 : { 0x1260, 0x1286 },
649 : { 0x1288, 0x1288 },
650 : { 0x128A, 0x128D },
651 : { 0x1290, 0x12AE },
652 : { 0x12B0, 0x12B0 },
653 : { 0x12B2, 0x12B5 },
654 : { 0x12B8, 0x12BE },
655 : { 0x12C0, 0x12C0 },
656 : { 0x12C2, 0x12C5 },
657 : { 0x12C8, 0x12CE },
658 : { 0x12D0, 0x12D6 },
659 : { 0x12D8, 0x12EE },
660 : { 0x12F0, 0x130E },
661 : { 0x1310, 0x1310 },
662 : { 0x1312, 0x1315 },
663 : { 0x1318, 0x131E },
664 : { 0x1320, 0x1346 },
665 : { 0x1348, 0x135A },
666 : { 0x1369, 0x137C },
667 : { 0x13A0, 0x13F4 },
668 : { 0x1401, 0x166C },
669 : { 0x166F, 0x1676 },
670 : { 0x1681, 0x169A },
671 : { 0x16A0, 0x16EA },
672 : { 0x16EE, 0x16F0 },
673 : { 0x1780, 0x17B3 },
674 : { 0x17E0, 0x17E9 },
675 : { 0x1810, 0x1819 },
676 : { 0x1820, 0x1877 },
677 : { 0x1880, 0x18A8 },
678 : { 0x1E00, 0x1E9B },
679 : { 0x1EA0, 0x1EF9 },
680 : { 0x1F00, 0x1F15 },
681 : { 0x1F18, 0x1F1D },
682 : { 0x1F20, 0x1F45 },
683 : { 0x1F48, 0x1F4D },
684 : { 0x1F50, 0x1F57 },
685 : { 0x1F59, 0x1F59 },
686 : { 0x1F5B, 0x1F5B },
687 : { 0x1F5D, 0x1F5D },
688 : { 0x1F5F, 0x1F7D },
689 : { 0x1F80, 0x1FB4 },
690 : { 0x1FB6, 0x1FBC },
691 : { 0x1FBE, 0x1FBE },
692 : { 0x1FC2, 0x1FC4 },
693 : { 0x1FC6, 0x1FCC },
694 : { 0x1FD0, 0x1FD3 },
695 : { 0x1FD6, 0x1FDB },
696 : { 0x1FE0, 0x1FEC },
697 : { 0x1FF2, 0x1FF4 },
698 : { 0x1FF6, 0x1FFC },
699 : { 0x2070, 0x2070 },
700 : { 0x2074, 0x2079 },
701 : { 0x207F, 0x2089 },
702 : { 0x2102, 0x2102 },
703 : { 0x2107, 0x2107 },
704 : { 0x210A, 0x2113 },
705 : { 0x2115, 0x2115 },
706 : { 0x2119, 0x211D },
707 : { 0x2124, 0x2124 },
708 : { 0x2126, 0x2126 },
709 : { 0x2128, 0x2128 },
710 : { 0x212A, 0x212D },
711 : { 0x212F, 0x2131 },
712 : { 0x2133, 0x2139 },
713 : { 0x2153, 0x2183 },
714 : { 0x2460, 0x249B },
715 : { 0x24EA, 0x24EA },
716 : { 0x2776, 0x2793 },
717 : { 0x3005, 0x3007 },
718 : { 0x3021, 0x3029 },
719 : { 0x3031, 0x3035 },
720 : { 0x3038, 0x303A },
721 : { 0x3041, 0x3094 },
722 : { 0x309D, 0x309E },
723 : { 0x30A1, 0x30FA },
724 : { 0x30FC, 0x30FE },
725 : { 0x3105, 0x312C },
726 : { 0x3131, 0x318E },
727 : { 0x3192, 0x3195 },
728 : { 0x31A0, 0x31B7 },
729 : { 0x3220, 0x3229 },
730 : { 0x3280, 0x3289 },
731 : { 0x3400, 0x3400 },
732 : { 0x4DB5, 0x4DB5 },
733 : { 0x4E00, 0x4E00 },
734 : { 0x9FA5, 0x9FA5 },
735 : { 0xA000, 0xA48C },
736 : { 0xAC00, 0xAC00 },
737 : { 0xD7A3, 0xD7A3 },
738 : { 0xF900, 0xFA2D },
739 : { 0xFB00, 0xFB06 },
740 : { 0xFB13, 0xFB17 },
741 : { 0xFB1D, 0xFB1D },
742 : { 0xFB1F, 0xFB28 },
743 : { 0xFB2A, 0xFB36 },
744 : { 0xFB38, 0xFB3C },
745 : { 0xFB3E, 0xFB3E },
746 : { 0xFB40, 0xFB41 },
747 : { 0xFB43, 0xFB44 },
748 : { 0xFB46, 0xFBB1 },
749 : { 0xFBD3, 0xFD3D },
750 : { 0xFD50, 0xFD8F },
751 : { 0xFD92, 0xFDC7 },
752 : { 0xFDF0, 0xFDFB },
753 : { 0xFE70, 0xFE72 },
754 : { 0xFE74, 0xFE74 },
755 : { 0xFE76, 0xFEFC },
756 : { 0xFF10, 0xFF19 },
757 : { 0xFF21, 0xFF3A },
758 : { 0xFF41, 0xFF5A },
759 : { 0xFF66, 0xFFBE },
760 : { 0xFFC2, 0xFFC7 },
761 : { 0xFFCA, 0xFFCF },
762 : { 0xFFD2, 0xFFD7 }
763 : };
764 :
765 0 : CharRange search = { ch, ch };
766 0 : const CharRange* end = mozilla::ArrayEnd(alphanumericRanges);
767 0 : const CharRange* element = std::lower_bound(&alphanumericRanges[0], end, search);
768 0 : if (element == end) {
769 0 : return false;
770 : }
771 0 : return element->lower <= ch && ch <= element->upper;
772 : }
|