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