1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 // Class header file.
19 #include "DOMStringHelper.hpp"
20
21
22
23 #include <cassert>
24 #include <cctype>
25 #include <cmath>
26 #include <cstdio>
27 #include <cstdlib>
28 #if defined(XALAN_WINDOWS)
29 #include <clocale>
30 #include <cstring>
31 #endif
32
33
34 #include <algorithm>
35
36
37
38 #include <iostream>
39
40
41
42 #include <xalanc/Include/STLHelper.hpp>
43
44
45
46 #include "DoubleSupport.hpp"
47 #include "XalanOutputStream.hpp"
48 #include "XalanUnicode.hpp"
49
50
51
52 namespace XALAN_CPP_NAMESPACE {
53
54
55
56 using std::size_t;
57
58
59
60 // The maximum number of digits that sprintf can put in a buffer.
61 // 100 for now. We're using this because we want to avoid transcoding
62 // number strings when we don't have to,
63 const size_t MAX_PRINTF_DIGITS = 100;
64
65 // The maximum number of characters for a floating point number.
66 const size_t MAX_FLOAT_CHARACTERS = 100;
67
68
69
70 static XalanDOMChar theNaNString[] =
71 {
72 XalanUnicode::charLetter_N,
73 XalanUnicode::charLetter_a,
74 XalanUnicode::charLetter_N,
75 0
76 };
77
78 static const XalanDOMChar theNegativeInfinityString[] =
79 {
80 XalanUnicode::charHyphenMinus,
81 XalanUnicode::charLetter_I,
82 XalanUnicode::charLetter_n,
83 XalanUnicode::charLetter_f,
84 XalanUnicode::charLetter_i,
85 XalanUnicode::charLetter_n,
86 XalanUnicode::charLetter_i,
87 XalanUnicode::charLetter_t,
88 XalanUnicode::charLetter_y,
89 0
90 };
91
92 static const XalanDOMChar thePositiveInfinityString[] =
93 {
94 XalanUnicode::charLetter_I,
95 XalanUnicode::charLetter_n,
96 XalanUnicode::charLetter_f,
97 XalanUnicode::charLetter_i,
98 XalanUnicode::charLetter_n,
99 XalanUnicode::charLetter_i,
100 XalanUnicode::charLetter_t,
101 XalanUnicode::charLetter_y,
102 0
103 };
104
105 static const XalanDOMChar theZeroString[] =
106 {
107 XalanUnicode::charDigit_0,
108 0
109 };
110
111
112
113 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
indexOf(const XalanDOMChar * theString,XalanDOMString::size_type theStringLength,const XalanDOMChar * theSubstring,XalanDOMString::size_type theSubstringLength)114 indexOf(
115 const XalanDOMChar* theString,
116 XalanDOMString::size_type theStringLength,
117 const XalanDOMChar* theSubstring,
118 XalanDOMString::size_type theSubstringLength)
119 {
120 assert(theString != 0);
121 assert(theSubstring != 0);
122
123 // If the substring is longer than the string, then
124 // it's not a substring.
125 if (theStringLength < theSubstringLength)
126 {
127 return theStringLength;
128 }
129 else
130 {
131 bool fMatch = false;
132
133 XalanDOMString::size_type theStringIndex = 0;
134
135 // While we haven't matched, and we haven't finished with the
136 // first string, and the number of characters left in the first
137 // string is greater than the length of the second string, try
138 // to match the strings.
139 while(fMatch == false &&
140 theStringIndex < theStringLength &&
141 theStringLength - theStringIndex >= theSubstringLength)
142 {
143 // We always start over from the beginning of the second string.
144 XalanDOMString::size_type theSubstringIndex = 0;
145
146 // This variable will be incremented to index into the first
147 // string. That way, we preserve the first string index for
148 // when we have to restart the following loop with the next
149 // position in the first string.
150 XalanDOMString::size_type theOffset = 0;
151
152 // Compare the characters in the two strings, at the
153 // current indices, until the characters don't match.
154 while(theStringIndex < theStringLength &&
155 theSubstringIndex < theSubstringLength &&
156 theString[theStringIndex + theOffset] ==
157 theSubstring[theSubstringIndex])
158 {
159 theOffset++;
160 theSubstringIndex++;
161 }
162
163 // If we've reached the end of the second string,
164 // then we've found a match.
165 if (theSubstringIndex == theSubstringLength)
166 {
167 fMatch = true;
168 }
169 else
170 {
171 theStringIndex++;
172 }
173 }
174
175 return fMatch == false ? theStringLength : theStringIndex;
176 }
177 }
178
179
180 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
indexOf(const XalanDOMString & theString,const XalanDOMString & theSubstring)181 indexOf(
182 const XalanDOMString& theString,
183 const XalanDOMString& theSubstring)
184 {
185 if (theString.empty() == true)
186 {
187 return 0;
188 }
189 else if (theSubstring.empty() == true)
190 {
191 return theString.length();
192 }
193 else
194 {
195 return indexOf(theString.c_str(), theSubstring.c_str());
196 }
197 }
198
199
200
201 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString::size_type)
lastIndexOf(const XalanDOMChar * theString,XalanDOMChar theChar)202 lastIndexOf(
203 const XalanDOMChar* theString,
204 XalanDOMChar theChar)
205 {
206 const XalanDOMString::size_type theLength = length(theString);
207
208 if (theLength == 0)
209 {
210 return theLength;
211 }
212 else
213 {
214 XalanDOMString::size_type theIndex = theLength;
215
216 while(theIndex > 0 && theString[theIndex - 1] != theChar)
217 {
218 theIndex--;
219 }
220
221 return theIndex == 0 ? theLength : theIndex - 1;
222 }
223 }
224
225
226
227 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
startsWith(const XalanDOMChar * theString,XalanDOMString::size_type theStringLength,const XalanDOMChar * theSubstring,XalanDOMString::size_type theSubstringLength)228 startsWith(
229 const XalanDOMChar* theString,
230 XalanDOMString::size_type theStringLength,
231 const XalanDOMChar* theSubstring,
232 XalanDOMString::size_type theSubstringLength)
233 {
234 if (theSubstringLength == 0)
235 {
236 // Make this work like Java...
237 return true;
238 }
239 else if (theStringLength < theSubstringLength)
240 {
241 return false;
242 }
243 else
244 {
245 XalanDOMString::size_type i = 0;
246
247 // Compare each character...
248 for (;
249 i < theSubstringLength &&
250 theString[i] == theSubstring[i];
251 ++i)
252 {
253 ;
254 }
255
256 // If we've gotten to the end of the substring, then
257 // return true.
258 if (i == theSubstringLength)
259 {
260 return true;
261 }
262 else
263 {
264 return false;
265 }
266 }
267 }
268
269
270
271 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
endsWith(const XalanDOMChar * theString,XalanDOMString::size_type theStringLength,const XalanDOMChar * theSubstring,XalanDOMString::size_type theSubstringLength)272 endsWith(
273 const XalanDOMChar* theString,
274 XalanDOMString::size_type theStringLength,
275 const XalanDOMChar* theSubstring,
276 XalanDOMString::size_type theSubstringLength)
277 {
278 assert(theString != 0);
279 assert(theSubstring != 0);
280
281 bool fResult = false;
282
283 // If the substring is longer, there's no point in continuing.
284 if (theSubstringLength > 0 && theStringLength >= theSubstringLength)
285 {
286 XalanDOMString::size_type i = theStringLength;
287 XalanDOMString::size_type j = theSubstringLength;
288
289 // Compare each character...
290 for (;
291 j > 0 &&
292 theString[i - 1] == theSubstring[j - 1];
293 --j, --i)
294 {
295 ;
296 }
297
298 // If we've gotten to the beginning of the substring, then
299 // return true.
300 if (j == 0)
301 {
302 fResult = true;
303 }
304 }
305
306 return fResult;
307 }
308
309
310
311 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(XalanOutputStream & theStream,const CharVectorType & theString)312 OutputString(XalanOutputStream& theStream,
313 const CharVectorType& theString)
314 {
315 if (theString.empty() == false)
316 {
317 theStream.write(c_str(theString));
318 }
319 }
320
321
322
323 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(std::ostream & theStream,const CharVectorType & theString)324 OutputString(
325 std::ostream& theStream,
326 const CharVectorType& theString)
327 {
328 if (theString.empty() == false)
329 {
330 assert(
331 static_cast<XMLUInt64>(static_cast<std::streamsize>(theString.size())) == theString.size());
332
333 theStream.write(
334 &*theString.begin(),
335 static_cast<std::streamsize>(theString.size()));
336 }
337 }
338
339
340
341 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(XalanOutputStream & theStream,const XalanDOMChar * theString)342 OutputString(XalanOutputStream& theStream,
343 const XalanDOMChar* theString)
344 {
345 if (theString != 0)
346 {
347 theStream.write(theString);
348 }
349 }
350
351
352
353 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
OutputString(std::ostream & theStream,const XalanDOMChar * theString,MemoryManager & theMemoryManager)354 OutputString(
355 std::ostream& theStream,
356 const XalanDOMChar* theString,
357 MemoryManager& theMemoryManager)
358 {
359 CharVectorType theVector(theMemoryManager);
360
361 TranscodeToLocalCodePage(theString, theVector, false, '?');
362
363 OutputString(theStream, theVector);
364 }
365
366
367
368
369 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
substring(const XalanDOMChar * theString,XalanDOMString & theSubstring,XalanDOMString::size_type theStartIndex,XalanDOMString::size_type theEndIndex)370 substring(
371 const XalanDOMChar* theString,
372 XalanDOMString& theSubstring,
373 XalanDOMString::size_type theStartIndex,
374 XalanDOMString::size_type theEndIndex)
375 {
376 assert(theString != 0);
377
378 const XalanDOMString::size_type theStringLength = length(theString);
379
380 // $$$ ToDo: In Java-land, any failing of this
381 // assertion would result in an exception being thrown.
382 assert(theStartIndex <= theStringLength);
383
384 if (theStartIndex == theStringLength)
385 {
386 // This is allowed, and should return an empty string.
387 theSubstring.clear();
388 }
389 else
390 {
391 const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
392 theEndIndex - theStartIndex;
393 assert(theStartIndex + theLength <= theStringLength);
394
395 theSubstring.assign(theString + theStartIndex, theLength);
396 }
397
398 return theSubstring;
399 }
400
401
402
403 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
substring(const XalanDOMString & theString,XalanDOMString & theSubstring,XalanDOMString::size_type theStartIndex,XalanDOMString::size_type theEndIndex)404 substring(
405 const XalanDOMString& theString,
406 XalanDOMString& theSubstring,
407 XalanDOMString::size_type theStartIndex,
408 XalanDOMString::size_type theEndIndex)
409 {
410 const XalanDOMString::size_type theStringLength = theString.length();
411
412 assert(theStartIndex <= theStringLength);
413
414 if (theStartIndex == theStringLength)
415 {
416 // This is allowed, and should return an empty string.
417 theSubstring.clear();
418 }
419 else
420 {
421 const XalanDOMString::size_type theLength = theEndIndex == XalanDOMString::npos ? theStringLength - theStartIndex :
422 theEndIndex - theStartIndex;
423
424 if (theLength == 0)
425 {
426 theSubstring.clear();
427 }
428 else
429 {
430 assert(theStartIndex + theLength <= theStringLength);
431
432 theString.substr(theSubstring, theStartIndex, theLength);
433 }
434 }
435 }
436
437
438 template <class InputIteratorType, class OutputIteratorType, class FunctionType>
439 OutputIteratorType
440 TransformString(
441 InputIteratorType theInputBegin,
442 InputIteratorType theInputEnd,
443 OutputIteratorType theOutputIterator,
444 FunctionType theFunction)
445 {
446 return std::transform(
447 theInputBegin,
448 theInputEnd,
449 theOutputIterator,
450 theFunction);
451 }
452
453
454
455 template <class FunctionType>
456 XalanDOMString&
TransformString(const XalanDOMChar * theInputString,XalanDOMString::size_type theInputStringLength,FunctionType theFunction,XalanDOMString & theConvertedString)457 TransformString(
458 const XalanDOMChar* theInputString,
459 XalanDOMString::size_type theInputStringLength,
460 FunctionType theFunction,
461 XalanDOMString& theConvertedString)
462 {
463 assert(theInputString != 0);
464
465 TransformString(
466 theInputString,
467 theInputString + theInputStringLength,
468 std::back_inserter(theConvertedString),
469 theFunction);
470
471 return theConvertedString;
472 }
473
474
475
476 template <class FunctionType>
477 XalanDOMString&
TransformXalanDOMString(const XalanDOMString & theInputString,FunctionType theFunction,XalanDOMString & theResult)478 TransformXalanDOMString(
479 const XalanDOMString& theInputString,
480 FunctionType theFunction,
481 XalanDOMString& theResult)
482 {
483 const XalanDOMString::size_type theStringLength = theInputString.length();
484
485 if (theStringLength == 0)
486 {
487 theResult = theInputString;
488 }
489 else
490 {
491 const XalanDOMChar* const theBuffer = theInputString.c_str();
492 assert(theBuffer != 0);
493
494 TransformString(theBuffer, theStringLength, theFunction, theResult);
495 }
496
497 return theResult;
498 }
499
500
501
502 template <class FunctionType>
503 XalanDOMString&
TransformString(FunctionType theFunction,XalanDOMString & theString)504 TransformString(
505 FunctionType theFunction,
506 XalanDOMString& theString)
507 {
508 TransformString(
509 theString.begin(),
510 theString.end(),
511 theString.begin(),
512 theFunction);
513
514 return theString;
515 }
516
517
518
519 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toLowerCaseASCII(const XalanDOMChar * theString,XalanDOMString & theResult)520 toLowerCaseASCII(
521 const XalanDOMChar* theString,
522 XalanDOMString& theResult)
523 {
524 TransformString(theString, length(theString), toLowerASCII, theResult);
525
526 return theResult;
527 }
528
529
530
531 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toLowerCaseASCII(const XalanDOMString & theString,XalanDOMString & theResult)532 toLowerCaseASCII(
533 const XalanDOMString& theString,
534 XalanDOMString& theResult)
535 {
536 TransformXalanDOMString(theString, toLowerASCII, theResult);
537
538 return theResult;
539 }
540
541
542
543 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toLowerCaseASCII(XalanDOMString & theString)544 toLowerCaseASCII(XalanDOMString& theString)
545 {
546 TransformString(toLowerASCII, theString);
547
548 return theString;
549 }
550
551
552
553
554 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toUpperCaseASCII(const XalanDOMChar * theString,XalanDOMString & theResult)555 toUpperCaseASCII(
556 const XalanDOMChar* theString,
557 XalanDOMString& theResult)
558 {
559 TransformString(theString, length(theString), toUpperASCII, theResult);
560
561 return theResult;
562 }
563
564
565
566 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toUpperCaseASCII(const XalanDOMString & theString,XalanDOMString & theResult)567 toUpperCaseASCII(
568 const XalanDOMString& theString,
569 XalanDOMString& theResult)
570 {
571 TransformXalanDOMString(theString, toUpperASCII, theResult);
572
573 return theResult;
574 }
575
576
577
578 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
toUpperCaseASCII(XalanDOMString & theString)579 toUpperCaseASCII(XalanDOMString& theString)
580 {
581 TransformString(toUpperASCII, theString);
582
583 return theString;
584 }
585
586
587
588 template <class InputCharType, class OutputCharType>
589 class IdentityTransform
590 {
591 public:
592
593 OutputCharType
operator ()(InputCharType theChar) const594 operator()(InputCharType theChar) const
595 {
596 return OutputCharType(theChar);
597 }
598 };
599
600
601
602 template <class CharType>
603 class CaseFlipTransform
604 {
605 public:
606
607 CharType
operator ()(CharType theChar) const608 operator()(CharType theChar) const
609 {
610 return flipCaseASCII(theChar);
611 }
612 };
613
614
615
616 template<class InputCharType, class OutputCharType>
617 IdentityTransform<InputCharType, OutputCharType>
makeIdentityTransform(const InputCharType *,const OutputCharType *)618 makeIdentityTransform(
619 const InputCharType*,
620 const OutputCharType*)
621 {
622 return IdentityTransform<InputCharType, OutputCharType>();
623 }
624
625
626
627 IdentityTransform<char, char>
makeCharIdentityTransform()628 makeCharIdentityTransform()
629 {
630 char theDummy;
631
632 return makeIdentityTransform(&theDummy, &theDummy);
633 }
634
635
636 IdentityTransform<XalanDOMChar, XalanDOMChar>
makeXalanDOMCharIdentityTransform()637 makeXalanDOMCharIdentityTransform()
638 {
639 XalanDOMChar theDummy;
640
641 return makeIdentityTransform(&theDummy, &theDummy);
642 }
643
644
645 template <class Type, class SizeType, class FunctionType>
646 int
doCompare(const Type * theLHS,SizeType theLHSLength,const Type * theRHS,SizeType theRHSLength,FunctionType theTransformFunction)647 doCompare(
648 const Type* theLHS,
649 SizeType theLHSLength,
650 const Type* theRHS,
651 SizeType theRHSLength,
652 FunctionType theTransformFunction)
653 {
654 // We don't really have to order, so save some time...
655 if (theLHSLength < theRHSLength)
656 {
657 return -1;
658 }
659 else if (theRHSLength < theLHSLength)
660 {
661 return 1;
662 }
663 else
664 {
665 Type theLHSChar = Type(0);
666 Type theRHSChar = Type(0);
667
668 for(SizeType i = 0; i < theLHSLength; i++)
669 {
670 theLHSChar = theTransformFunction(theLHS[i]);
671 theRHSChar = theTransformFunction(theRHS[i]);
672
673 if (theLHSChar != theRHSChar)
674 {
675 break;
676 }
677 }
678
679 return int(theLHSChar - theRHSChar);
680 }
681 }
682
683
684
685 template <class Type, class SizeType, class FunctionType>
686 int
doCollationCompare(const Type * theLHS,SizeType theLHSLength,const Type * theRHS,SizeType theRHSLength,FunctionType theTransformFunction)687 doCollationCompare(
688 const Type* theLHS,
689 SizeType theLHSLength,
690 const Type* theRHS,
691 SizeType theRHSLength,
692 FunctionType theTransformFunction)
693 {
694 int theResult = 0;
695
696 if (theLHSLength != 0 || theRHSLength != 0)
697 {
698 Type theLHSChar = Type(0);
699 Type theRHSChar = Type(0);
700
701 SizeType i = 0;
702
703 for(; i < theLHSLength && i < theRHSLength; i++)
704 {
705 theLHSChar = theTransformFunction(theLHS[i]);
706 theRHSChar = theTransformFunction(theRHS[i]);
707
708 if (theLHSChar != theRHSChar)
709 {
710 break;
711 }
712 }
713
714 if (i == theLHSLength)
715 {
716 // We reached the end of theLHS...
717 if (i != theRHSLength)
718 {
719 // but not the end of theRHS.
720 theResult = -1;
721 }
722 }
723 else if (i == theRHSLength)
724 {
725 // We reached the end of theRHS string...
726 if (i != theLHSLength)
727 {
728 // but not the end of theLHS string.
729 theResult = 1;
730 }
731 }
732 else
733 {
734 // We didn't reach the end of _either_ string, so
735 // return the difference between the two characters
736 // that caused the problem.
737 theResult = theLHSChar - theRHSChar;
738 }
739 }
740
741 return theResult;
742 }
743
744
745
746 template <class Type, class FunctionType>
747 int
doCollationCompare(const Type * theLHS,const Type * theRHS,FunctionType theTransformFunction)748 doCollationCompare(
749 const Type* theLHS,
750 const Type* theRHS,
751 FunctionType theTransformFunction)
752 {
753 assert(theLHS != 0);
754 assert(theRHS != 0);
755
756 size_t i = 0;
757
758 Type theLHSChar;
759 Type theRHSChar;
760
761 for (;;)
762 {
763 theLHSChar = theTransformFunction(theLHS[i]);
764 theRHSChar = theTransformFunction(theRHS[i]);
765
766 if (theLHSChar == static_cast<Type>(0) ||
767 theLHSChar != theRHSChar)
768 {
769 break;
770 }
771 else
772 {
773 ++i;
774 }
775 }
776
777 return theLHSChar - theRHSChar;
778 }
779
780
781
782 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compare(const CharVectorType & theLHS,const CharVectorType & theRHS)783 compare(
784 const CharVectorType& theLHS,
785 const CharVectorType& theRHS)
786 {
787 return doCompare(
788 c_str(theLHS),
789 theLHS.size(),
790 c_str(theRHS),
791 theRHS.size(),
792 makeCharIdentityTransform());
793 }
794
795
796
797 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compare(const XalanDOMChar * theLHS,XalanDOMString::size_type theLHSLength,const XalanDOMChar * theRHS,XalanDOMString::size_type theRHSLength)798 compare(
799 const XalanDOMChar* theLHS,
800 XalanDOMString::size_type theLHSLength,
801 const XalanDOMChar* theRHS,
802 XalanDOMString::size_type theRHSLength)
803 {
804 return doCompare(
805 theLHS,
806 theLHSLength,
807 theRHS,
808 theRHSLength,
809 makeXalanDOMCharIdentityTransform());
810 }
811
812
813
814 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
compareIgnoreCaseASCII(const XalanDOMChar * theLHS,XalanDOMString::size_type theLHSLength,const XalanDOMChar * theRHS,XalanDOMString::size_type theRHSLength)815 compareIgnoreCaseASCII(
816 const XalanDOMChar* theLHS,
817 XalanDOMString::size_type theLHSLength,
818 const XalanDOMChar* theRHS,
819 XalanDOMString::size_type theRHSLength)
820 {
821 return doCompare(
822 theLHS,
823 theLHSLength,
824 theRHS,
825 theRHSLength,
826 toUpperASCII);
827 }
828
829
830
831 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
collationCompare(const XalanDOMChar * theLHS,XalanDOMString::size_type theLHSLength,const XalanDOMChar * theRHS,XalanDOMString::size_type theRHSLength)832 collationCompare(
833 const XalanDOMChar* theLHS,
834 XalanDOMString::size_type theLHSLength,
835 const XalanDOMChar* theRHS,
836 XalanDOMString::size_type theRHSLength)
837 {
838 return doCollationCompare(
839 theLHS,
840 theLHSLength,
841 theRHS,
842 theRHSLength,
843 makeXalanDOMCharIdentityTransform());
844 }
845
846
847
848 #if defined(XALAN_USE_WINDOWS_COLLATION)
849 static _locale_t s_locale;
850 #endif
851
852 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
collationCompare(const XalanDOMChar * theLHS,const XalanDOMChar * theRHS)853 collationCompare(
854 const XalanDOMChar* theLHS,
855 const XalanDOMChar* theRHS)
856 {
857 #if defined(XALAN_USE_WINDOWS_COLLATION)
858 return _wcscoll_l(reinterpret_cast<const wchar_t *>(theLHS), reinterpret_cast<const wchar_t *>(theRHS), s_locale);
859 #else
860 return doCollationCompare(
861 theLHS,
862 theRHS,
863 makeXalanDOMCharIdentityTransform());
864 #endif
865 }
866
867
868
869
870 template <class Type, class SizeType, class FunctionType>
871 bool
doEquals(const Type * theLHS,const Type * theRHS,SizeType theLength,FunctionType theTransformFunction)872 doEquals(
873 const Type* theLHS,
874 const Type* theRHS,
875 SizeType theLength,
876 FunctionType theTransformFunction)
877 {
878 assert(theLHS != 0 && theRHS != 0);
879
880 if (theLength == 0)
881 {
882 return true;
883 }
884 else
885 {
886 const Type* const theEnd = theLHS + theLength;
887
888 while(theTransformFunction(*theLHS) == theTransformFunction(*theRHS))
889 {
890 ++theLHS;
891
892 if (theLHS == theEnd)
893 {
894 return true;
895 }
896 else
897 {
898 ++theRHS;
899 }
900 }
901
902 return false;
903 }
904 }
905
906
907
908 template <class Type, class SizeType, class FunctionType>
909 bool
doEqualsIgnoreCase(const Type * theLHS,const Type * theRHS,SizeType theLength,FunctionType theToUpperFunction)910 doEqualsIgnoreCase(
911 const Type* theLHS,
912 const Type* theRHS,
913 SizeType theLength,
914 FunctionType theToUpperFunction)
915 {
916 // Check each character, converting to uppercase
917 // for the test.
918 for(SizeType i = 0; i < theLength; i++)
919 {
920 const Type charLHS = theLHS[i];
921 const Type charRHS = theRHS[i];
922
923 if (charLHS != charRHS &&
924 Type(theToUpperFunction(charLHS)) != charRHS &&
925 charLHS != Type(theToUpperFunction(charRHS)))
926 {
927 return false;
928 }
929 }
930
931 return true;
932 }
933
934
935
936 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
equals(const XalanDOMChar * theLHS,const XalanDOMChar * theRHS,XalanDOMString::size_type theLength)937 equals(
938 const XalanDOMChar* theLHS,
939 const XalanDOMChar* theRHS,
940 XalanDOMString::size_type theLength)
941 {
942 return doEquals(
943 theLHS,
944 theRHS,
945 theLength,
946 makeXalanDOMCharIdentityTransform());
947 }
948
949
950
951 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
equalsIgnoreCaseASCII(const XalanDOMChar * theLHS,const XalanDOMChar * theRHS,XalanDOMString::size_type theLength)952 equalsIgnoreCaseASCII(
953 const XalanDOMChar* theLHS,
954 const XalanDOMChar* theRHS,
955 XalanDOMString::size_type theLength)
956 {
957 return doEqualsIgnoreCase(
958 theLHS,
959 theRHS,
960 theLength,
961 toUpperASCII);
962 }
963
964
965
966 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMCharVectorType&)
MakeXalanDOMCharVector(const char * data,XalanDOMCharVectorType & theResult,bool fTranscode)967 MakeXalanDOMCharVector(
968 const char* data,
969 XalanDOMCharVectorType& theResult,
970 bool fTranscode)
971 {
972 assert(data != 0);
973
974 if (fTranscode == true)
975 {
976 // Create a vector which includes the terminating 0.
977 TranscodeFromLocalCodePage(data, theResult, true);
978 }
979 else
980 {
981 // Include the terminating null byte...
982 const XalanDOMString::size_type theLength = XalanDOMString::length(data) + 1;
983
984 theResult.reserve(theLength);
985
986 std::copy(
987 data,
988 data + theLength,
989 std::back_inserter(theResult));
990 }
991
992 return theResult;
993 }
994
995
996
997 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMCharVectorType&)
MakeXalanDOMCharVector(const XalanDOMChar * data,XalanDOMCharVectorType & theResult)998 MakeXalanDOMCharVector(const XalanDOMChar* data,
999 XalanDOMCharVectorType& theResult)
1000 {
1001 assert(data != 0);
1002
1003 const XalanDOMString::size_type theLength = length(data);
1004
1005 XalanDOMCharVectorType tmpVector(data, data + theLength + 1,theResult.getMemoryManager());
1006
1007 theResult.swap(tmpVector);
1008 // Create a vector which includes the terminating 0.
1009 return theResult;
1010 }
1011
1012
1013
1014 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
CopyWideStringToVector(const XalanDOMChar * theString,CharVectorType & theVector)1015 CopyWideStringToVector(
1016 const XalanDOMChar* theString,
1017 CharVectorType& theVector)
1018 {
1019 const XalanDOMString::size_type theLength = length(theString);
1020
1021 if (theLength != 0)
1022 {
1023 theVector.reserve(theVector.size() + theLength + 1);
1024
1025 for(XalanDOMString::size_type i = 0; i < theLength; i++)
1026 {
1027 // Assert that the truncation will not affect the resulting character.
1028 assert(theString[i] == char(theString[i]));
1029
1030 theVector.push_back(char(theString[i]));
1031 }
1032
1033 // Put a terminating 0 byte.
1034 theVector.push_back(0);
1035 }
1036 }
1037
1038
1039
1040 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(void)
CopyStringToVector(const char * theString,CharVectorType & theVector)1041 CopyStringToVector(
1042 const char* theString,
1043 CharVectorType& theVector)
1044 {
1045 theVector.insert(
1046 theVector.end(),
1047 theString,
1048 theString + XalanDOMString::length(theString) + 1);
1049 }
1050
1051
1052
1053 template <class Type>
1054 Type
WideStringToIntegral(const XalanDOMChar * theString,Type)1055 WideStringToIntegral(
1056 const XalanDOMChar* theString,
1057 Type /* theDummy */)
1058 {
1059 if (theString == 0 || DoubleSupport::isValid(theString) == false)
1060 {
1061 return Type(0);
1062 }
1063 else
1064 {
1065 // OK, now we know we have a valid string, so start converting...
1066 Type theResult = 0;
1067
1068 // Consume any leading whitespace (which we allow)
1069 while(isXMLWhitespace(*theString) == true)
1070 {
1071 ++theString;
1072 }
1073
1074 const bool isNegative = *theString == XalanUnicode::charHyphenMinus ? true : false;
1075
1076 if (isNegative == true)
1077 {
1078 ++theString;
1079 }
1080
1081 while(*theString != 0)
1082 {
1083 if (*theString >= XalanUnicode::charDigit_0 && *theString <= XalanUnicode::charDigit_9)
1084 {
1085 theResult *= 10;
1086
1087 theResult += *theString - XalanUnicode::charDigit_0;
1088
1089 ++theString;
1090 }
1091 else if (isXMLWhitespace(*theString) == true)
1092 {
1093 // This must be trailing whitespace...
1094 break;
1095 }
1096 else
1097 {
1098 // An non-numeric character was encountered, so stop...
1099 return 0;
1100 }
1101 }
1102
1103 return isNegative == true ? -theResult : theResult;
1104 }
1105 }
1106
1107
1108
1109 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(int)
WideStringToInt(const XalanDOMChar * theString)1110 WideStringToInt(const XalanDOMChar* theString)
1111 {
1112 return WideStringToIntegral(theString, int(0));
1113 }
1114
1115
1116
1117 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(long)
WideStringToLong(const XalanDOMChar * theString)1118 WideStringToLong(const XalanDOMChar* theString)
1119 {
1120 return WideStringToIntegral(theString, long(0));
1121 }
1122
1123
1124
1125 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(unsigned long)
WideStringToUnsignedLong(const XalanDOMChar * theString)1126 WideStringToUnsignedLong(const XalanDOMChar* theString)
1127 {
1128 return WideStringToIntegral(theString, (unsigned long)0);
1129 }
1130
1131
1132
1133 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(double)
WideStringToDouble(const XalanDOMChar * theString,MemoryManager & theManager)1134 WideStringToDouble(
1135 const XalanDOMChar* theString,
1136 MemoryManager& theManager)
1137 {
1138 return DoubleSupport::toDouble(theString, theManager);
1139 }
1140
1141
1142
1143 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
trim(const XalanDOMString & theString,XalanDOMString & theResult)1144 trim(
1145 const XalanDOMString& theString,
1146 XalanDOMString& theResult)
1147 {
1148 if (theString.empty())
1149 {
1150 theResult.erase();
1151 return theResult;
1152 }
1153
1154 const XalanDOMString::size_type strLen = theString.length();
1155 assert(strLen > 0);
1156
1157 // index of first non-whitespace character
1158 XalanDOMString::size_type leadingSpace = 0;
1159
1160 for (; leadingSpace < strLen; ++leadingSpace)
1161 if (!isXMLWhitespace(theString[leadingSpace]))
1162 break;
1163
1164 // index of last non-whitespace character
1165 XalanDOMString::size_type trailingSpace = strLen -1;
1166
1167 for (; trailingSpace > 0; --trailingSpace)
1168 if (!isXMLWhitespace(theString[trailingSpace]))
1169 break;
1170
1171 substring(theString, theResult, leadingSpace, trailingSpace + 1);
1172
1173 return theResult;
1174 }
1175
1176
1177
1178 // A very cheap decimal number transcoder...
1179 template <class InputCharType, class OutputCharType>
1180 class DecimalNumberTranscodeTransform
1181 {
1182 public:
1183
1184 OutputCharType
operator ()(InputCharType theChar) const1185 operator()(InputCharType theChar) const
1186 {
1187 switch(theChar)
1188 {
1189 case '-':
1190 return OutputCharType(XalanUnicode::charHyphenMinus);
1191 break;
1192
1193 case '.':
1194 return OutputCharType(XalanUnicode::charFullStop);
1195 break;
1196
1197 case '0':
1198 return OutputCharType(XalanUnicode::charDigit_0);
1199 break;
1200
1201 case '1':
1202 return OutputCharType(XalanUnicode::charDigit_1);
1203 break;
1204
1205 case '2':
1206 return OutputCharType(XalanUnicode::charDigit_2);
1207 break;
1208
1209 case '3':
1210 return OutputCharType(XalanUnicode::charDigit_3);
1211 break;
1212
1213 case '4':
1214 return OutputCharType(XalanUnicode::charDigit_4);
1215 break;
1216
1217 case '5':
1218 return OutputCharType(XalanUnicode::charDigit_5);
1219 break;
1220
1221 case '6':
1222 return OutputCharType(XalanUnicode::charDigit_6);
1223 break;
1224
1225 case '7':
1226 return OutputCharType(XalanUnicode::charDigit_7);
1227 break;
1228
1229 case '8':
1230 return OutputCharType(XalanUnicode::charDigit_8);
1231 break;
1232
1233 case '9':
1234 return OutputCharType(XalanUnicode::charDigit_9);
1235 break;
1236
1237 default:
1238 return OutputCharType(0);
1239 break;
1240 }
1241 }
1242 };
1243
1244
1245
1246 template<class InputCharType, class OutputCharType>
1247 DecimalNumberTranscodeTransform<InputCharType, OutputCharType>
makeDecimalNumberTranscodeTransform(const InputCharType *,const OutputCharType *)1248 makeDecimalNumberTranscodeTransform(
1249 const InputCharType*,
1250 const OutputCharType*)
1251 {
1252 return DecimalNumberTranscodeTransform<InputCharType, OutputCharType>();
1253 }
1254
1255
1256
1257 // A very cheap hex number transcoder...
1258 template <class InputCharType, class OutputCharType>
1259 class HexadecimalNumberTranscodeTransform : public DecimalNumberTranscodeTransform<InputCharType, OutputCharType>
1260 {
1261 public:
1262
1263 typedef DecimalNumberTranscodeTransform<InputCharType, OutputCharType> BaseClassType;
1264
1265 OutputCharType
operator ()(InputCharType theChar) const1266 operator()(InputCharType theChar) const
1267 {
1268 switch(theChar)
1269 {
1270 case 'A':
1271 return OutputCharType(XalanUnicode::charLetter_A);
1272 break;
1273
1274 case 'a':
1275 return OutputCharType(XalanUnicode::charLetter_a);
1276 break;
1277
1278 case 'B':
1279 return OutputCharType(XalanUnicode::charLetter_B);
1280 break;
1281
1282 case 'b':
1283 return OutputCharType(XalanUnicode::charLetter_b);
1284 break;
1285
1286 case 'C':
1287 return OutputCharType(XalanUnicode::charLetter_C);
1288 break;
1289
1290 case 'c':
1291 return OutputCharType(XalanUnicode::charLetter_c);
1292 break;
1293
1294 case 'D':
1295 return OutputCharType(XalanUnicode::charLetter_D);
1296 break;
1297
1298 case 'd':
1299 return OutputCharType(XalanUnicode::charLetter_d);
1300 break;
1301
1302 case 'E':
1303 return OutputCharType(XalanUnicode::charLetter_E);
1304 break;
1305
1306 case 'e':
1307 return OutputCharType(XalanUnicode::charLetter_e);
1308 break;
1309
1310 case 'F':
1311 return OutputCharType(XalanUnicode::charLetter_F);
1312 break;
1313
1314 case 'f':
1315 return OutputCharType(XalanUnicode::charLetter_f);
1316 break;
1317
1318 default:
1319 return BaseClassType::operator()(theChar);
1320 break;
1321 }
1322 }
1323 };
1324
1325
1326
1327 template <class InputIteratorType, class OutputIteratorType>
1328 OutputIteratorType
TranscodeNumber(InputIteratorType theInputBegin,InputIteratorType theInputEnd,OutputIteratorType theOutputIterator)1329 TranscodeNumber(
1330 InputIteratorType theInputBegin,
1331 InputIteratorType theInputEnd,
1332 OutputIteratorType theOutputIterator)
1333 {
1334 return TransformString(
1335 theInputBegin,
1336 theInputEnd,
1337 theOutputIterator,
1338 #if defined(XALAN_NON_ASCII_PLATFORM)
1339 HexadecimalNumberTranscodeTransform<char, XalanDOMChar>());
1340 #else
1341 IdentityTransform<char, XalanDOMChar>());
1342 #endif
1343 }
1344
1345
1346
1347 static const char* const thePrintfStrings[] =
1348 {
1349 "%.10f",
1350 "%.11f",
1351 "%.12f",
1352 "%.13f",
1353 "%.14f",
1354 "%.15f",
1355 "%.16f",
1356 "%.17f",
1357 "%.18f",
1358 "%.19f",
1359 "%.20f",
1360 "%.21f",
1361 "%.22f",
1362 "%.23f",
1363 "%.24f",
1364 "%.25f",
1365 "%.26f",
1366 "%.27f",
1367 "%.28f",
1368 "%.29f",
1369 "%.30f",
1370 "%.31f",
1371 "%.32f",
1372 "%.33f",
1373 "%.34f",
1374 "%.35f",
1375 0
1376 };
1377
1378
1379
1380
1381 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
PointerToDOMString(const void * theValue,XalanDOMString & theResult)1382 PointerToDOMString(
1383 const void* theValue,
1384 XalanDOMString& theResult)
1385 {
1386 char theBuffer[MAX_PRINTF_DIGITS + 1];
1387
1388 using std::sprintf;;
1389
1390 const int theCharsWritten = sprintf(theBuffer, "%p", theValue);
1391 assert(theCharsWritten != 0);
1392
1393 theResult.reserve(theResult.length() + theCharsWritten);
1394
1395 TranscodeNumber(
1396 theBuffer,
1397 theBuffer + theCharsWritten,
1398 std::back_inserter(theResult));
1399
1400 return theResult;
1401 }
1402
1403
1404
1405 void
NumberToCharacters(double theValue,FormatterListener & formatterListener,MemberFunctionPtr function)1406 DOMStringHelper::NumberToCharacters(
1407 double theValue,
1408 FormatterListener& formatterListener,
1409 MemberFunctionPtr function)
1410 {
1411 if (DoubleSupport::isNaN(theValue) == true)
1412 {
1413 (formatterListener.*function)(
1414 theNaNString,
1415 sizeof(theNaNString) / sizeof(theNaNString[0]) - 1);
1416 }
1417 else if (DoubleSupport::isPositiveInfinity(theValue) == true)
1418 {
1419 (formatterListener.*function)(
1420 thePositiveInfinityString,
1421 sizeof(thePositiveInfinityString) / sizeof(thePositiveInfinityString[0]) - 1);
1422 }
1423 else if (DoubleSupport::isNegativeInfinity(theValue) == true)
1424 {
1425 (formatterListener.*function)(
1426 theNegativeInfinityString,
1427 sizeof(theNegativeInfinityString) / sizeof(theNegativeInfinityString[0]) - 1);
1428 }
1429 else if (DoubleSupport::isPositiveZero(theValue) == true ||
1430 DoubleSupport::isNegativeZero(theValue) == true)
1431 {
1432 (formatterListener.*function)(
1433 theZeroString,
1434 sizeof(theZeroString) / sizeof(theZeroString[0]) - 1);
1435 }
1436 else if (static_cast<XMLInt64>(theValue) == theValue)
1437 {
1438 NumberToCharacters(static_cast<XMLInt64>(theValue), formatterListener, function);
1439 }
1440 else
1441 {
1442 char theBuffer[MAX_PRINTF_DIGITS + 1];
1443
1444 using std::sprintf;
1445 using std::atof;
1446 using std::isdigit;
1447
1448 const char* const * thePrintfString = thePrintfStrings;
1449
1450 int theCharsWritten = 0;
1451
1452 do
1453 {
1454 theCharsWritten = sprintf(theBuffer, *thePrintfString, theValue);
1455 assert(theCharsWritten != 0);
1456
1457 ++thePrintfString;
1458 }
1459 while(atof(theBuffer) != theValue && *thePrintfString != 0);
1460
1461 // First, cleanup the output to conform to the XPath standard,
1462 // which says no trailing '0's for the decimal portion.
1463 // So start with the last digit, and search until we find
1464 // the last correct character for the output.
1465 // Also, according to the XPath standard, any values without
1466 // a fractional part are printed as integers. There's always
1467 // a decimal point, so we have to strip stuff away...
1468
1469 // Now, move back while there are zeros...
1470 while(theBuffer[--theCharsWritten] == '0')
1471 {
1472 }
1473
1474 int theCurrentIndex = theCharsWritten;
1475
1476 // If a decimal point stopped the loop, then
1477 // we don't want to preserve it. Otherwise,
1478 // another digit stopped the loop, so we must
1479 // preserve it.
1480 if(isdigit(theBuffer[theCharsWritten]))
1481 {
1482 ++theCharsWritten;
1483 }
1484
1485 // Some other character other than '.' can be the
1486 // separator. This can happen if the locale is
1487 // not the "C" locale, etc. If that's the case,
1488 // replace it with '.'.
1489 while(theCurrentIndex > 0)
1490 {
1491 if (isdigit(theBuffer[theCurrentIndex]))
1492 {
1493 --theCurrentIndex;
1494 }
1495 else
1496 {
1497 if (theBuffer[theCurrentIndex] != '.')
1498 {
1499 theBuffer[theCurrentIndex] = '.';
1500 }
1501
1502 break;
1503 }
1504 }
1505
1506 XalanDOMChar theResult[MAX_PRINTF_DIGITS + 1];
1507
1508 TranscodeNumber(
1509 theBuffer,
1510 theBuffer + theCharsWritten,
1511 &theResult[0]);
1512
1513 (formatterListener.*function)(
1514 theResult,
1515 theCharsWritten);
1516 }
1517 }
1518
1519
1520
1521 template <class ScalarType>
1522 XalanDOMChar*
ScalarToDecimalString(ScalarType theValue,XalanDOMChar * theOutput)1523 ScalarToDecimalString(
1524 ScalarType theValue,
1525 XalanDOMChar* theOutput)
1526 {
1527 // Null terminate it...
1528 *theOutput = 0;
1529
1530 if (theValue < 0)
1531 {
1532 do
1533 {
1534 *--theOutput = XalanDOMChar(-(theValue % 10) + XalanUnicode::charDigit_0);
1535
1536 // OK, we're done with it...
1537 theValue /= 10;
1538 }
1539 while(theValue != 0);
1540
1541 *--theOutput = XalanUnicode::charHyphenMinus;
1542 }
1543 else
1544 {
1545 do
1546 {
1547 *--theOutput = XalanDOMChar(theValue % 10 + XalanUnicode::charDigit_0);
1548
1549 // OK, we're done with it...
1550 theValue /= 10;
1551 }
1552 while(theValue != 0);
1553 }
1554
1555 return theOutput;
1556 }
1557
1558
1559
1560 template <class ScalarType>
1561 XalanDOMString&
ScalarToDecimalString(ScalarType theValue,XalanDOMString & theResult)1562 ScalarToDecimalString(
1563 ScalarType theValue,
1564 XalanDOMString& theResult)
1565 {
1566 // We don't need to transcode, so just make it a
1567 // wide character string...
1568 XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
1569
1570 XalanDOMChar* const theEnd = &theBuffer[MAX_PRINTF_DIGITS];
1571
1572 XalanDOMChar* const theBegin = ScalarToDecimalString(theValue, theEnd);
1573
1574 theResult.append(
1575 theBegin,
1576 XalanDOMString::size_type(theEnd - theBegin));
1577
1578 return theResult;
1579 }
1580
1581
1582
1583 template <class ScalarType>
1584 XalanDOMChar*
UnsignedScalarToHexadecimalString(ScalarType theValue,XalanDOMChar * theOutput)1585 UnsignedScalarToHexadecimalString(
1586 ScalarType theValue,
1587 XalanDOMChar* theOutput)
1588 {
1589 if (theValue >= 0)
1590 {
1591 // Null terminate it...
1592 *theOutput = 0;
1593
1594 do
1595 {
1596 // Next spot...
1597 --theOutput;
1598
1599 const ScalarType theTemp = theValue % 16;
1600
1601 // Isolate the left most character.
1602 if (theTemp >= 0 && theTemp <= 9)
1603 {
1604 *theOutput = XalanDOMChar(theTemp + XalanUnicode::charDigit_0);
1605 }
1606 else
1607 {
1608 assert(theTemp >= 10 && theTemp <= 15);
1609
1610 *theOutput = XalanDOMChar(theTemp - 10 + XalanUnicode::charLetter_A);
1611 }
1612
1613 // OK, we're done with it...
1614 theValue /= 16;
1615 }
1616 while(theValue != 0);
1617 }
1618
1619 return theOutput;
1620 }
1621
1622
1623
1624 template <class ScalarType>
1625 XalanDOMString&
UnsignedScalarToHexadecimalString(ScalarType theValue,XalanDOMString & theResult)1626 UnsignedScalarToHexadecimalString(
1627 ScalarType theValue,
1628 XalanDOMString& theResult)
1629 {
1630 if (theValue >= 0)
1631 {
1632 // We don't need to transcode, so just make it a
1633 // wide character string...
1634 XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
1635
1636 XalanDOMChar* const theEnd = &theBuffer[MAX_PRINTF_DIGITS];
1637
1638 XalanDOMChar* const theBegin = UnsignedScalarToHexadecimalString(theValue, theEnd);
1639
1640 theResult.append(
1641 theBegin,
1642 XalanDOMString::size_type(theEnd - theBegin));
1643 }
1644
1645 return theResult;
1646 }
1647
1648
1649
1650 void
NumberToCharacters(XMLInt32 theValue,FormatterListener & formatterListener,MemberFunctionPtr function)1651 DOMStringHelper::NumberToCharacters(
1652 XMLInt32 theValue,
1653 FormatterListener& formatterListener,
1654 MemberFunctionPtr function)
1655 {
1656 XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
1657
1658 const XalanDOMChar* const theResult =
1659 ScalarToDecimalString(
1660 theValue,
1661 &theBuffer[MAX_PRINTF_DIGITS]);
1662
1663 (formatterListener.*function)(theResult, XalanDOMString::length(theResult));
1664 }
1665
1666
1667
1668 void
NumberToCharacters(XMLInt64 theValue,FormatterListener & formatterListener,MemberFunctionPtr function)1669 DOMStringHelper::NumberToCharacters(
1670 XMLInt64 theValue,
1671 FormatterListener& formatterListener,
1672 MemberFunctionPtr function)
1673 {
1674 XalanDOMChar theBuffer[MAX_PRINTF_DIGITS + 1];
1675
1676 const XalanDOMChar* const theResult =
1677 ScalarToDecimalString(
1678 theValue,
1679 &theBuffer[MAX_PRINTF_DIGITS]);
1680
1681 (formatterListener.*function)(theResult, XalanDOMString::length(theResult));
1682 }
1683
1684
1685
1686 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
NumberToDOMString(XMLInt64 theValue,XalanDOMString & theResult)1687 NumberToDOMString(
1688 XMLInt64 theValue,
1689 XalanDOMString& theResult)
1690 {
1691 return ScalarToDecimalString(theValue, theResult);
1692 }
1693
1694
1695
1696 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
NumberToDOMString(XMLUInt64 theValue,XalanDOMString & theResult)1697 NumberToDOMString(
1698 XMLUInt64 theValue,
1699 XalanDOMString& theResult)
1700 {
1701 return ScalarToDecimalString(theValue, theResult);
1702 }
1703
1704
1705
1706 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
NumberToDOMString(double theValue,XalanDOMString & theResult)1707 NumberToDOMString(
1708 double theValue,
1709 XalanDOMString& theResult)
1710 {
1711 if (DoubleSupport::isNaN(theValue) == true)
1712 {
1713 theResult.append(
1714 theNaNString,
1715 sizeof(theNaNString) / sizeof(theNaNString[0]) - 1);
1716 }
1717 else if (DoubleSupport::isPositiveInfinity(theValue) == true)
1718 {
1719 theResult.append(
1720 thePositiveInfinityString,
1721 sizeof(thePositiveInfinityString) / sizeof(thePositiveInfinityString[0]) - 1);
1722 }
1723 else if (DoubleSupport::isNegativeInfinity(theValue) == true)
1724 {
1725 theResult.append(
1726 theNegativeInfinityString,
1727 sizeof(theNegativeInfinityString) / sizeof(theNegativeInfinityString[0]) - 1);
1728 }
1729 else if (DoubleSupport::isPositiveZero(theValue) == true ||
1730 DoubleSupport::isNegativeZero(theValue) == true)
1731 {
1732 theResult.append(
1733 theZeroString,
1734 sizeof(theZeroString) / sizeof(theZeroString[0]) - 1);
1735 }
1736 else if (static_cast<XMLInt64>(theValue) == theValue)
1737 {
1738 NumberToDOMString(static_cast<XMLInt64>(theValue), theResult);
1739 }
1740 else
1741 {
1742 char theBuffer[MAX_PRINTF_DIGITS + 1];
1743
1744 using std::sprintf;
1745 using std::atof;
1746 using std::isdigit;
1747
1748 const char* const * thePrintfString = thePrintfStrings;
1749
1750 int theCharsWritten = 0;
1751
1752 do
1753 {
1754 theCharsWritten = sprintf(theBuffer, *thePrintfString, theValue);
1755 assert(theCharsWritten != 0);
1756
1757 ++thePrintfString;
1758 }
1759 while(atof(theBuffer) != theValue && *thePrintfString != 0);
1760
1761 // First, cleanup the output to conform to the XPath standard,
1762 // which says no trailing '0's for the decimal portion.
1763 // So start with the last digit, and search until we find
1764 // the last correct character for the output.
1765 // Also, according to the XPath standard, any values without
1766 // a fractional part are printed as integers. There's always
1767 // a decimal point, so we have to strip stuff away...
1768
1769 // Now, move back while there are zeros...
1770 while(theBuffer[--theCharsWritten] == '0')
1771 {
1772 }
1773
1774 int theCurrentIndex = theCharsWritten;
1775
1776 // If a decimal point stopped the loop, then
1777 // we don't want to preserve it. Otherwise,
1778 // another digit stopped the loop, so we must
1779 // preserve it.
1780 if(isdigit(theBuffer[theCharsWritten]))
1781 {
1782 ++theCharsWritten;
1783 }
1784
1785 // Some other character other than '.' can be the
1786 // separator. This can happen if the locale is
1787 // not the "C" locale, etc. If that's the case,
1788 // replace it with '.'.
1789 while(theCurrentIndex > 0)
1790 {
1791 if (isdigit(theBuffer[theCurrentIndex]))
1792 {
1793 --theCurrentIndex;
1794 }
1795 else
1796 {
1797 if (theBuffer[theCurrentIndex] != '.')
1798 {
1799 theBuffer[theCurrentIndex] = '.';
1800 }
1801
1802 break;
1803 }
1804 }
1805
1806 theResult.reserve(theResult.length() + theCharsWritten);
1807
1808 TranscodeNumber(
1809 theBuffer,
1810 theBuffer + theCharsWritten,
1811 std::back_inserter(theResult));
1812 }
1813
1814 return theResult;
1815 }
1816
1817
1818
1819
1820 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
NumberToHexDOMString(XMLUInt64 theValue,XalanDOMString & theResult)1821 NumberToHexDOMString(
1822 XMLUInt64 theValue,
1823 XalanDOMString& theResult)
1824 {
1825 return UnsignedScalarToHexadecimalString(theValue, theResult);
1826 }
1827
1828
1829
1830 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(XalanDOMString&)
NumberToHexDOMString(XMLInt64 theValue,XalanDOMString & theResult)1831 NumberToHexDOMString(
1832 XMLInt64 theValue,
1833 XalanDOMString& theResult)
1834 {
1835 return UnsignedScalarToHexadecimalString(theValue, theResult);
1836 }
1837
1838
1839
1840 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
isXMLWhitespace(const XalanDOMString & string)1841 isXMLWhitespace(const XalanDOMString& string)
1842 {
1843 const XalanDOMString::size_type theLength = string.length();
1844
1845 if (theLength == 0)
1846 {
1847 return true;
1848 }
1849 else
1850 {
1851 const XalanDOMChar* const theBuffer =
1852 string.c_str();
1853
1854 assert(theBuffer != 0);
1855
1856 return isXMLWhitespace(theBuffer, 0, theLength);
1857 }
1858 }
1859
1860
1861
1862 XALAN_PLATFORMSUPPORT_EXPORT_FUNCTION(bool)
isXMLWhitespace(const XalanDOMChar ch[],XalanDOMString::size_type start,XalanDOMString::size_type length)1863 isXMLWhitespace(
1864 const XalanDOMChar ch[],
1865 XalanDOMString::size_type start,
1866 XalanDOMString::size_type length)
1867 {
1868 const XalanDOMString::size_type end = start + length;
1869
1870 for(XalanDOMString::size_type s = start; s < end; s++)
1871 {
1872 if (!isXMLWhitespace(ch[s]))
1873 return false;
1874 }
1875
1876 return true;
1877 }
1878
1879
1880
1881 void
initialize(MemoryManager &)1882 DOMStringHelper::initialize(MemoryManager& /* theMemoryManager */)
1883 {
1884 #if defined(XALAN_USE_WINDOWS_COLLATION)
1885 s_locale = _create_locale(LC_COLLATE, "");
1886 #endif
1887 }
1888
1889
1890
1891 void
terminate()1892 DOMStringHelper::terminate()
1893 {
1894 #if defined(XALAN_USE_WINDOWS_COLLATION)
1895 _free_locale(s_locale);
1896 #endif
1897 }
1898
1899
1900
1901 }
1902