source: icXML/icXML-devel/src/xercesc/util/XMLUri.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 74.5 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: XMLUri.cpp 881714 2009-11-18 10:39:06Z borisk $
20 */
21
22// ---------------------------------------------------------------------------
23//  Includes
24// ---------------------------------------------------------------------------
25#include <xercesc/util/Janitor.hpp>
26#include <xercesc/util/XMLURL.hpp>
27#include <xercesc/util/XMLUri.hpp>
28#include <xercesc/util/XMLChar.hpp>
29#include <xercesc/util/OutOfMemoryException.hpp>
30
31XERCES_CPP_NAMESPACE_BEGIN
32
33// ---------------------------------------------------------------------------
34//  XMLUri: static data
35// ---------------------------------------------------------------------------
36
37//      Amended by RFC2732
38//      reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
39//                      "$" | "," | "[" | "]"
40//
41const XMLCh XMLUri::RESERVED_CHARACTERS[] =
42{
43    chSemiColon, chForwardSlash, chQuestion, chColon, chAt,
44    chAmpersand, chEqual, chPlus, chDollarSign, chComma, chOpenSquare,
45    chCloseSquare, chNull
46};
47
48//
49//      mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
50//                      "(" | ")"
51//
52const XMLCh XMLUri::MARK_CHARACTERS[] =
53{
54    chDash, chUnderscore, chPeriod, chBang, chTilde,
55    chAsterisk, chSingleQuote, chOpenParen, chCloseParen, chNull
56};
57
58// combination of MARK and RESERVED
59const XMLCh XMLUri::MARK_OR_RESERVED_CHARACTERS[] =
60{
61    chDash, chUnderscore, chPeriod, chBang, chTilde,
62    chAsterisk, chSingleQuote, chOpenParen, chCloseParen,
63    chSemiColon, chForwardSlash, chQuestion, chColon, chAt,
64    chAmpersand, chEqual, chPlus, chDollarSign, chComma, chOpenSquare,
65    chCloseSquare, chNull
66};
67
68//
69//      scheme        = alpha *( alpha | digit | "+" | "-" | "." )
70//
71const XMLCh XMLUri::SCHEME_CHARACTERS[] =
72{
73    chPlus, chDash, chPeriod, chNull
74};
75
76//
77//      userinfo      = *( unreserved | escaped |
78//                         ";" | ":" | "&" | "=" | "+" | "$" | "," )
79//
80const XMLCh XMLUri::USERINFO_CHARACTERS[] =
81{
82    chSemiColon, chColon, chAmpersand, chEqual, chPlus,
83    chDollarSign, chPeriod, chNull
84};
85
86//
87//      reg_name     = 1*( unreserved | escaped | "$" | "," |
88//                         ";" | ":" | "@" | "&" | "=" | "+" )
89//
90const XMLCh XMLUri::REG_NAME_CHARACTERS[] =
91{
92    chDollarSign, chComma, chSemiColon, chColon, chAt,
93    chAmpersand, chEqual, chPlus, chNull
94};
95
96//      pchar plus ';' and '/'.
97//      pchar         = unreserved | escaped |
98//                      ":" | "@" | "&" | "=" | "+" | "$" | ","
99const XMLCh XMLUri::PATH_CHARACTERS[] =
100{
101    chSemiColon, chForwardSlash, chColon, chAt, chAmpersand,
102    chEqual, chPlus, chDollarSign, chComma, chNull
103};
104
105
106// ---------------------------------------------------------------------------
107//  Local methods and data
108// ---------------------------------------------------------------------------
109static const int BUF_LEN = 64;
110
111//
112// "Scheme"
113// "SchemeSpecificPart"
114// "Parameters"
115// "UserInfo"
116// "Host"
117// "Port"
118// "RegName"
119// "Path"
120// "Query"
121// "Fragment"
122//
123static const XMLCh errMsg_SCHEME[] =
124{
125    chLatin_s, chLatin_c, chLatin_h, chLatin_e,
126    chLatin_m, chLatin_e, chNull
127};
128
129static const XMLCh errMsg_SCHEMESPART[] =
130{
131    chLatin_s, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_e,
132    chLatin_S, chLatin_p, chLatin_e, chLatin_c, chLatin_i, chLatin_f,
133    chLatin_i, chLatin_c, chLatin_P, chLatin_a, chLatin_r, chLatin_t,
134    chNull
135};
136
137static const XMLCh errMsg_PARAMS[] =
138{
139    chLatin_p, chLatin_a, chLatin_r, chLatin_a, chLatin_m,
140    chLatin_e, chLatin_t, chLatin_e, chLatin_r, chLatin_s, chNull
141};
142
143static const XMLCh errMsg_USERINFO[] =
144{
145    chLatin_u, chLatin_s, chLatin_e, chLatin_r,
146    chLatin_i, chLatin_n, chLatin_f, chLatin_o, chNull
147};
148
149static const XMLCh errMsg_HOST[] =
150{
151    chLatin_h, chLatin_o, chLatin_s, chLatin_t, chNull
152};
153
154static const XMLCh errMsg_PORT[] =
155{
156    chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull
157};
158
159static const XMLCh errMsg_REGNAME[] =
160{
161    chLatin_R, chLatin_e, chLatin_g,
162    chLatin_N, chLatin_a, chLatin_m, chLatin_e, chNull
163};
164
165static const XMLCh errMsg_PATH[] =
166{
167    chLatin_p, chLatin_a, chLatin_t, chLatin_h, chNull
168};
169
170static const XMLCh errMsg_QUERY[] =
171{
172    chLatin_q, chLatin_u, chLatin_e, chLatin_r, chLatin_y, chNull
173};
174
175static const XMLCh errMsg_FRAGMENT[] =
176{
177    chLatin_f, chLatin_r, chLatin_a, chLatin_g,
178    chLatin_m, chLatin_e, chLatin_n, chLatin_t, chNull
179};
180
181//
182//  "//"
183//  "/"
184//  "./"
185//  "/."
186//  "/../"
187//  "/.."
188//
189static const XMLCh DOUBLE_SLASH[] =
190{
191    chForwardSlash, chForwardSlash, chNull
192};
193
194static const XMLCh SINGLE_SLASH[] =
195{
196    chForwardSlash, chNull
197};
198
199static const XMLCh SLASH_DOT_SLASH[] =
200{
201    chForwardSlash, chPeriod, chForwardSlash, chNull
202};
203
204static const XMLCh SLASH_DOT[] =
205{
206    chForwardSlash, chPeriod, chNull
207};
208
209static const XMLCh SLASH_DOTDOT_SLASH[] =
210{
211    chForwardSlash, chPeriod, chPeriod, chForwardSlash, chNull
212};
213
214static const XMLCh SLASH_DOTDOT[] =
215{
216    chForwardSlash, chPeriod, chPeriod, chNull
217};
218
219//
220//  ":/?#"
221//
222// REVISIT: why?
223static const XMLCh SCHEME_SEPARATORS[] =
224{
225    chColon, chForwardSlash, chQuestion, chPound, chNull
226};
227
228//
229//  "?#"
230//
231static const XMLCh PATH_SEPARATORS[] =
232{
233    chQuestion, chPound, chNull
234};
235
236// ---------------------------------------------------------------------------
237//  XMLUri: Constructors and Helper methods
238// ---------------------------------------------------------------------------
239// ctor# 2
240
241typedef JanitorMemFunCall<XMLUri>   CleanupType;
242
243XMLUri::XMLUri(const XMLCh* const uriSpec,
244               MemoryManager* const manager)
245: fPort(-1)
246, fScheme(0)
247, fUserInfo(0)
248, fHost(0)
249, fRegAuth(0)
250, fPath(0)
251, fQueryString(0)
252, fFragment(0)
253, fURIText(0)
254, fMemoryManager(manager)
255{
256    CleanupType cleanup(this, &XMLUri::cleanUp);
257
258    try {
259        initialize((XMLUri *)0, uriSpec);
260    }
261    catch(const OutOfMemoryException&)
262    {
263        cleanup.release();
264
265        throw;
266    }
267
268    cleanup.release();
269}
270
271// ctor# 7 relative ctor
272XMLUri::XMLUri(const XMLUri* const      baseURI
273              , const XMLCh* const   uriSpec
274              , MemoryManager* const manager)
275: fPort(-1)
276, fScheme(0)
277, fUserInfo(0)
278, fHost(0)
279, fRegAuth(0)
280, fPath(0)
281, fQueryString(0)
282, fFragment(0)
283, fURIText(0)
284, fMemoryManager(manager)
285{
286    CleanupType cleanup(this, &XMLUri::cleanUp);
287
288    try {
289        initialize(baseURI, uriSpec);
290    }
291    catch(const OutOfMemoryException&)
292    {
293        cleanup.release();
294
295        throw;
296    }
297
298    cleanup.release();
299}
300
301//Copy constructor
302XMLUri::XMLUri(const XMLUri& toCopy)
303: XSerializable(toCopy)
304, XMemory(toCopy)
305, fPort(-1)
306, fScheme(0)
307, fUserInfo(0)
308, fHost(0)
309, fRegAuth(0)
310, fPath(0)
311, fQueryString(0)
312, fFragment(0)
313, fURIText(0)
314, fMemoryManager(toCopy.fMemoryManager)
315{
316    CleanupType cleanup(this, &XMLUri::cleanUp);
317
318    try {
319        initialize(toCopy);
320    }
321    catch(const OutOfMemoryException&)
322    {
323        cleanup.release();
324
325        throw;
326    }
327
328    cleanup.release();
329}
330
331XMLUri& XMLUri::operator=(const XMLUri& toAssign)
332{
333    cleanUp();
334
335    CleanupType cleanup(this, &XMLUri::cleanUp);
336
337    try {
338        initialize(toAssign);
339    }
340    catch(const OutOfMemoryException&)
341    {
342        cleanup.release();
343
344        throw;
345    }
346
347    cleanup.release();
348
349    return *this;
350}
351
352XMLUri::~XMLUri()
353{
354    cleanUp();
355}
356
357void XMLUri::cleanUp()
358{
359    if (fScheme)
360        XMLString::release(&fScheme, fMemoryManager);//delete[] fScheme;
361
362    if (fUserInfo)
363        XMLString::release(&fUserInfo, fMemoryManager);//delete[] fUserInfo;
364
365    if (fHost)
366        XMLString::release(&fHost, fMemoryManager);//delete[] fHost;
367
368    if (fRegAuth)
369        XMLString::release(&fRegAuth, fMemoryManager);//delete[] fRegAuth;
370
371    if (fPath)
372        XMLString::release(&fPath, fMemoryManager);//delete[] fPath;
373
374    if (fQueryString)
375        XMLString::release(&fQueryString, fMemoryManager);//delete[] fQueryString;
376
377    if (fFragment)
378        XMLString::release(&fFragment, fMemoryManager);//delete[] fFragment;
379
380    XMLString::release(&fURIText, fMemoryManager);//delete[] fURIText;
381}
382
383void XMLUri::initialize(const XMLUri& toCopy)
384{
385    //
386    // assuming that all fields from the toCopy are valid,
387    // therefore need NOT to go through various setXXX() methods
388    //
389    fMemoryManager = toCopy.fMemoryManager;
390    fScheme = XMLString::replicate(toCopy.fScheme, fMemoryManager);
391    fUserInfo = XMLString::replicate(toCopy.fUserInfo, fMemoryManager);
392    fHost = XMLString::replicate(toCopy.fHost, fMemoryManager);
393    fPort = toCopy.fPort;
394    fRegAuth = XMLString::replicate(toCopy.fRegAuth, fMemoryManager);
395    fPath = XMLString::replicate(toCopy.fPath, fMemoryManager);
396    fQueryString = XMLString::replicate(toCopy.fQueryString, fMemoryManager);
397    fFragment = XMLString::replicate(toCopy.fFragment, fMemoryManager);
398}
399
400void XMLUri::initialize(const XMLUri* const baseURI
401                      , const XMLCh*  const uriSpec)
402{
403
404    // get a trimmed version of uriSpec
405    // uriSpec will NO LONGER be used in this function.
406    //
407    XMLCh* trimmedUriSpec = XMLString::replicate(uriSpec, fMemoryManager);
408    XMLString::trim(trimmedUriSpec);
409    ArrayJanitor<XMLCh> janName(trimmedUriSpec, fMemoryManager);
410    XMLSize_t trimmedUriSpecLen = XMLString::stringLen(trimmedUriSpec);
411
412    if ( !baseURI &&
413        (!trimmedUriSpec || trimmedUriSpecLen == 0))
414    {
415        ThrowXMLwithMemMgr1(MalformedURLException
416               , XMLExcepts::XMLNUM_URI_Component_Empty
417               , errMsg_PARAMS
418               , fMemoryManager);
419    }
420
421        // just make a copy of the base if spec is empty
422        if (!trimmedUriSpec || trimmedUriSpecLen == 0)
423    {
424        initialize(*baseURI);
425        return;
426        }
427
428        XMLSize_t index = 0;
429        bool foundScheme = false;
430
431        // Check for scheme, which must be before `/', '?' or '#'.
432        int colonIdx = XMLString::indexOf(trimmedUriSpec, chColon);
433        int slashIdx = XMLString::indexOf(trimmedUriSpec, chForwardSlash);
434        int queryIdx = XMLString::indexOf(trimmedUriSpec, chQuestion);
435        int fragmentIdx = XMLString::indexOf(trimmedUriSpec, chPound);
436
437        if ((colonIdx <= 0) ||
438            (colonIdx > slashIdx && slashIdx != -1) ||
439            (colonIdx > queryIdx && queryIdx != -1) ||
440            (colonIdx > fragmentIdx && fragmentIdx != -1))
441        {
442            // A standalone base is a valid URI according to spec
443            if ( colonIdx == 0 || (!baseURI && fragmentIdx != 0) )
444            {
445                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::XMLNUM_URI_No_Scheme, fMemoryManager);
446            }
447        }
448        else
449        {
450            foundScheme = true;
451            initializeScheme(trimmedUriSpec);
452            index = XMLString::stringLen(fScheme)+1;
453        }
454
455    // It's an error if we stop here
456    if (index == trimmedUriSpecLen || (foundScheme && (trimmedUriSpec[index] == chPound)))
457    {
458        ThrowXMLwithMemMgr1(MalformedURLException
459                , XMLExcepts::XMLNUM_URI_Component_Empty
460                , errMsg_PATH
461                , fMemoryManager);
462    }
463
464        // two slashes means generic URI syntax, so we get the authority
465    XMLCh* authUriSpec = (XMLCh*) fMemoryManager->allocate
466    (
467        (trimmedUriSpecLen+1) * sizeof(XMLCh)
468    );//new XMLCh[trimmedUriSpecLen+1];
469    ArrayJanitor<XMLCh> authName(authUriSpec, fMemoryManager);
470    XMLString::subString(authUriSpec, trimmedUriSpec, index, trimmedUriSpecLen, fMemoryManager);
471
472    if (((index+1) < trimmedUriSpecLen) &&
473        XMLString::startsWith(authUriSpec, DOUBLE_SLASH))
474    {
475        index += 2;
476        XMLSize_t startPos = index;
477
478        // get authority - everything up to path, query or fragment
479        XMLCh testChar;
480        while (index < trimmedUriSpecLen)
481        {
482            testChar = trimmedUriSpec[index];
483            if (testChar == chForwardSlash ||
484                testChar == chQuestion     ||
485                testChar == chPound         )
486            {
487                break;
488            }
489
490            index++;
491        }
492
493        // if we found authority, parse it out, otherwise we set the
494        // host to empty string
495        if (index > startPos)
496        {
497            XMLString::subString(authUriSpec, trimmedUriSpec, startPos, index, fMemoryManager);
498            initializeAuthority(authUriSpec);
499        }
500        else
501        {
502            //fHost = 0;
503            setHost(XMLUni::fgZeroLenString);
504        }
505    }
506
507    // we need to check if index has exceed the lenght or not
508    if (index >= trimmedUriSpecLen)
509        return;
510
511    XMLCh* pathUriSpec = (XMLCh*) fMemoryManager->allocate
512    (
513        (trimmedUriSpecLen+1) * sizeof(XMLCh)
514    );//new XMLCh[trimmedUriSpecLen+1];
515    ArrayJanitor<XMLCh> pathUriSpecName(pathUriSpec, fMemoryManager);
516    XMLString::subString(pathUriSpec, trimmedUriSpec, index, trimmedUriSpecLen, fMemoryManager);
517
518        initializePath(pathUriSpec);
519
520        // Resolve relative URI to base URI - see RFC 2396 Section 5.2
521        // In some cases, it might make more sense to throw an exception
522        // (when scheme is specified is the string spec and the base URI
523        // is also specified, for example), but we're just following the
524        // RFC specifications
525        if ( baseURI )
526    {
527        // check to see if this is the current doc - RFC 2396 5.2 #2
528        // note that this is slightly different from the RFC spec in that
529        // we don't include the check for query string being null
530        // - this handles cases where the urispec is just a query
531        // string or a fragment (e.g. "?y" or "#s") -
532        // see <http://www.ics.uci.edu/~fielding/url/test1.html> which
533        // identified this as a bug in the RFC
534        if ((!fPath || !*fPath) &&
535            fScheme == 0 &&
536            fHost == 0 && fRegAuth == 0)
537        {
538            fScheme = XMLString::replicate(baseURI->getScheme(), fMemoryManager);
539            fMemoryManager->deallocate(fUserInfo);//delete [] fUserInfo;
540            fUserInfo = XMLString::replicate(baseURI->getUserInfo(), fMemoryManager);
541            fHost = XMLString::replicate(baseURI->getHost(), fMemoryManager);
542            fPort = baseURI->getPort();
543            fRegAuth = XMLString::replicate(baseURI->getRegBasedAuthority(), fMemoryManager);
544            fMemoryManager->deallocate(fPath);//delete [] fPath;
545            fPath = XMLString::replicate(baseURI->getPath(), fMemoryManager);
546
547            if ( !fQueryString )
548            {
549                fQueryString = XMLString::replicate(baseURI->getQueryString(), fMemoryManager);
550            }
551            return;
552        }
553
554        // check for scheme - RFC 2396 5.2 #3
555        // if we found a scheme, it means absolute URI, so we're done
556        if (fScheme == 0)
557        {
558            fScheme = XMLString::replicate(baseURI->getScheme(), fMemoryManager);
559        }
560        else
561        {
562            return;
563        }
564
565        // check for authority - RFC 2396 5.2 #4
566        // if we found a host, then we've got a network path, so we're done
567        if (fHost == 0 && fRegAuth == 0)
568        {
569            fMemoryManager->deallocate(fUserInfo);//delete [] fUserInfo;
570            fUserInfo = XMLString::replicate(baseURI->getUserInfo(), fMemoryManager);
571            fHost = XMLString::replicate(baseURI->getHost(), fMemoryManager);
572            fPort = baseURI->getPort();
573            fRegAuth = XMLString::replicate(baseURI->getRegBasedAuthority(), fMemoryManager);
574        }
575        else
576        {
577            return;
578        }
579
580        // check for absolute path - RFC 2396 5.2 #5
581        if ((fPath && *fPath) &&
582            XMLString::startsWith(fPath, SINGLE_SLASH))
583        {
584            return;
585        }
586
587        // if we get to this point, we need to resolve relative path
588        // RFC 2396 5.2 #6
589
590        XMLCh* basePath = XMLString::replicate(baseURI->getPath(), fMemoryManager);
591        ArrayJanitor<XMLCh> basePathName(basePath, fMemoryManager);
592
593        XMLSize_t bufLen = trimmedUriSpecLen+XMLString::stringLen(fPath)+XMLString::stringLen(basePath)+1;
594        XMLCh* path = (XMLCh*) fMemoryManager->allocate(bufLen * sizeof(XMLCh));//new XMLCh[bufLen];
595        ArrayJanitor<XMLCh> pathName(path, fMemoryManager);
596        path[0] = 0;
597
598        XMLCh* tmp1 = (XMLCh*) fMemoryManager->allocate(bufLen * sizeof(XMLCh));//new XMLCh[bufLen];
599        ArrayJanitor<XMLCh> tmp1Name(tmp1, fMemoryManager);
600        XMLCh* tmp2 = (XMLCh*) fMemoryManager->allocate(bufLen * sizeof(XMLCh));//new XMLCh[bufLen];
601        ArrayJanitor<XMLCh> tmp2Name(tmp2, fMemoryManager);
602
603        // 6a - get all but the last segment of the base URI path
604        if (basePath)
605        {
606            int lastSlash = XMLString::lastIndexOf(basePath, chForwardSlash);
607            if (lastSlash != -1)
608            {
609                XMLString::subString(path, basePath, 0, lastSlash+1, fMemoryManager);
610            }
611        }
612
613        // 6b - append the relative URI path
614        XMLString::catString(path, fPath);
615
616        // 6c - remove all "./" where "." is a complete path segment
617        int iIndex = -1;
618        while ((iIndex = XMLString::patternMatch(path, SLASH_DOT_SLASH)) != -1)
619        {
620            XMLString::subString(tmp1, path, 0, iIndex, fMemoryManager);
621            XMLString::subString(tmp2, path, iIndex+2, XMLString::stringLen(path), fMemoryManager);
622
623            path[0] = 0;
624            XMLString::catString(path, tmp1);
625            XMLString::catString(path, tmp2);
626        }
627
628        // 6d - remove "." if path ends with "." as a complete path segment
629        if (XMLString::endsWith(path, SLASH_DOT))
630        {
631            path[XMLString::stringLen(path) - 1] = chNull;
632        }
633
634        // 6e - remove all "<segment>/../" where "<segment>" is a complete
635        // path segment not equal to ".."
636        iIndex = -1;
637        int segIndex = -1;
638        int offset = 1;
639
640        while ((iIndex = XMLString::patternMatch(&(path[offset]), SLASH_DOTDOT_SLASH)) != -1)
641        {
642                        // Undo offset
643                        iIndex += offset;
644
645                        // Find start of <segment> within substring ending at found point.
646                        XMLString::subString(tmp1, path, 0, iIndex-1, fMemoryManager);
647                        segIndex = XMLString::lastIndexOf(tmp1, chForwardSlash);
648
649                        // Ensure <segment> exists and != ".."
650            if (segIndex != -1                &&
651                (path[segIndex+1] != chPeriod ||
652                 path[segIndex+2] != chPeriod ||
653                                 segIndex + 3 != iIndex))
654            {
655
656                XMLString::subString(tmp1, path, 0, segIndex, fMemoryManager);
657                XMLString::subString(tmp2, path, iIndex+3, XMLString::stringLen(path), fMemoryManager);
658
659                path[0] = 0;
660                XMLString::catString(path, tmp1);
661                XMLString::catString(path, tmp2);
662
663                offset = (segIndex == 0 ? 1 : segIndex);
664            }
665            else
666            {
667                offset += 4;
668            }
669        }// while
670
671        // 6f - remove ending "<segment>/.." where "<segment>" is a
672        // complete path segment
673        if (XMLString::endsWith(path, SLASH_DOTDOT))
674        {
675                        // Find start of <segment> within substring ending at found point.
676            index = XMLString::stringLen(path) - 3;
677                        XMLString::subString(tmp1, path, 0, index-1, fMemoryManager);
678                        segIndex = XMLString::lastIndexOf(tmp1, chForwardSlash);
679
680            if (segIndex != -1                &&
681                (path[segIndex+1] != chPeriod ||
682                 path[segIndex+2] != chPeriod ||
683                                 segIndex + 3 != (int)index))
684            {
685                path[segIndex+1] = chNull;
686            }
687        }
688
689        if (getPath())
690            fMemoryManager->deallocate(fPath);//delete [] fPath;
691
692        fPath = XMLString::replicate(path, fMemoryManager);
693
694    }
695}
696
697// ---------------------------------------------------------------------------
698//  Components initialization
699// ---------------------------------------------------------------------------
700
701//
702// authority     = server | reg_name
703// server        = [ [ userinfo "@" ] hostport ]
704// hostport      = host [ ":" port ]
705//
706// reg_name      = 1*( unreserved | escaped | "$" | "," |
707//                    ";" | ":" | "@" | "&" | "=" | "+" )
708//
709// userinfo      = *( unreserved | escaped |
710//                 ";" | ":" | "&" | "=" | "+" | "$" | "," )
711//
712
713void XMLUri::initializeAuthority(const XMLCh* const uriSpec)
714{
715
716    int index = 0;
717    XMLSize_t start = 0;
718    const XMLSize_t end = XMLString::stringLen(uriSpec);
719
720    //
721    // server = [ [ userinfo "@" ] hostport ]
722    // userinfo is everything up @,
723    //
724    XMLCh* userinfo = (XMLCh*) fMemoryManager->allocate
725    (
726        (end+1) * sizeof(XMLCh)
727    );//new XMLCh[end+1];
728    ArrayJanitor<XMLCh> userName(userinfo, fMemoryManager);
729    index = XMLString::indexOf(&(uriSpec[start]), chAt);
730
731    if ( index != -1)
732    {
733        XMLString::subString(userinfo, &(uriSpec[start]), 0, index, fMemoryManager);
734        index++; // skip the @
735        start += index;
736    }
737    else
738    {
739        userinfo = 0;
740    }
741
742    //
743    // hostport = host [ ":" port ]
744    // host is everything up to ':', or up to
745    // and including ']' if followed by ':'.
746    //
747    XMLCh* host = (XMLCh*) fMemoryManager->allocate
748    (
749        (end+1) * sizeof(XMLCh)
750    );//new XMLCh[end+1];
751    ArrayJanitor<XMLCh> hostName(host, fMemoryManager);
752
753    // Search for port boundary.
754    if (start < end && uriSpec[start] == chOpenSquare)
755    {
756        index = XMLString::indexOf(&(uriSpec[start]), chCloseSquare);
757        if (index != -1)
758        {
759            // skip the ']'
760            index = ((start + index + 1) < end
761              && uriSpec[start + index + 1] == chColon) ? index+1 : -1;
762        }
763    }
764    else
765    {
766        index = XMLString::indexOf(&(uriSpec[start]), chColon);
767    }
768
769    if ( index != -1 )
770    {
771        XMLString::subString(host, &(uriSpec[start]), 0, index, fMemoryManager);
772        index++;  // skip the :
773        start +=index;
774    }
775    else
776    {
777        XMLString::subString(host, &(uriSpec[start]), 0, end-start, fMemoryManager);
778        start = end;
779    }
780
781    // port is everything after ":"
782
783    XMLCh* portStr = (XMLCh*) fMemoryManager->allocate
784    (
785        (end+1) * sizeof(XMLCh)
786    );//new XMLCh[end+1];
787    ArrayJanitor<XMLCh> portName(portStr, fMemoryManager);
788    int port = -1;
789
790    if ((host && *host) &&   // non empty host
791        (index != -1)                    &&   // ":" found
792        (start < end)                     )   // ":" is not the last
793    {
794        XMLString::subString(portStr, &(uriSpec[start]), 0, end-start, fMemoryManager);
795
796        if (portStr && *portStr)
797        {
798            port = XMLString::parseInt(portStr, fMemoryManager);
799        }
800    } // if > 0
801
802    // Check if we have server based authority.
803    if (isValidServerBasedAuthority(host, port, userinfo, fMemoryManager))
804    {
805        if (fHost)
806            fMemoryManager->deallocate(fHost);//delete [] fHost;
807
808        if (fUserInfo)
809            fMemoryManager->deallocate(fUserInfo);//delete[] fUserInfo;
810
811        fHost = XMLString::replicate(host, fMemoryManager);
812        fPort = port;
813        fUserInfo = XMLString::replicate(userinfo, fMemoryManager);
814
815        return;
816    }
817    // This must be registry based authority or the URI is malformed.
818    setRegBasedAuthority(uriSpec);
819}
820
821// scheme = alpha *( alpha | digit | "+" | "-" | "." )
822void XMLUri::initializeScheme(const XMLCh* const uriSpec)
823{
824    const XMLCh* tmpPtr = XMLString::findAny(uriSpec, SCHEME_SEPARATORS);
825
826    if ( !tmpPtr )
827    {
828        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::XMLNUM_URI_No_Scheme, fMemoryManager);
829    }
830        else
831    {
832        XMLCh* scheme = (XMLCh*) fMemoryManager->allocate
833        (
834            (XMLString::stringLen(uriSpec) + 1) * sizeof(XMLCh)
835        );//new XMLCh[XMLString::stringLen(uriSpec)+1];
836        ArrayJanitor<XMLCh> tmpName(scheme, fMemoryManager);
837        XMLString::subString(scheme, uriSpec, 0, (tmpPtr - uriSpec), fMemoryManager);
838        setScheme(scheme);
839        }
840
841}
842
843void XMLUri::initializePath(const XMLCh* const uriSpec)
844{
845    if ( !uriSpec )
846    {
847        ThrowXMLwithMemMgr1(MalformedURLException
848                , XMLExcepts::XMLNUM_URI_Component_Empty
849                , errMsg_PATH
850                , fMemoryManager);
851    }
852
853    XMLSize_t index = 0;
854    XMLSize_t start = 0;
855    XMLSize_t end = XMLString::stringLen(uriSpec);
856    XMLCh testChar = 0;
857
858    // path - everything up to query string or fragment
859    if (start < end)
860    {
861        // RFC 2732 only allows '[' and ']' to appear in the opaque part.
862        if (!getScheme() || uriSpec[start] == chForwardSlash)
863        {
864            // Scan path.
865            // abs_path = "/"  path_segments
866            // rel_path = rel_segment [ abs_path ]
867            while (index < end)
868            {
869                testChar = uriSpec[index];
870                if (testChar == chQuestion || testChar == chPound)
871                {
872                    break;
873                }
874
875                // check for valid escape sequence
876                if (testChar == chPercent)
877                {
878                    if (index+2 >= end ||
879                        !XMLString::isHex(uriSpec[index+1]) ||
880                        !XMLString::isHex(uriSpec[index+2]))
881                    {
882                        XMLCh value1[BUF_LEN+1];
883                        XMLString::moveChars(value1, &(uriSpec[index]), 3);
884                        value1[3] = chNull;
885                        ThrowXMLwithMemMgr2(MalformedURLException
886                                , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
887                                , errMsg_PATH
888                                , value1
889                                , fMemoryManager);
890                    }
891                }
892                else if (!isUnreservedCharacter(testChar) &&
893                         !isPathCharacter(testChar))
894                {
895                    XMLCh value1[BUF_LEN+1];
896                    value1[0] = testChar;
897                    value1[1] = chNull;
898                    ThrowXMLwithMemMgr2(MalformedURLException
899                            , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
900                            , errMsg_PATH
901                            , value1
902                            , fMemoryManager);
903                }
904
905                index++;
906            }//while (index < end)
907        }
908        else
909        {
910            // Scan opaque part.
911            // opaque_part = uric_no_slash *uric
912            while (index < end)
913            {
914                testChar = uriSpec[index];
915                if (testChar == chQuestion || testChar == chPound)
916                {
917                    break;
918                }
919
920                // check for valid escape sequence
921                if (testChar == chPercent)
922                {
923                    if (index+2 >= end ||
924                        !XMLString::isHex(uriSpec[index+1]) ||
925                        !XMLString::isHex(uriSpec[index+2]))
926                    {
927                        XMLCh value1[BUF_LEN+1];
928                        XMLString::moveChars(value1, &(uriSpec[index]), 3);
929                        value1[3] = chNull;
930                        ThrowXMLwithMemMgr2(MalformedURLException
931                                , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
932                                , errMsg_PATH
933                                , value1
934                                , fMemoryManager);
935                    }
936                }
937                // If the scheme specific part is opaque, it can contain '['
938                // and ']'. uric_no_slash wasn't modified by RFC 2732, which
939                // I've interpreted as an error in the spec, since the
940                // production should be equivalent to (uric - '/'), and uric
941                // contains '[' and ']'.
942                else if (!isReservedOrUnreservedCharacter(testChar))
943                {
944                    XMLCh value1[BUF_LEN+1];
945                    value1[0] = testChar;
946                    value1[1] = chNull;
947                    ThrowXMLwithMemMgr2(MalformedURLException
948                            , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
949                            , errMsg_PATH
950                            , value1
951                            , fMemoryManager);
952                }
953
954                index++;
955            }//while (index < end)
956        }
957    } //if (start < end)
958
959    if (getPath())
960    {
961        fMemoryManager->deallocate(fPath);//delete [] fPath;
962    }
963
964    fPath = (XMLCh*) fMemoryManager->allocate((index+1) * sizeof(XMLCh));//new XMLCh[index+1];
965    XMLString::subString(fPath, uriSpec, start, index, fMemoryManager);
966
967    // query - starts with ? and up to fragment or end
968    if (testChar == chQuestion)
969    {
970        index++;
971        start = index;
972        while (index < end)
973        {
974            testChar = uriSpec[index];
975            if (testChar == chPound)
976            {
977                break;
978            }
979
980            if (testChar == chPercent)
981            {
982                if (index+2 >= end ||
983                    !XMLString::isHex(uriSpec[index+1]) ||
984                    !XMLString::isHex(uriSpec[index+2]))
985                {
986                    XMLCh value1[BUF_LEN+1];
987                    XMLString::moveChars(value1, &(uriSpec[index]), 3);
988                    value1[3] = chNull;
989                    ThrowXMLwithMemMgr2(MalformedURLException
990                            , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
991                            , errMsg_QUERY
992                            , value1
993                            , fMemoryManager);
994                }
995            }
996            else if (!isReservedOrUnreservedCharacter(testChar))
997            {
998                XMLCh value1[BUF_LEN+1];
999                value1[0] = testChar;
1000                value1[1] = chNull;
1001                ThrowXMLwithMemMgr2(MalformedURLException
1002                        , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
1003                        , errMsg_QUERY
1004                        , value1
1005                        , fMemoryManager);
1006            }
1007            index++;
1008        }
1009
1010        if (getQueryString())
1011        {
1012            fMemoryManager->deallocate(fQueryString);//delete [] fQueryString;
1013        }
1014
1015        fQueryString = (XMLCh*) fMemoryManager->allocate
1016        (
1017            (index - start + 1) * sizeof(XMLCh)
1018        );//new XMLCh[index - start + 1];
1019        XMLString::subString(fQueryString, uriSpec, start, index, fMemoryManager);
1020    }
1021
1022    // fragment - starts with #
1023    if (testChar == chPound)
1024    {
1025        index++;
1026        start = index;
1027        while (index < end)
1028        {
1029            testChar = uriSpec[index];
1030
1031            if (testChar == chPercent)
1032            {
1033                if (index+2 >= end ||
1034                    !XMLString::isHex(uriSpec[index+1]) ||
1035                    !XMLString::isHex(uriSpec[index+2]))
1036                {
1037                    XMLCh value1[BUF_LEN+1];
1038                    XMLString::moveChars(value1, &(uriSpec[index]), 3);
1039                    value1[3] = chNull;
1040                    ThrowXMLwithMemMgr2(MalformedURLException
1041                            , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
1042                            , errMsg_FRAGMENT
1043                            , value1
1044                            , fMemoryManager);
1045                }
1046            }
1047            else if (!isReservedOrUnreservedCharacter(testChar))
1048            {
1049                XMLCh value1[BUF_LEN+1];
1050                value1[0] = testChar;
1051                value1[1] = chNull;
1052                ThrowXMLwithMemMgr2(MalformedURLException
1053                        , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
1054                        , errMsg_FRAGMENT
1055                        , value1
1056                        , fMemoryManager);
1057            }
1058
1059            index++;
1060
1061        }
1062
1063        if (getFragment())
1064            fMemoryManager->deallocate(fFragment);//delete [] fFragment;
1065
1066        //make sure that there is something following the '#'
1067        if (index > start)
1068        {
1069            fFragment = (XMLCh*) fMemoryManager->allocate
1070            (
1071                (index - start + 1) * sizeof(XMLCh)
1072            );//new XMLCh[index - start + 1];
1073            XMLString::subString(fFragment, uriSpec, start, index, fMemoryManager);
1074        }
1075        else
1076        {
1077            // RFC 2396, 4.0. URI Reference
1078            // URI-reference = [absoulteURI | relativeURI] [# fragment]
1079            //
1080            // RFC 2396, 4.1. Fragment Identifier
1081            // fragment = *uric
1082            //
1083            // empty fragment is valid
1084            fFragment = 0;
1085        }
1086    }
1087
1088}
1089
1090// ---------------------------------------------------------------------------
1091//  Setter
1092// ---------------------------------------------------------------------------
1093void XMLUri::setScheme(const XMLCh* const newScheme)
1094{
1095    if ( !newScheme )
1096    {
1097        ThrowXMLwithMemMgr1(MalformedURLException
1098                , XMLExcepts::XMLNUM_URI_Component_Set_Null
1099                , errMsg_SCHEME
1100                , fMemoryManager);
1101    }
1102
1103    if (!isConformantSchemeName(newScheme))
1104    {
1105        ThrowXMLwithMemMgr2(MalformedURLException
1106                , XMLExcepts::XMLNUM_URI_Component_Not_Conformant
1107                , errMsg_SCHEME
1108                , newScheme
1109                , fMemoryManager);
1110    }
1111
1112    if (getScheme())
1113    {
1114        fMemoryManager->deallocate(fScheme);//delete [] fScheme;
1115    }
1116
1117    fScheme = XMLString::replicate(newScheme, fMemoryManager);
1118    XMLString::lowerCase(fScheme);
1119}
1120
1121//
1122// server = [ [ userinfo "@" ] hostport ]
1123// hostport = host [":" port]
1124//
1125// setUserInfo(), setHost() and setPort() are closely related
1126// three methods, in a word, userinfo and port has dependency
1127// on host.
1128//
1129// if host is not present, userinfo must be null and port = -1
1130//
1131void XMLUri::setUserInfo(const XMLCh* const newUserInfo)
1132{
1133    if ( newUserInfo &&
1134         !getHost()    )
1135    {
1136        ThrowXMLwithMemMgr2(MalformedURLException
1137                , XMLExcepts::XMLNUM_URI_NullHost
1138                , errMsg_USERINFO
1139                , newUserInfo
1140                , fMemoryManager);
1141    }
1142
1143    isConformantUserInfo(newUserInfo, fMemoryManager);
1144
1145    if (getUserInfo())
1146    {
1147        fMemoryManager->deallocate(fUserInfo);//delete [] fUserInfo;
1148    }
1149
1150    //sometimes we get passed a empty string rather than a null.
1151    //Other procedures rely on it being null
1152    if(newUserInfo && *newUserInfo) {
1153        fUserInfo = XMLString::replicate(newUserInfo, fMemoryManager);
1154    }
1155    else
1156        fUserInfo = 0;
1157
1158}
1159
1160void XMLUri::setHost(const XMLCh* const newHost)
1161{
1162    if ( !newHost )
1163    {
1164        if (getHost())
1165            fMemoryManager->deallocate(fHost);//delete [] fHost;
1166
1167        fHost = 0;
1168        setUserInfo(0);
1169        setPort(-1);
1170
1171        return;
1172    }
1173
1174    if ( *newHost && !isWellFormedAddress(newHost, fMemoryManager))
1175    {
1176        ThrowXMLwithMemMgr2(MalformedURLException
1177                , XMLExcepts::XMLNUM_URI_Component_Not_Conformant
1178                , errMsg_HOST
1179                , newHost
1180                , fMemoryManager);
1181    }
1182
1183    if (getHost())
1184    {
1185        fMemoryManager->deallocate(fHost);//delete [] fHost;
1186    }
1187
1188    fHost = XMLString::replicate(newHost, fMemoryManager);
1189    setRegBasedAuthority(0);
1190}
1191
1192void XMLUri::setPort(int newPort)
1193{
1194    if (newPort >= 0 && newPort <= 65535)
1195    {
1196        if (!getHost())
1197        {
1198            XMLCh value1[BUF_LEN+1];
1199            XMLString::binToText(newPort, value1, BUF_LEN, 10, fMemoryManager);
1200            ThrowXMLwithMemMgr2(MalformedURLException
1201                    , XMLExcepts::XMLNUM_URI_NullHost
1202                    , errMsg_PORT
1203                    , value1
1204                    , fMemoryManager);
1205        }
1206    }
1207    else if (newPort != -1)
1208    {
1209        XMLCh value1[BUF_LEN+1];
1210        XMLString::binToText(newPort, value1, BUF_LEN, 10, fMemoryManager);
1211        ThrowXMLwithMemMgr1(MalformedURLException
1212                , XMLExcepts::XMLNUM_URI_PortNo_Invalid
1213                , value1
1214                , fMemoryManager);
1215    }
1216
1217    fPort = newPort;
1218}
1219
1220void XMLUri::setRegBasedAuthority(const XMLCh* const newRegAuth)
1221{
1222    if ( !newRegAuth )
1223    {
1224        if (getRegBasedAuthority())
1225            fMemoryManager->deallocate(fRegAuth);//delete [] fRegAuth;
1226
1227        fRegAuth = 0;
1228        return;
1229    }
1230    // reg_name = 1*( unreserved | escaped | "$" | "," |
1231    //            ";" | ":" | "@" | "&" | "=" | "+" )
1232    else if ( !*newRegAuth || !isValidRegistryBasedAuthority(newRegAuth) )
1233    {
1234        ThrowXMLwithMemMgr2(MalformedURLException
1235                , XMLExcepts::XMLNUM_URI_Component_Not_Conformant
1236                , errMsg_REGNAME
1237                , newRegAuth
1238                , fMemoryManager);
1239    }
1240
1241    if (getRegBasedAuthority())
1242        fMemoryManager->deallocate(fRegAuth);//delete [] fRegAuth;
1243
1244    fRegAuth = XMLString::replicate(newRegAuth, fMemoryManager);
1245    setHost(0);
1246}
1247
1248//
1249// setPath(), setQueryString() and setFragment() are closely
1250// related three methods as well.
1251//
1252void XMLUri::setPath(const XMLCh* const newPath)
1253{
1254    if (!newPath)
1255    {
1256        if (getPath())
1257            fMemoryManager->deallocate(fPath);//delete [] fPath;
1258
1259        fPath = 0;
1260        setQueryString(0);
1261        setFragment(0);
1262    }
1263    else
1264    {
1265        initializePath(newPath);
1266    }
1267}
1268
1269//
1270// fragment = *uric
1271//
1272void XMLUri::setFragment(const XMLCh* const newFragment)
1273{
1274        if ( !newFragment )
1275    {
1276        if (getFragment())
1277            fMemoryManager->deallocate(fFragment);//delete [] fFragment;
1278
1279        fFragment = 0;
1280        }
1281        else if (!isGenericURI())
1282    {
1283        ThrowXMLwithMemMgr2(MalformedURLException
1284                , XMLExcepts::XMLNUM_URI_Component_for_GenURI_Only
1285                , errMsg_FRAGMENT
1286                , newFragment
1287                , fMemoryManager);
1288        }
1289        else if ( !getPath() )
1290    {
1291        ThrowXMLwithMemMgr2(MalformedURLException
1292               , XMLExcepts::XMLNUM_URI_NullPath
1293               , errMsg_FRAGMENT
1294               , newFragment
1295               , fMemoryManager);
1296        }
1297        else if (!isURIString(newFragment))
1298    {
1299        ThrowXMLwithMemMgr1(MalformedURLException
1300                , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
1301                , errMsg_FRAGMENT
1302                , fMemoryManager);
1303        }
1304        else
1305    {
1306        if (getFragment())
1307        {
1308            fMemoryManager->deallocate(fFragment);//delete [] fFragment;
1309        }
1310
1311        fFragment = XMLString::replicate(newFragment, fMemoryManager);
1312        }
1313}
1314
1315//
1316// query = *uric
1317//
1318void XMLUri::setQueryString(const XMLCh* const newQueryString)
1319{
1320        if ( !newQueryString )
1321    {
1322        if (getQueryString())
1323            fMemoryManager->deallocate(fQueryString);//delete [] fQueryString;
1324
1325        fQueryString = 0;
1326        }
1327        else if (!isGenericURI())
1328    {
1329        ThrowXMLwithMemMgr2(MalformedURLException
1330                , XMLExcepts::XMLNUM_URI_Component_for_GenURI_Only
1331                , errMsg_QUERY
1332                , newQueryString
1333                , fMemoryManager);
1334        }
1335        else if ( !getPath() )
1336    {
1337        ThrowXMLwithMemMgr2(MalformedURLException
1338                , XMLExcepts::XMLNUM_URI_NullPath
1339                , errMsg_QUERY
1340                , newQueryString
1341                , fMemoryManager);
1342        }
1343        else if (!isURIString(newQueryString))
1344    {
1345        ThrowXMLwithMemMgr2(MalformedURLException
1346               , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
1347               , errMsg_QUERY
1348               , newQueryString
1349               , fMemoryManager);
1350        }
1351        else
1352    {
1353        if (getQueryString())
1354        {
1355            fMemoryManager->deallocate(fQueryString);//delete [] fQueryString;
1356        }
1357
1358        fQueryString = XMLString::replicate(newQueryString, fMemoryManager);
1359        }
1360}
1361
1362// ---------------------------------------------------------------------------
1363//  XMLUri: Public, static methods
1364// ---------------------------------------------------------------------------
1365
1366//
1367//  scheme = alpha *( alpha | digit | "+" | "-" | "." )
1368//  alphanum = alpha | digit
1369//
1370bool XMLUri::isConformantSchemeName(const XMLCh* const scheme)
1371{
1372        if ( !scheme )
1373        return false;
1374
1375    const XMLCh* tmpStr = scheme;
1376    if (!XMLString::isAlpha(*tmpStr))     // first: alpha
1377        return false;
1378
1379    // second onwards: ( alpha | digit | "+" | "-" | "." )
1380    tmpStr++;
1381    while (*tmpStr)
1382    {
1383        if ( !XMLString::isAlphaNum(*tmpStr) &&
1384             (XMLString::indexOf(SCHEME_CHARACTERS, *tmpStr) == -1))
1385            return false;
1386
1387        tmpStr++;
1388    }
1389
1390    return true;
1391}
1392
1393//
1394// userinfo = *( unreserved | escaped |
1395//              ";" | ":" | "&" | "=" | "+" | "$" | "," )
1396//
1397void XMLUri::isConformantUserInfo(const XMLCh* const userInfo
1398                                  , MemoryManager* const manager)
1399{
1400        if ( !userInfo )
1401        return;
1402
1403    const XMLCh* tmpStr = userInfo;
1404    while (*tmpStr)
1405    {
1406        if ( isUnreservedCharacter(*tmpStr) ||
1407            (XMLString::indexOf(USERINFO_CHARACTERS, *tmpStr) != -1))
1408        {
1409            tmpStr++;
1410        }
1411        else if (*tmpStr == chPercent)               // '%'
1412        {
1413            if (XMLString::isHex(*(tmpStr+1)) &&     // 1st hex
1414                XMLString::isHex(*(tmpStr+2))  )     // 2nd hex
1415            {
1416                tmpStr+=3;
1417            }
1418            else
1419            {
1420                XMLCh value1[BUF_LEN+1];
1421                value1[0] = chPercent;
1422                value1[1] = *(tmpStr+1);
1423                value1[2] = *(tmpStr+2);
1424                value1[3] = chNull;
1425
1426                ThrowXMLwithMemMgr2(MalformedURLException
1427                        , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
1428                        , errMsg_USERINFO
1429                        , value1
1430                        , manager);
1431            }
1432        }
1433        else
1434        {
1435            ThrowXMLwithMemMgr2(MalformedURLException
1436                    , XMLExcepts::XMLNUM_URI_Component_Invalid_Char
1437                    , errMsg_USERINFO
1438                    , userInfo
1439                    , manager);
1440        }
1441    } //while
1442
1443    return;
1444}
1445
1446bool XMLUri::isValidServerBasedAuthority(const XMLCh* const host,
1447                                         const XMLSize_t hostLen,
1448                                         const int port,
1449                                         const XMLCh* const userinfo,
1450                                         const XMLSize_t userLen)
1451{
1452    // The order is important, do not change
1453    if (!isWellFormedAddress(host, hostLen))
1454        return false;
1455
1456    // check port number
1457    if ((port > 65535) || (port < 0 && port != -1))
1458        return false;
1459
1460    // check userinfo
1461    XMLSize_t index = 0;
1462    while (index < userLen)
1463    {
1464        if (isUnreservedCharacter(userinfo[index]) ||
1465            (XMLString::indexOf(USERINFO_CHARACTERS, userinfo[index]) != -1))
1466        {
1467            index++;
1468        }
1469        else if (userinfo[index] == chPercent)               // '%'
1470        {
1471            if (XMLString::isHex(userinfo[index+1]) &&     // 1st hex
1472                XMLString::isHex(userinfo[index+2])  )     // 2nd hex
1473                index +=3;
1474            else
1475                return false;
1476        }
1477        else
1478            return false;
1479    } //while
1480
1481    return true;
1482}
1483
1484bool XMLUri::isValidServerBasedAuthority(const XMLCh* const host
1485                                         , const int port
1486                                         , const XMLCh* const userinfo
1487                                         , MemoryManager* const manager)
1488{
1489    // The order is important, do not change
1490    if (!isWellFormedAddress(host, manager))
1491        return false;
1492
1493    // check port number
1494    if ((port > 65535) || (port < 0 && port != -1))
1495        return false;
1496
1497    // check userinfo
1498    if (!userinfo)
1499        return true;
1500
1501    const XMLCh* tmpStr = userinfo;
1502    while (*tmpStr)
1503    {
1504        if ( isUnreservedCharacter(*tmpStr) ||
1505            (XMLString::indexOf(USERINFO_CHARACTERS, *tmpStr) != -1))
1506        {
1507            tmpStr++;
1508        }
1509        else if (*tmpStr == chPercent)               // '%'
1510        {
1511            if (XMLString::isHex(*(tmpStr+1)) &&     // 1st hex
1512                XMLString::isHex(*(tmpStr+2))  )     // 2nd hex
1513            {
1514                tmpStr+=3;
1515            }
1516            else
1517                return false;
1518        }
1519        else
1520            return false;
1521    } //while
1522
1523    return true;
1524}
1525
1526bool XMLUri::isValidRegistryBasedAuthority(const XMLCh* const authority,
1527                                           const XMLSize_t authLen)
1528{
1529    // check authority
1530    XMLSize_t index = 0;
1531    while (index < authLen)
1532    {
1533        if (isUnreservedCharacter(authority[index]) ||
1534            (XMLString::indexOf(REG_NAME_CHARACTERS, authority[index]) != -1))
1535        {
1536            index++;
1537        }
1538        else if (authority[index] == chPercent)               // '%'
1539        {
1540            if (XMLString::isHex(authority[index+1]) &&     // 1st hex
1541                XMLString::isHex(authority[index+2])  )     // 2nd hex
1542                index +=3;
1543            else
1544                return false;
1545        }
1546        else
1547            return false;
1548    } //while
1549
1550    return true;
1551}
1552
1553bool XMLUri::isValidRegistryBasedAuthority(const XMLCh* const authority)
1554{
1555    // check authority
1556    if (!authority)
1557        return false;
1558
1559    const XMLCh* tmpStr = authority;
1560    while (*tmpStr)
1561    {
1562        if (isUnreservedCharacter(*tmpStr) ||
1563            (XMLString::indexOf(REG_NAME_CHARACTERS, *tmpStr) != -1))
1564        {
1565            tmpStr++;
1566        }
1567        else if (*tmpStr == chPercent)               // '%'
1568        {
1569            if (XMLString::isHex(*(tmpStr+1)) &&     // 1st hex
1570                XMLString::isHex(*(tmpStr+2))  )     // 2nd hex
1571            {
1572                tmpStr+=3;
1573            }
1574            else
1575                return false;
1576        }
1577        else
1578            return false;
1579    } //while
1580
1581    return true;
1582}
1583
1584//
1585// uric     = reserved | unreserved | escaped
1586// escaped  = "%" hex hex
1587// hex      = digit | "A" | "B" | "C" | "D" | "E" | "F" |
1588//                    "a" | "b" | "c" | "d" | "e" | "f"
1589//
1590bool XMLUri::isURIString(const XMLCh* const uricString)
1591{
1592        if (!uricString || !*uricString)
1593        return false;
1594
1595    const XMLCh* tmpStr = uricString;
1596
1597    while (*tmpStr)
1598    {
1599        if (isReservedOrUnreservedCharacter(*tmpStr))
1600        {
1601            tmpStr++;
1602        }
1603        else if (*tmpStr == chPercent)               // '%'
1604        {
1605            if (XMLString::isHex(*(tmpStr+1)) &&     // 1st hex
1606                XMLString::isHex(*(tmpStr+2))  )     // 2nd hex
1607            {
1608                tmpStr+=3;
1609            }
1610            else
1611            {
1612                return false;
1613            }
1614        }
1615        else
1616        {
1617            return false;
1618        }
1619    }
1620
1621    return true;
1622}
1623
1624//
1625//  host          = hostname | IPv4address
1626//
1627//  hostname      = *( domainlabel "." ) toplabel [ "." ]
1628//  domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
1629//  toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
1630//
1631//  IPv4address   = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1632//
1633bool XMLUri::isWellFormedAddress(const XMLCh* const addrString
1634                                 , MemoryManager* const manager)
1635{
1636    // Check that we have a non-zero length string.
1637    if (!addrString || !*addrString)
1638        return false;
1639
1640    // Get address length.
1641    XMLSize_t addrStrLen = XMLString::stringLen(addrString);
1642
1643    // Check if the host is a valid IPv6reference.
1644    if (*addrString == chOpenSquare)
1645    {
1646        return isWellFormedIPv6Reference(addrString, addrStrLen);
1647    }
1648
1649    //
1650    // Cannot start with a '.', '-', or end with a '-'.
1651    //
1652    if (*addrString == chPeriod ||
1653        *addrString == chDash ||
1654        addrString[addrStrLen-1] == chDash)
1655        return false;
1656
1657    // rightmost domain label starting with digit indicates IP address
1658    // since top level domain label can only start with an alpha
1659    // see RFC 2396 Section 3.2.2
1660
1661    int lastPeriodPos = XMLString::lastIndexOf(addrString, chPeriod);
1662
1663    // if the string ends with "."
1664    // get the second last "."
1665    if (XMLSize_t(lastPeriodPos + 1) == addrStrLen)
1666    {
1667        XMLCh* tmp2 = (XMLCh*) manager->allocate
1668        (
1669            addrStrLen * sizeof(XMLCh)
1670        );//new XMLCh[addrStrLen];
1671        XMLString::subString(tmp2, addrString, 0, lastPeriodPos, manager);
1672        lastPeriodPos = XMLString::lastIndexOf(tmp2, chPeriod);
1673        manager->deallocate(tmp2);//delete [] tmp2;
1674
1675        if ( XMLString::isDigit(addrString[lastPeriodPos + 1]))
1676                        return false;
1677    }
1678
1679    if (XMLString::isDigit(addrString[lastPeriodPos + 1]))
1680    {
1681        return isWellFormedIPv4Address(addrString, addrStrLen);
1682    } // end of IPv4address
1683    else
1684    {
1685        //
1686        //  hostname      = *( domainlabel "." ) toplabel [ "." ]
1687        //  domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
1688        //  toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
1689
1690        // RFC 2396 states that hostnames take the form described in
1691        // RFC 1034 (Section 3) and RFC 1123 (Section 2.1). According
1692        // to RFC 1034, hostnames are limited to 255 characters.
1693        if (addrStrLen > 255) {
1694            return false;
1695        }
1696
1697        unsigned int labelCharCount = 0;
1698
1699        // domain labels can contain alphanumerics and '-"
1700        // but must start and end with an alphanumeric
1701        for (XMLSize_t i = 0; i < addrStrLen; i++)
1702        {
1703            if (addrString[i] == chPeriod)
1704            {
1705              if (((i > 0)  &&
1706                   (!XMLString::isAlphaNum(addrString[i-1]))) ||
1707                  ((i + 1 < addrStrLen) &&
1708                   (!XMLString::isAlphaNum(addrString[i+1])))  )
1709                {
1710                    return false;
1711                }
1712                labelCharCount = 0;
1713            }
1714            else if (!XMLString::isAlphaNum(addrString[i]) &&
1715                      addrString[i] != chDash)
1716            {
1717                return false;
1718            }
1719            // RFC 1034: Labels must be 63 characters or less.
1720            else if (++labelCharCount > 63) {
1721                return false;
1722            }
1723        } //for
1724    }
1725
1726    return true;
1727}
1728
1729//
1730//  RFC 2732 amended RFC 2396 by replacing the definition
1731//  of IPv4address with the one defined by RFC 2373.
1732//
1733//  IPv4address   = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1734//
1735bool XMLUri::isWellFormedIPv4Address(const XMLCh* const addr, const XMLSize_t length)
1736{
1737    int numDots = 0;
1738    int numDigits = 0;
1739
1740    // IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1741    //
1742    // make sure that
1743    // 1) we see only digits and dot separators,
1744    // 2) that any dot separator is preceded and followed by a digit
1745    // 3) that we find 3 dots
1746    // 4) that each segment contains 1 to 3 digits.
1747    // 5) that each segment is not greater than 255.
1748    for (XMLSize_t i = 0; i < length; ++i)
1749    {
1750        if (addr[i] == chPeriod)
1751        {
1752            if ((i == 0) ||
1753                (i+1 == length) ||
1754                !XMLString::isDigit(addr[i+1]))
1755            {
1756               return false;
1757            }
1758            numDigits = 0;
1759            if (++numDots > 3)
1760                return false;
1761        }
1762        else if (!XMLString::isDigit(addr[i]))
1763        {
1764            return false;
1765        }
1766        // Check that that there are no more than three digits
1767        // in this segment.
1768        else if (++numDigits > 3)
1769        {
1770            return false;
1771        }
1772        // Check that this segment is not greater than 255.
1773        else if (numDigits == 3)
1774        {
1775            XMLCh first = addr[i-2];
1776            XMLCh second = addr[i-1];
1777            XMLCh last = addr[i];
1778            if (!(first < chDigit_2 ||
1779                 (first == chDigit_2 &&
1780                 (second < chDigit_5 ||
1781                 (second == chDigit_5 && last <= chDigit_5)))))
1782            {
1783                return false;
1784            }
1785        }
1786    } //for
1787    return (numDots == 3);
1788}
1789
1790//
1791//  IPv6reference = "[" IPv6address "]"
1792//
1793bool XMLUri::isWellFormedIPv6Reference(const XMLCh* const addr, const XMLSize_t length)
1794{
1795    XMLSize_t end = length-1;
1796
1797    // Check if string is a potential match for IPv6reference.
1798    if (!(length > 2 && addr[0] == chOpenSquare && addr[end] == chCloseSquare))
1799    {
1800        return false;
1801    }
1802
1803    // Counter for the number of 16-bit sections read in the address.
1804    int counter = 0;
1805
1806    // Scan hex sequence before possible '::' or IPv4 address.
1807    int iIndex = scanHexSequence(addr, 1, end, counter);
1808    if (iIndex == -1)
1809        return false;
1810
1811    XMLSize_t index=(XMLSize_t)iIndex;
1812    // Address must contain 128-bits of information.
1813    if (index == end)
1814    {
1815       return (counter == 8);
1816    }
1817
1818    if (index+1 < end && addr[index] == chColon)
1819    {
1820        if (addr[index+1] == chColon)
1821        {
1822            // '::' represents at least one 16-bit group of zeros.
1823            if (++counter > 8)
1824            {
1825                return false;
1826            }
1827            index += 2;
1828            // Trailing zeros will fill out the rest of the address.
1829            if (index == end)
1830            {
1831                return true;
1832            }
1833        }
1834        // If the second character wasn't ':', in order to be valid,
1835        // the remainder of the string must match IPv4Address,
1836        // and we must have read exactly 6 16-bit groups.
1837        else
1838        {
1839            if (counter == 6)
1840                return isWellFormedIPv4Address(addr+index+1, end-index-1);
1841            else
1842                return false;
1843        }
1844    }
1845    else
1846    {
1847       return false;
1848    }
1849
1850    // 3. Scan hex sequence after '::'.
1851    int prevCount = counter;
1852    iIndex = scanHexSequence(addr, index, end, counter);
1853    if (iIndex == -1)
1854        return false;
1855
1856    index=(XMLSize_t)iIndex;
1857    // If this is the end of the address then
1858    // we've got 128-bits of information.
1859    if (index == end)
1860    {
1861        return true;
1862    }
1863
1864    // The address ends in an IPv4 address, or it is invalid.
1865    // scanHexSequence has already made sure that we have the right number of bits.
1866    XMLSize_t shiftCount = (counter > prevCount) ? index+1 : index;
1867    return isWellFormedIPv4Address(addr + shiftCount, end - shiftCount);
1868}
1869
1870//
1871//  For use with isWellFormedIPv6Reference only.
1872//
1873int XMLUri::scanHexSequence (const XMLCh* const addr, XMLSize_t index, XMLSize_t end, int& counter)
1874{
1875    XMLCh testChar = chNull;
1876    int numDigits = 0;
1877    XMLSize_t start = index;
1878
1879    // Trying to match the following productions:
1880    // hexseq = hex4 *( ":" hex4)
1881    // hex4   = 1*4HEXDIG
1882    for (; index < end; ++index)
1883    {
1884        testChar = addr[index];
1885        if (testChar == chColon)
1886        {
1887            // IPv6 addresses are 128-bit, so there can be at most eight sections.
1888            if (numDigits > 0 && ++counter > 8)
1889            {
1890                return -1;
1891            }
1892            // This could be '::'.
1893            if (numDigits == 0 || ((index+1 < end) && addr[index+1] == chColon))
1894            {
1895                return (int)index;
1896            }
1897            numDigits = 0;
1898        }
1899        // This might be invalid or an IPv4address. If it's potentially an IPv4address,
1900        // backup to just after the last valid character that matches hexseq.
1901        else if (!XMLString::isHex(testChar))
1902        {
1903            if (testChar == chPeriod && numDigits < 4 && numDigits > 0 && counter <= 6)
1904            {
1905                int back = (int)index - numDigits - 1;
1906                return (back >= (int)start) ? back : (int)start;
1907            }
1908            return -1;
1909        }
1910        // There can be at most 4 hex digits per group.
1911        else if (++numDigits > 4)
1912        {
1913            return -1;
1914        }
1915    }
1916    return (numDigits > 0 && ++counter <= 8) ? (int)end : -1;
1917}
1918
1919bool XMLUri::isGenericURI()
1920{
1921    return (getHost() != 0);
1922}
1923
1924
1925//
1926//  This method will take the broken out parts of the URI and build up the
1927//  full text. We don't do this unless someone asks us to, since its often
1928//  never required.
1929//
1930void XMLUri::buildFullText()
1931{
1932    // Calculate the worst case size of the buffer required
1933    XMLSize_t bufSize = XMLString::stringLen(fScheme) + 1
1934                           + XMLString::stringLen(fFragment) + 1
1935                           + XMLString::stringLen(fHost ? fHost : fRegAuth) + 2
1936                           + XMLString::stringLen(fPath)
1937                           + XMLString::stringLen(fQueryString) + 1
1938                           + XMLString::stringLen(fUserInfo) + 1
1939                           + 32;
1940
1941    // Clean up the existing buffer and allocate another
1942    fMemoryManager->deallocate(fURIText);//delete [] fURIText;
1943    fURIText = (XMLCh*) fMemoryManager->allocate(bufSize * sizeof(XMLCh));//new XMLCh[bufSize];
1944    *fURIText = 0;
1945
1946    XMLCh* outPtr = fURIText;
1947    if (fScheme != 0)
1948    {
1949        XMLString::catString(fURIText, getScheme());
1950        outPtr += XMLString::stringLen(fURIText);
1951        *outPtr++ = chColon;
1952    }
1953
1954    // Authority
1955    if (fHost || fRegAuth)
1956    {
1957        *outPtr++ = chForwardSlash;
1958        *outPtr++ = chForwardSlash;
1959
1960        // Server based authority.
1961        if (fHost)
1962        {
1963            if (fUserInfo)
1964            {
1965                XMLString::copyString(outPtr, fUserInfo);
1966                outPtr += XMLString::stringLen(fUserInfo);
1967                *outPtr++ = chAt;
1968            }
1969
1970            XMLString::copyString(outPtr, fHost);
1971            outPtr += XMLString::stringLen(fHost);
1972
1973            //
1974            //  If the port is -1, then we don't put it in. Else we need
1975            //  to because it was explicitly provided.
1976            //
1977            if (fPort != -1)
1978            {
1979                *outPtr++ = chColon;
1980
1981                XMLCh tmpBuf[17];
1982                XMLString::binToText(fPort, tmpBuf, 16, 10, fMemoryManager);
1983                XMLString::copyString(outPtr, tmpBuf);
1984                outPtr += XMLString::stringLen(tmpBuf);
1985            }
1986        }
1987        // Registry based authority.
1988        else {
1989            XMLString::copyString(outPtr, fRegAuth);
1990            outPtr += XMLString::stringLen(fRegAuth);
1991        }
1992    }
1993
1994    if (fPath)
1995    {
1996        XMLString::copyString(outPtr, fPath);
1997        outPtr += XMLString::stringLen(fPath);
1998    }
1999
2000    if (fQueryString)
2001    {
2002        *outPtr++ = chQuestion;
2003        XMLString::copyString(outPtr, fQueryString);
2004        outPtr += XMLString::stringLen(fQueryString);
2005    }
2006
2007    if (fFragment)
2008    {
2009        *outPtr++ = chPound;
2010        XMLString::copyString(outPtr, fFragment);
2011        outPtr += XMLString::stringLen(fFragment);
2012    }
2013
2014    // Cap it off in case the last op was not a string copy
2015    *outPtr = 0;
2016}
2017
2018// NOTE: no check for NULL value of uriStr (caller responsiblilty)
2019bool XMLUri::isValidURI(const XMLUri* const baseURI
2020                       , const XMLCh* const uriStr
2021                       , bool bAllowSpaces/*=false*/)
2022{
2023    // get a trimmed version of uriStr
2024    // uriStr will NO LONGER be used in this function.
2025    const XMLCh* trimmedUriSpec = uriStr;
2026
2027    while (XMLChar1_0::isWhitespace(*trimmedUriSpec))
2028        trimmedUriSpec++;
2029
2030    XMLSize_t trimmedUriSpecLen = XMLString::stringLen(trimmedUriSpec);
2031
2032    while (trimmedUriSpecLen) {
2033        if (XMLChar1_0::isWhitespace(trimmedUriSpec[trimmedUriSpecLen-1]))
2034            trimmedUriSpecLen--;
2035        else
2036            break;
2037    }
2038
2039    if (trimmedUriSpecLen == 0)
2040    {
2041        if (!baseURI)
2042            return false;
2043        else
2044            return true;
2045    }
2046
2047    XMLSize_t index = 0;
2048    bool foundScheme = false;
2049
2050    // Check for scheme, which must be before `/', '?' or '#'.
2051    int colonIdx = XMLString::indexOf(trimmedUriSpec, chColon);
2052    int slashIdx = XMLString::indexOf(trimmedUriSpec, chForwardSlash);
2053    int queryIdx = XMLString::indexOf(trimmedUriSpec, chQuestion);
2054    int fragmentIdx = XMLString::indexOf(trimmedUriSpec, chPound);
2055
2056    if ((colonIdx <= 0) ||
2057        (colonIdx > slashIdx && slashIdx != -1) ||
2058        (colonIdx > queryIdx && queryIdx != -1) ||
2059        (colonIdx > fragmentIdx && fragmentIdx != -1))
2060    {
2061        // A standalone base is a valid URI according to spec
2062        if (colonIdx == 0 || (!baseURI && fragmentIdx != 0))
2063            return false;
2064    }
2065    else
2066    {
2067        if (!processScheme(trimmedUriSpec, index))
2068            return false;
2069        foundScheme = true;
2070        ++index;
2071    }
2072
2073    // It's an error if we stop here
2074    if (index == trimmedUriSpecLen || (foundScheme && (trimmedUriSpec[index] == chPound)))
2075        return false;
2076
2077        // two slashes means generic URI syntax, so we get the authority
2078    const XMLCh* authUriSpec = trimmedUriSpec +  index;
2079    if (((index+1) < trimmedUriSpecLen) &&
2080        XMLString::startsWith(authUriSpec, DOUBLE_SLASH))
2081    {
2082        index += 2;
2083        XMLSize_t startPos = index;
2084
2085        // get authority - everything up to path, query or fragment
2086        XMLCh testChar;
2087        while (index < trimmedUriSpecLen)
2088        {
2089            testChar = trimmedUriSpec[index];
2090            if (testChar == chForwardSlash ||
2091                testChar == chQuestion     ||
2092                testChar == chPound         )
2093            {
2094                break;
2095            }
2096
2097            index++;
2098        }
2099
2100        // if we found authority, parse it out, otherwise we set the
2101        // host to empty string
2102        if (index > startPos)
2103        {
2104            if (!processAuthority(trimmedUriSpec + startPos, index - startPos))
2105                return false;
2106        }
2107    }
2108
2109    // we need to check if index has exceed the lenght or not
2110    if (index < trimmedUriSpecLen)
2111    {
2112            if (!processPath(trimmedUriSpec + index, trimmedUriSpecLen - index, foundScheme, bAllowSpaces))
2113            return false;
2114    }
2115
2116    return true;
2117}
2118
2119// NOTE: no check for NULL value of uriStr (caller responsiblilty)
2120// NOTE: this routine is the same as above, but it uses a flag to
2121//       indicate the existance of a baseURI rather than an XMLuri.
2122bool XMLUri::isValidURI(bool haveBaseURI, const XMLCh* const uriStr, bool bAllowSpaces/*=false*/)
2123{
2124    // get a trimmed version of uriStr
2125    // uriStr will NO LONGER be used in this function.
2126    const XMLCh* trimmedUriSpec = uriStr;
2127
2128    while (XMLChar1_0::isWhitespace(*trimmedUriSpec))
2129        trimmedUriSpec++;
2130
2131    XMLSize_t trimmedUriSpecLen = XMLString::stringLen(trimmedUriSpec);
2132
2133    while (trimmedUriSpecLen) {
2134        if (XMLChar1_0::isWhitespace(trimmedUriSpec[trimmedUriSpecLen-1]))
2135            trimmedUriSpecLen--;
2136        else
2137            break;
2138    }
2139
2140    if (trimmedUriSpecLen == 0)
2141    {
2142        if (!haveBaseURI)
2143            return false;
2144        return true;
2145    }
2146
2147    XMLSize_t index = 0;
2148    bool foundScheme = false;
2149
2150    // Check for scheme, which must be before `/', '?' or '#'.
2151    int colonIdx = XMLString::indexOf(trimmedUriSpec, chColon);
2152    int slashIdx = XMLString::indexOf(trimmedUriSpec, chForwardSlash);
2153    int queryIdx = XMLString::indexOf(trimmedUriSpec, chQuestion);
2154    int fragmentIdx = XMLString::indexOf(trimmedUriSpec, chPound);
2155
2156    if ((colonIdx <= 0) ||
2157        (colonIdx > slashIdx && slashIdx != -1) ||
2158        (colonIdx > queryIdx && queryIdx != -1) ||
2159        (colonIdx > fragmentIdx && fragmentIdx != -1))
2160    {
2161        // A standalone base is a valid URI according to spec
2162        if (colonIdx == 0 || (!haveBaseURI && fragmentIdx != 0))
2163            return false;
2164    }
2165    else
2166    {
2167        if (!processScheme(trimmedUriSpec, index))
2168            return false;
2169        foundScheme = true;
2170        ++index;
2171    }
2172
2173    // It's an error if we stop here
2174    if (index == trimmedUriSpecLen || (foundScheme && (trimmedUriSpec[index] == chPound)))
2175        return false;
2176
2177        // two slashes means generic URI syntax, so we get the authority
2178    const XMLCh* authUriSpec = trimmedUriSpec +  index;
2179    if (((index+1) < trimmedUriSpecLen) &&
2180        XMLString::startsWith(authUriSpec, DOUBLE_SLASH))
2181    {
2182        index += 2;
2183        XMLSize_t startPos = index;
2184
2185        // get authority - everything up to path, query or fragment
2186        XMLCh testChar;
2187        while (index < trimmedUriSpecLen)
2188        {
2189            testChar = trimmedUriSpec[index];
2190            if (testChar == chForwardSlash ||
2191                testChar == chQuestion     ||
2192                testChar == chPound         )
2193            {
2194                break;
2195            }
2196
2197            index++;
2198        }
2199
2200        // if we found authority, parse it out, otherwise we set the
2201        // host to empty string
2202        if (index > startPos)
2203        {
2204            if (!processAuthority(trimmedUriSpec + startPos, index - startPos))
2205                return false;
2206        }
2207    }
2208
2209    // we need to check if index has exceed the length or not
2210    if (index < trimmedUriSpecLen)
2211    {
2212        if (!processPath(trimmedUriSpec + index, trimmedUriSpecLen - index, foundScheme, bAllowSpaces))
2213            return false;
2214    }
2215
2216    return true;
2217}
2218
2219bool XMLUri::isWellFormedAddress(const XMLCh* const addrString,
2220                                 const XMLSize_t addrStrLen)
2221{
2222    // Check that we have a non-zero length string.
2223    if (addrStrLen == 0)
2224        return false;
2225
2226    // Check if the host is a valid IPv6reference.
2227    if (*addrString == chOpenSquare)
2228    {
2229        return isWellFormedIPv6Reference(addrString, addrStrLen);
2230    }
2231
2232    //
2233    // Cannot start with a '.', '-', or end with a '-'.
2234    //
2235    if (*addrString == chPeriod ||
2236        *addrString == chDash ||
2237        addrString[addrStrLen-1] == chDash)
2238        return false;
2239
2240    // rightmost domain label starting with digit indicates IP address
2241    // since top level domain label can only start with an alpha
2242    // see RFC 2396 Section 3.2.2
2243
2244    int lastPeriodPos = XMLString::lastIndexOf(chPeriod, addrString, addrStrLen);
2245
2246    // if the string ends with "."
2247    // get the second last "."
2248    if (XMLSize_t(lastPeriodPos + 1) == addrStrLen)
2249    {
2250        lastPeriodPos = XMLString::lastIndexOf(chPeriod, addrString, lastPeriodPos);
2251
2252        if ( XMLString::isDigit(addrString[lastPeriodPos + 1]))
2253                        return false;
2254    }
2255
2256    if (XMLString::isDigit(addrString[lastPeriodPos + 1]))
2257    {
2258        return isWellFormedIPv4Address(addrString, addrStrLen);
2259    } // end of IPv4address
2260    else
2261    {
2262        //
2263        //  hostname      = *( domainlabel "." ) toplabel [ "." ]
2264        //  domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
2265        //  toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
2266
2267        // RFC 2396 states that hostnames take the form described in
2268        // RFC 1034 (Section 3) and RFC 1123 (Section 2.1). According
2269        // to RFC 1034, hostnames are limited to 255 characters.
2270        if (addrStrLen > 255) {
2271            return false;
2272        }
2273
2274        unsigned int labelCharCount = 0;
2275
2276        // domain labels can contain alphanumerics and '-"
2277        // but must start and end with an alphanumeric
2278        for (XMLSize_t i = 0; i < addrStrLen; i++)
2279        {
2280            if (addrString[i] == chPeriod)
2281            {
2282              if (((i > 0)  &&
2283                   (!XMLString::isAlphaNum(addrString[i-1]))) ||
2284                  ((i + 1 < addrStrLen) &&
2285                   (!XMLString::isAlphaNum(addrString[i+1])))  )
2286                {
2287                    return false;
2288                }
2289                labelCharCount = 0;
2290            }
2291            else if (!XMLString::isAlphaNum(addrString[i]) &&
2292                      addrString[i] != chDash)
2293            {
2294                return false;
2295            }
2296            // RFC 1034: Labels must be 63 characters or less.
2297            else if (++labelCharCount > 63) {
2298                return false;
2299            }
2300        } //for
2301    }
2302
2303    return true;
2304}
2305
2306bool XMLUri::processScheme(const XMLCh* const schemeStr, XMLSize_t& index)
2307{
2308    const XMLCh* tmpPtr = XMLString::findAny(schemeStr, SCHEME_SEPARATORS);
2309
2310    if (tmpPtr) {
2311        index = tmpPtr - schemeStr;
2312        return isConformantSchemeName(schemeStr, index);
2313    }
2314    else {
2315        return false;
2316    }
2317}
2318
2319
2320bool XMLUri::isConformantSchemeName( const XMLCh* const scheme
2321                                   , const XMLSize_t schemeLen)
2322{
2323    if (!XMLString::isAlpha(*scheme))     // first: alpha
2324        return false;
2325
2326    // second onwards: ( alpha | digit | "+" | "-" | "." )
2327    for (XMLSize_t i=1; i<schemeLen; i++)
2328    {
2329        if ( !XMLString::isAlphaNum(scheme[i]) &&
2330             (XMLString::indexOf(SCHEME_CHARACTERS, scheme[i]) == -1))
2331            return false;
2332    }
2333
2334    return true;
2335}
2336
2337bool XMLUri::processAuthority( const XMLCh* const authSpec
2338                             , const XMLSize_t authLen)
2339{
2340    int index = XMLString::indexOf(authSpec, chAt);
2341    XMLSize_t start = 0;
2342
2343    // server = [ [ userinfo "@" ] hostport ]
2344    // userinfo is everything up @,
2345    const XMLCh* userinfo;
2346    int userInfoLen = 0;
2347    if ((index != -1) && (XMLSize_t(index) < authLen))
2348    {
2349        userinfo = authSpec;
2350        userInfoLen = index;
2351        start = index + 1;
2352    }
2353    else
2354    {
2355        userinfo = XMLUni::fgZeroLenString;
2356    }
2357
2358    // hostport = host [ ":" port ]
2359    // host is everything up to ':', or up to
2360    // and including ']' if followed by ':'.
2361    //
2362    // Search for port boundary.
2363    const XMLCh* host;
2364    XMLSize_t hostLen = 0;
2365    if ((start < authLen) && (authSpec[start] == chOpenSquare))
2366    {
2367        index = XMLString::indexOf(&(authSpec[start]), chCloseSquare);
2368        if ((index != -1) && (XMLSize_t(index) < authLen))
2369        {
2370            // skip the ']'
2371            index = ((start + index + 1) < authLen
2372              && authSpec[start + index + 1] == chColon) ? index+1 : -1;
2373        }
2374    }
2375    else
2376    {
2377        index = XMLString::indexOf(&(authSpec[start]), chColon);
2378        if (index!=-1 && XMLSize_t(index) >= authLen)
2379            index = -1;
2380    }
2381
2382    host = &(authSpec[start]);
2383    if (index != -1)
2384    {
2385        hostLen = index;
2386        start += index + 1;  // skip the :
2387    }
2388    else
2389    {
2390        hostLen = authLen - start;
2391        start = authLen;
2392    }
2393
2394    // port is everything after ":"
2395    int port = -1;
2396    if ((hostLen) &&   // non empty host
2397        (index != -1)                    &&   // ":" found
2398        (start < authLen)                     )   // ":" is not the last
2399    {
2400        const XMLCh* portStr = &(authSpec[start]);
2401        if (*portStr)
2402        {
2403            port = 0;
2404            for (XMLSize_t i=0; i<(authLen - start); i++)
2405            {
2406                if (portStr[i] < chDigit_0 || portStr[i] > chDigit_9)
2407                {
2408                  // Assume this is a registry-based authority.
2409                  //
2410                  port = -1;
2411                  hostLen = 0;
2412                  host = XMLUni::fgZeroLenString;
2413                  userInfoLen = 0;
2414                  userinfo = XMLUni::fgZeroLenString;
2415                  break;
2416                }
2417
2418                port = (port * 10) + (int) (portStr[i] - chDigit_0);
2419            }
2420        }
2421    }
2422
2423    return isValidServerBasedAuthority(host, hostLen, port, userinfo, userInfoLen)
2424      || isValidRegistryBasedAuthority(authSpec, authLen);
2425}
2426
2427bool XMLUri::processPath(const XMLCh* const pathStr,
2428                         const XMLSize_t pathStrLen,
2429                         const bool isSchemePresent,
2430                         const bool bAllowSpaces/*=false*/)
2431{
2432    if (pathStrLen != 0)
2433    {
2434        XMLSize_t index = 0;
2435        XMLCh testChar = chNull;
2436        bool isOpaque = (!isSchemePresent || *pathStr == chForwardSlash);
2437
2438        // path - everything up to query string or fragment
2439        //
2440        // RFC 2732 only allows '[' and ']' to appear in the opaque part.
2441        while (index < pathStrLen)
2442        {
2443            testChar = pathStr[index];
2444            if (testChar == chQuestion || testChar == chPound)
2445                break;
2446
2447            if (testChar == chPercent)
2448            {
2449                if (index+2 >= pathStrLen ||
2450                    !XMLString::isHex(pathStr[index+1]) ||
2451                    !XMLString::isHex(pathStr[index+2]))
2452                        return false;
2453            }
2454            else if (testChar==chSpace)
2455            {
2456                if(!bAllowSpaces)
2457                    return false;
2458            }
2459            else if (!isUnreservedCharacter(testChar) &&
2460                     ((isOpaque && !isPathCharacter(testChar)) ||
2461                      (!isOpaque && !isReservedCharacter(testChar))))
2462            {
2463                return false;
2464            }
2465
2466            index++;
2467        }
2468
2469        // query - starts with ? and up to fragment or end
2470        // fragment - starts with #
2471        bool isQuery = (testChar == chQuestion);
2472        if (isQuery || testChar == chPound)
2473        {
2474            index++;
2475            while (index < pathStrLen)
2476            {
2477                testChar = pathStr[index];
2478                if (testChar == chPound && isQuery) {
2479                    isQuery = false;
2480                    index++;
2481                    continue;
2482                }
2483
2484                if (testChar == chPercent)
2485                {
2486                    if (index+2 >= pathStrLen ||
2487                        !XMLString::isHex(pathStr[index+1]) ||
2488                        !XMLString::isHex(pathStr[index+2]))
2489                        return false;
2490                }
2491                else if (testChar==chSpace)
2492                {
2493                    if(!bAllowSpaces)
2494                        return false;
2495                }
2496                else if (!isReservedOrUnreservedCharacter(testChar))
2497                {
2498                    return false;
2499                }
2500                index++;
2501            }
2502        }
2503    } //if (pathStrLen...)
2504
2505    return true;
2506}
2507
2508/***
2509 * [Bug7698]: filenames with embedded spaces in schemaLocation strings not handled properly
2510 *
2511 * This method is called when Scanner/TraverseSchema knows that the URI reference is
2512 * for local file.
2513 *
2514 ***/
2515void XMLUri::normalizeURI(const XMLCh*     const systemURI,
2516                                XMLBuffer&       normalizedURI)
2517{
2518    const XMLCh* pszSrc = systemURI;
2519
2520    normalizedURI.reset();
2521
2522    while (*pszSrc) {
2523
2524        if ((*(pszSrc) == chPercent)
2525        &&  (*(pszSrc+1) == chDigit_2)
2526        &&  (*(pszSrc+2) == chDigit_0))
2527        {
2528            pszSrc += 3;
2529            normalizedURI.append(chSpace);
2530        }
2531        else
2532        {
2533            normalizedURI.append(*pszSrc);
2534            pszSrc++;
2535        }
2536    }
2537}
2538
2539/***
2540 * Support for Serialization/De-serialization
2541 ***/
2542
2543IMPL_XSERIALIZABLE_TOCREATE(XMLUri)
2544
2545void XMLUri::serialize(XSerializeEngine& serEng)
2546{
2547
2548    if (serEng.isStoring())
2549    {
2550        serEng<<fPort;
2551        serEng.writeString(fScheme);
2552        serEng.writeString(fUserInfo);
2553        serEng.writeString(fHost);
2554        serEng.writeString(fRegAuth);
2555        serEng.writeString(fPath);
2556        serEng.writeString(fQueryString);
2557        serEng.writeString(fFragment);
2558        serEng.writeString(fURIText);
2559    }
2560    else
2561    {
2562        serEng>>fPort;
2563        serEng.readString(fScheme);
2564        serEng.readString(fUserInfo);
2565        serEng.readString(fHost);
2566        serEng.readString(fRegAuth);
2567        serEng.readString(fPath);
2568        serEng.readString(fQueryString);
2569        serEng.readString(fFragment);
2570        serEng.readString(fURIText);
2571    }
2572
2573}
2574
2575XMLUri::XMLUri(MemoryManager* const manager)
2576: fPort(-1)
2577, fScheme(0)
2578, fUserInfo(0)
2579, fHost(0)
2580, fRegAuth(0)
2581, fPath(0)
2582, fQueryString(0)
2583, fFragment(0)
2584, fURIText(0)
2585, fMemoryManager(manager)
2586{
2587}
2588
2589XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.