source: icXML/icXML-devel/src/xercesc/util/XMLURL.cpp @ 2732

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

Original Xerces files with import mods for icxercesc

File size: 42.2 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: XMLURL.cpp 901107 2010-01-20 08:45:02Z borisk $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <xercesc/util/BinFileInputStream.hpp>
27#include <xercesc/util/Janitor.hpp>
28#include <icxercesc/util/PlatformUtils.hpp>
29#include <xercesc/util/RuntimeException.hpp>
30#include <icxercesc/util/TransService.hpp>
31#include <xercesc/util/XMLURL.hpp>
32#include <xercesc/util/XMLNetAccessor.hpp>
33#include <icxercesc/util/XMLString.hpp>
34#include <xercesc/util/XMLUniDefs.hpp>
35#include <xercesc/util/XMLUni.hpp>
36#include <xercesc/util/XMLUri.hpp>
37#include <xercesc/util/OutOfMemoryException.hpp>
38#include <xercesc/util/XMLChar.hpp>
39
40XERCES_CPP_NAMESPACE_BEGIN
41
42
43
44// ---------------------------------------------------------------------------
45//  Local types
46//
47//  TypeEntry
48//      This structure defines a single entry in the list of URL types. Each
49//      entry indicates the prefix for that type of URL, and the SourceTypes
50//      value it maps to.
51// ---------------------------------------------------------------------------
52struct ProtoEntry
53{
54    XMLURL::Protocols   protocol;
55    const XMLCh*        prefix;
56    unsigned int        defPort;
57};
58
59
60// ---------------------------------------------------------------------------
61//  Local data
62//
63//  gXXXString
64//      These are the strings for our prefix types. They all have to be
65//      Unicode strings all the time, so we can't just do regular strings.
66//
67//  gProtoList
68//      The list of URL types that we support and some info related to each
69//      one.
70//
71//  gMaxProtoLen
72//      The length of the longest protocol string
73//
74//      NOTE:!!! Be sure to keep this up to date if new protocols are added!
75// ---------------------------------------------------------------------------
76static const XMLCh  gFileString[] =
77{
78        chLatin_f, chLatin_i, chLatin_l, chLatin_e, chNull
79};
80
81static const XMLCh gFTPString[]  =
82{
83        chLatin_f, chLatin_t, chLatin_p, chNull
84};
85
86static const XMLCh gHTTPString[] =
87{
88        chLatin_h, chLatin_t, chLatin_t, chLatin_p, chNull
89};
90
91static const XMLCh gHTTPSString[] =
92{
93        chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chNull
94};
95
96static ProtoEntry gProtoList[XMLURL::Protocols_Count] =
97{
98        { XMLURL::File     , gFileString    , 0  }
99    ,   { XMLURL::HTTP     , gHTTPString    , 80 }
100    ,   { XMLURL::FTP      , gFTPString     , 21 }
101    ,   { XMLURL::HTTPS    , gHTTPSString   , 443 }
102};
103
104// !!! Keep these up to date with list above!
105static const unsigned int gMaxProtoLen = 5;
106
107static const XMLCh gListOne[]    = { chColon, chForwardSlash, chNull };
108static const XMLCh gListTwo[]    = { chAt, chNull };
109static const XMLCh gListThree[]  = { chColon, chNull };
110static const XMLCh gListFour[]   = { chForwardSlash, chNull };
111static const XMLCh gListFive[]   = { chPound, chQuestion, chNull };
112static const XMLCh gListSix[]    = { chPound, chNull };
113
114// ---------------------------------------------------------------------------
115//  Local methods
116// ---------------------------------------------------------------------------
117static bool isHexDigit(const XMLCh toCheck)
118{
119    if (((toCheck >= chDigit_0) && (toCheck <= chDigit_9))
120    ||  ((toCheck >= chLatin_A) && (toCheck <= chLatin_Z))
121    ||  ((toCheck >= chLatin_a) && (toCheck <= chLatin_z)))
122    {
123        return true;
124    }
125    return false;
126}
127
128static unsigned int xlatHexDigit(const XMLCh toXlat)
129{
130    if ((toXlat >= chDigit_0) && (toXlat <= chDigit_9))
131        return (unsigned int)(toXlat - chDigit_0);
132
133    if ((toXlat >= chLatin_A) && (toXlat <= chLatin_Z))
134        return (unsigned int)(toXlat - chLatin_A) + 10;
135
136    return (unsigned int)(toXlat - chLatin_a) + 10;
137}
138
139
140
141// ---------------------------------------------------------------------------
142//  XMLURL: Public, static methods
143// ---------------------------------------------------------------------------
144XMLURL::Protocols XMLURL::lookupByName(const XMLCh* const protoName)
145{
146    for (unsigned int index = 0; index < XMLURL::Protocols_Count; index++)
147    {
148        if (!XMLString::compareIStringASCII(protoName, gProtoList[index].prefix))
149            return gProtoList[index].protocol;
150    }
151    return XMLURL::Unknown;
152}
153
154
155
156// ---------------------------------------------------------------------------
157//  XMLURL: Constructors and Destructor
158// ---------------------------------------------------------------------------
159XMLURL::XMLURL(MemoryManager* const manager) :
160
161    fMemoryManager(manager)
162    , fFragment(0)
163    , fHost(0)
164    , fPassword(0)
165    , fPath(0)
166    , fPortNum(0)
167    , fProtocol(XMLURL::Unknown)
168    , fQuery(0)
169    , fUser(0)
170    , fURLText(0)
171    , fHasInvalidChar(false)
172{
173}
174
175typedef JanitorMemFunCall<XMLURL>   CleanupType;
176
177XMLURL::XMLURL(const XMLCh* const    baseURL
178             , const XMLCh* const    relativeURL
179             , MemoryManager* const manager) :
180
181    fMemoryManager(manager)
182    , fFragment(0)
183    , fHost(0)
184    , fPassword(0)
185    , fPath(0)
186    , fPortNum(0)
187    , fProtocol(XMLURL::Unknown)
188    , fQuery(0)
189    , fUser(0)
190    , fURLText(0)
191    , fHasInvalidChar(false)
192{
193    CleanupType cleanup(this, &XMLURL::cleanUp);
194
195        try
196        {
197        setURL(baseURL, relativeURL);
198        }
199    catch(const OutOfMemoryException&)
200    {
201        cleanup.release();
202
203        throw;
204    }
205
206    cleanup.release();
207}
208
209XMLURL::XMLURL(const XMLCh* const  baseURL
210             , const char* const   relativeURL
211             , MemoryManager* const manager) :
212
213    fMemoryManager(manager)
214    , fFragment(0)
215    , fHost(0)
216    , fPassword(0)
217    , fPath(0)
218    , fPortNum(0)
219    , fProtocol(XMLURL::Unknown)
220    , fQuery(0)
221    , fUser(0)
222    , fURLText(0)
223    , fHasInvalidChar(false)
224{
225    CleanupType cleanup(this, &XMLURL::cleanUp);
226
227    XMLCh* tmpRel = XMLString::transcode(relativeURL, fMemoryManager);
228    ArrayJanitor<XMLCh> janRel(tmpRel, fMemoryManager);
229        try
230        {
231                setURL(baseURL, tmpRel);
232        }
233    catch(const OutOfMemoryException&)
234    {
235        cleanup.release();
236
237        throw;
238    }
239
240    cleanup.release();
241}
242
243XMLURL::XMLURL(const XMLURL&         baseURL
244             , const XMLCh* const    relativeURL) :
245
246    fMemoryManager(baseURL.fMemoryManager)
247    , fFragment(0)
248    , fHost(0)
249    , fPassword(0)
250    , fPath(0)
251    , fPortNum(0)
252    , fProtocol(XMLURL::Unknown)
253    , fQuery(0)
254    , fUser(0)
255    , fURLText(0)
256    , fHasInvalidChar(false)
257{
258    CleanupType cleanup(this, &XMLURL::cleanUp);
259
260        try
261        {
262                setURL(baseURL, relativeURL);
263        }
264    catch(const OutOfMemoryException&)
265    {
266        cleanup.release();
267
268        throw;
269    }
270
271    cleanup.release();
272}
273
274XMLURL::XMLURL(const  XMLURL&        baseURL
275             , const char* const     relativeURL) :
276
277    fMemoryManager(baseURL.fMemoryManager)
278    , fFragment(0)
279    , fHost(0)
280    , fPassword(0)
281    , fPath(0)
282    , fPortNum(0)
283    , fProtocol(XMLURL::Unknown)
284    , fQuery(0)
285    , fUser(0)
286    , fURLText(0)
287    , fHasInvalidChar(false)
288{
289    CleanupType cleanup(this, &XMLURL::cleanUp);
290
291    XMLCh* tmpRel = XMLString::transcode(relativeURL, fMemoryManager);
292    ArrayJanitor<XMLCh> janRel(tmpRel, fMemoryManager);
293        try
294        {
295                setURL(baseURL, tmpRel);
296        }
297    catch(const OutOfMemoryException&)
298    {
299        cleanup.release();
300
301        throw;
302    }
303
304    cleanup.release();
305}
306
307XMLURL::XMLURL(const XMLCh* const urlText,
308               MemoryManager* const manager) :
309
310    fMemoryManager(manager)
311    , fFragment(0)
312    , fHost(0)
313    , fPassword(0)
314    , fPath(0)
315    , fPortNum(0)
316    , fProtocol(XMLURL::Unknown)
317    , fQuery(0)
318    , fUser(0)
319    , fURLText(0)
320    , fHasInvalidChar(false)
321{
322    CleanupType cleanup(this, &XMLURL::cleanUp);
323
324        try
325        {
326            setURL(urlText);
327        }
328    catch(const OutOfMemoryException&)
329    {
330        cleanup.release();
331
332        throw;
333    }
334
335    cleanup.release();
336}
337
338XMLURL::XMLURL(const char* const urlText,
339               MemoryManager* const manager) :
340
341    fMemoryManager(manager)
342    , fFragment(0)
343    , fHost(0)
344    , fPassword(0)
345    , fPath(0)
346    , fPortNum(0)
347    , fProtocol(XMLURL::Unknown)
348    , fQuery(0)
349    , fUser(0)
350    , fURLText(0)
351    , fHasInvalidChar(false)
352{
353    CleanupType cleanup(this, &XMLURL::cleanUp);
354
355    XMLCh* tmpText = XMLString::transcode(urlText, fMemoryManager);
356    ArrayJanitor<XMLCh> janRel(tmpText, fMemoryManager);
357        try
358        {
359            setURL(tmpText);
360        }
361    catch(const OutOfMemoryException&)
362    {
363        cleanup.release();
364
365        throw;
366    }
367
368    cleanup.release();
369}
370
371XMLURL::XMLURL(const XMLURL& toCopy) :
372    XMemory(toCopy)
373    , fMemoryManager(toCopy.fMemoryManager)
374    , fFragment(0)
375    , fHost(0)
376    , fPassword(0)
377    , fPath(0)
378    , fPortNum(toCopy.fPortNum)
379    , fProtocol(toCopy.fProtocol)
380    , fQuery(0)
381    , fUser(0)
382    , fURLText(0)
383    , fHasInvalidChar(toCopy.fHasInvalidChar)
384{
385    CleanupType cleanup(this, &XMLURL::cleanUp);
386
387    try
388    {
389        fFragment = XMLString::replicate(toCopy.fFragment, fMemoryManager);
390        fHost = XMLString::replicate(toCopy.fHost, fMemoryManager);
391        fPassword = XMLString::replicate(toCopy.fPassword, fMemoryManager);
392        fPath = XMLString::replicate(toCopy.fPath, fMemoryManager);
393        fQuery = XMLString::replicate(toCopy.fQuery, fMemoryManager);
394        fUser = XMLString::replicate(toCopy.fUser, fMemoryManager);
395        fURLText = XMLString::replicate(toCopy.fURLText, fMemoryManager);
396    }
397    catch(const OutOfMemoryException&)
398    {
399        cleanup.release();
400
401        throw;
402    }
403
404    cleanup.release();
405}
406
407XMLURL::~XMLURL()
408{
409    cleanUp();
410}
411
412
413// ---------------------------------------------------------------------------
414//  XMLURL: Public operators
415// ---------------------------------------------------------------------------
416XMLURL& XMLURL::operator=(const XMLURL& toAssign)
417{
418    if (this == &toAssign)
419        return *this;
420
421    // Clean up our stuff
422    cleanUp();
423
424    // And copy his stuff
425    fMemoryManager = toAssign.fMemoryManager;
426    fFragment = XMLString::replicate(toAssign.fFragment, fMemoryManager);
427    fHost = XMLString::replicate(toAssign.fHost, fMemoryManager);
428    fPassword = XMLString::replicate(toAssign.fPassword, fMemoryManager);
429    fPath = XMLString::replicate(toAssign.fPath, fMemoryManager);
430    fPortNum = toAssign.fPortNum;
431    fProtocol = toAssign.fProtocol;
432    fQuery = XMLString::replicate(toAssign.fQuery, fMemoryManager);
433    fUser = XMLString::replicate(toAssign.fUser, fMemoryManager);
434    fURLText = XMLString::replicate(toAssign.fURLText, fMemoryManager);
435    fHasInvalidChar = toAssign.fHasInvalidChar;
436
437    return *this;
438}
439
440bool XMLURL::operator==(const XMLURL& toCompare) const
441{
442    //
443    //  Compare the two complete URLs (which have been processed the same
444    //  way so they should now be the same even if they came in via different
445    //  relative parts.
446    //
447    if (!XMLString::equals(getURLText(), toCompare.getURLText()))
448        return false;
449
450    return true;
451}
452
453
454
455// ---------------------------------------------------------------------------
456//  XMLURL: Getter methods
457// ---------------------------------------------------------------------------
458unsigned int XMLURL::getPortNum() const
459{
460    //
461    //  If it was not provided explicitly, then lets return the default one
462    //  for the protocol.
463    //
464    if (!fPortNum)
465    {
466        if (fProtocol == Unknown)
467            return 0;
468        return gProtoList[fProtocol].defPort;
469    }
470    return fPortNum;
471}
472
473
474const XMLCh* XMLURL::getProtocolName() const
475{
476    // Check to see if its ever been set
477    if (fProtocol == Unknown)
478        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
479
480    return gProtoList[fProtocol].prefix;
481}
482
483
484// ---------------------------------------------------------------------------
485//  XMLURL: Setter methods
486// ---------------------------------------------------------------------------
487void XMLURL::setURL(const XMLCh* const urlText)
488{
489    //
490    //  Try to parse the URL.
491    //
492    cleanUp();
493    parse(urlText);
494}
495
496void XMLURL::setURL(const XMLCh* const    baseURL
497                  , const XMLCh* const    relativeURL)
498{
499    cleanUp();
500
501    // Parse our URL string
502    parse(relativeURL);
503
504        //
505        //  If its relative and the base is non-null and non-empty, then
506        //  parse the base URL string and conglomerate them.
507        //
508        if (isRelative() && baseURL)
509        {
510                if (*baseURL)
511                {
512                        XMLURL basePart(baseURL, fMemoryManager);
513                        if (!conglomerateWithBase(basePart, false))
514                        {
515                                cleanUp();
516                                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_RelativeBaseURL, fMemoryManager);
517                        }
518                }
519        }
520}
521
522// this version of setURL doesn't throw a malformedurl exception
523// instead it returns false when it failed (or when it would of
524// thrown a malformedurl exception)
525bool XMLURL::setURL(const XMLCh* const    baseURL
526                  , const XMLCh* const    relativeURL
527                  , XMLURL& xmlURL)
528{
529    cleanUp();
530
531    // Parse our URL string
532    if (parse(relativeURL, xmlURL))
533    {
534            //  If its relative and the base is non-null and non-empty, then
535            //  parse the base URL string and conglomerate them.
536            //
537            if (isRelative() && baseURL && *baseURL)
538            {
539                XMLURL basePart(fMemoryManager);
540            if (parse(baseURL, basePart)  && conglomerateWithBase(basePart, false))
541            {
542                        return true;
543                    }
544            }
545        else
546            return true;
547    }
548    return false;
549}
550
551void XMLURL::setURL(const XMLURL&         baseURL
552                  , const XMLCh* const    relativeURL)
553{
554    cleanUp();
555
556        // Parse our URL string
557    parse(relativeURL);
558
559    // If its relative, then conglomerate with the base URL
560    if (isRelative())
561                conglomerateWithBase(baseURL);
562}
563
564
565// ---------------------------------------------------------------------------
566//  XMLURL: Miscellaneous methods
567// ---------------------------------------------------------------------------
568bool XMLURL::isRelative() const
569{
570    // If no protocol then relative
571    if (fProtocol == Unknown)
572        return true;
573
574    // If no path, or the path is not absolute, then relative
575    if (!fPath)
576        return true;
577
578    if (*fPath != chForwardSlash)
579        return true;
580
581    return false;
582}
583
584
585bool XMLURL::hasInvalidChar() const {
586    return fHasInvalidChar;
587}
588
589
590BinInputStream* XMLURL::makeNewStream() const
591{
592    //
593    //  If its a local host, then we short circuit it and use our own file
594    //  stream support. Otherwise, we just let it fall through and let the
595    //  installed network access object provide a stream.
596    //
597    if (fProtocol == XMLURL::File)
598    {
599        if (!fHost || !XMLString::compareIStringASCII(fHost, XMLUni::fgLocalHostString))
600        {
601
602            XMLCh* realPath = XMLString::replicate(fPath, fMemoryManager);
603            ArrayJanitor<XMLCh> basePathName(realPath, fMemoryManager);
604
605            //
606            // Need to manually replace any character reference %xx first
607            // HTTP protocol will be done automatically by the netaccessor
608            //
609            XMLSize_t end = XMLString::stringLen(realPath);
610            int percentIndex = XMLString::indexOf(realPath, chPercent, 0, fMemoryManager);
611
612            while (percentIndex != -1) {
613
614                if (percentIndex+2 >= (int)end ||
615                    !isHexDigit(realPath[percentIndex+1]) ||
616                    !isHexDigit(realPath[percentIndex+2]))
617                {
618                    XMLCh value1[4];
619                    XMLString::moveChars(value1, &(realPath[percentIndex]), 3);
620                    value1[3] = chNull;
621                    ThrowXMLwithMemMgr2(MalformedURLException
622                            , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence
623                            , realPath
624                            , value1
625                            , fMemoryManager);
626                }
627
628                unsigned int value = (xlatHexDigit(realPath[percentIndex+1]) * 16) + xlatHexDigit(realPath[percentIndex+2]);
629
630                realPath[percentIndex] = XMLCh(value);
631
632                XMLSize_t i =0;
633                for (i = percentIndex + 1; i < end - 2 ; i++)
634                    realPath[i] = realPath[i+2];
635                realPath[i] = chNull;
636                end = i;
637
638                if (((XMLSize_t)(percentIndex + 1)) < end)
639                  percentIndex = XMLString::indexOf(realPath, chPercent, percentIndex + 1, fMemoryManager);
640                else
641                  percentIndex = -1;
642            }
643
644
645            BinFileInputStream* retStrm = new (fMemoryManager) BinFileInputStream(realPath, fMemoryManager);
646            if (!retStrm->getIsOpen())
647            {
648                delete retStrm;
649                return 0;
650            }
651            return retStrm;
652        }
653    }
654
655    //
656    //  If we don't have have an installed net accessor object, then we
657    //  have to just throw here.
658    //
659    if (!XMLPlatformUtils::fgNetAccessor)
660        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_UnsupportedProto, fMemoryManager);
661
662    // Else ask the net accessor to create the stream
663    return XMLPlatformUtils::fgNetAccessor->makeNew(*this);
664}
665
666void XMLURL::makeRelativeTo(const XMLCh* const baseURLText)
667{
668    // If this one is not relative, don't bother
669    if (!isRelative())
670        return;
671
672    XMLURL baseURL(baseURLText, fMemoryManager);
673    conglomerateWithBase(baseURL);
674}
675
676void XMLURL::makeRelativeTo(const XMLURL& baseURL)
677{
678    // If this one is not relative, don't bother
679    if (!isRelative())
680        return;
681    conglomerateWithBase(baseURL);
682}
683
684
685
686
687// ---------------------------------------------------------------------------
688//  XMLURL: Private helper methods
689// ---------------------------------------------------------------------------
690
691//
692//  This method will take the broken out parts of the URL and build up the
693//  full text. We don't do this unless someone asks us to, since its often
694//  never required.
695//
696void XMLURL::buildFullText()
697{
698    // Calculate the worst case size of the buffer required
699    XMLSize_t bufSize = gMaxProtoLen + 1
700                           + XMLString::stringLen(fFragment) + 1
701                           + XMLString::stringLen(fHost) + 2
702                           + XMLString::stringLen(fPassword) + 1
703                           + XMLString::stringLen(fPath)
704                           + XMLString::stringLen(fQuery) + 1
705                           + XMLString::stringLen(fUser) + 1
706                           + 32;
707
708    // Clean up the existing buffer and allocate another
709    fMemoryManager->deallocate(fURLText);//delete [] fURLText;
710    fURLText = (XMLCh*) fMemoryManager->allocate((bufSize) * sizeof(XMLCh));//new XMLCh[bufSize];
711    *fURLText = 0;
712
713    XMLCh* outPtr = fURLText;
714    if (fProtocol != Unknown)
715    {
716        XMLString::catString(fURLText, getProtocolName());
717        outPtr += XMLString::stringLen(fURLText);
718        *outPtr++ = chColon;
719        *outPtr++ = chForwardSlash;
720        *outPtr++ = chForwardSlash;
721    }
722
723    if (fUser)
724    {
725        XMLString::copyString(outPtr, fUser);
726        outPtr += XMLString::stringLen(fUser);
727
728        if (fPassword)
729        {
730            *outPtr++ = chColon;
731            XMLString::copyString(outPtr, fPassword);
732            outPtr += XMLString::stringLen(fPassword);
733        }
734
735        *outPtr++ = chAt;
736    }
737
738    if (fHost)
739    {
740        XMLString::copyString(outPtr, fHost);
741        outPtr += XMLString::stringLen(fHost);
742
743        //
744        //  If the port is zero, then we don't put it in. Else we need
745        //  to because it was explicitly provided.
746        //
747        if (fPortNum)
748        {
749            *outPtr++ = chColon;
750
751            XMLCh tmpBuf[17];
752            XMLString::binToText(fPortNum, tmpBuf, 16, 10, fMemoryManager);
753            XMLString::copyString(outPtr, tmpBuf);
754            outPtr += XMLString::stringLen(tmpBuf);
755        }
756    }
757
758    if (fPath)
759    {
760        XMLString::copyString(outPtr, fPath);
761        outPtr += XMLString::stringLen(fPath);
762    }
763
764    if (fQuery)
765    {
766        *outPtr++ = chQuestion;
767        XMLString::copyString(outPtr, fQuery);
768        outPtr += XMLString::stringLen(fQuery);
769    }
770
771    if (fFragment)
772    {
773        *outPtr++ = chPound;
774        XMLString::copyString(outPtr, fFragment);
775        outPtr += XMLString::stringLen(fFragment);
776    }
777
778    // Cap it off in case the last op was not a string copy
779    *outPtr = 0;
780}
781
782
783//
784//  Just a central place to handle cleanup, since its done from a number
785//  of different spots.
786//
787void XMLURL::cleanUp()
788{
789    fMemoryManager->deallocate(fFragment);//delete [] fFragment;
790    fMemoryManager->deallocate(fHost);//delete [] fHost;
791    fMemoryManager->deallocate(fPassword);//delete [] fPassword;
792    fMemoryManager->deallocate(fPath);//delete [] fPath;
793    fMemoryManager->deallocate(fQuery);//delete [] fQuery;
794    fMemoryManager->deallocate(fUser);//delete [] fUser;
795    fMemoryManager->deallocate(fURLText);//delete [] fURLText;
796
797    fFragment = 0;
798    fHost = 0;
799    fPassword = 0;
800    fPath = 0;
801    fQuery = 0;
802    fUser = 0;
803    fURLText = 0;
804
805    fProtocol = Unknown;
806    fPortNum = 0;
807    fHasInvalidChar = false;
808}
809
810
811//This function  has been modified to take a bool parameter and the
812//functionality inside looks irrational but is only to make
813//solaris 2.7 CC 5.0 optimized build happy.
814
815bool XMLURL::conglomerateWithBase(const XMLURL& baseURL, bool useExceptions)
816{
817    // The base URL cannot be relative
818    if (baseURL.isRelative())
819    {
820        if (useExceptions)
821                        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_RelativeBaseURL, fMemoryManager);
822        else
823            return false;
824    }
825
826    //
827    //  Check a special case. If all we have is a fragment, then we want
828    //  to just take the base host and path, plus our fragment.
829    //
830    if ((fProtocol == Unknown)
831    &&  !fHost
832    &&  !fPath
833    &&  fFragment)
834    {
835        // Just in case, make sure we don't leak the user or password values
836        fMemoryManager->deallocate(fUser);//delete [] fUser;
837        fUser = 0;
838        fMemoryManager->deallocate(fPassword);//delete [] fPassword;
839        fPassword = 0;
840
841        // Copy over the protocol and port number as is
842        fProtocol = baseURL.fProtocol;
843        fPortNum = baseURL.fPortNum;
844
845        // Replicate the base fields that are provided
846        fHost = XMLString::replicate(baseURL.fHost, fMemoryManager);
847        fUser = XMLString::replicate(baseURL.fUser, fMemoryManager);
848        fPassword = XMLString::replicate(baseURL.fPassword, fMemoryManager);
849        fPath = XMLString::replicate(baseURL.fPath, fMemoryManager);
850        return true;
851    }
852
853    //
854    //  All we have to do is run up through our fields and, for each one
855    //  that we don't have, use the based URL's. Once we hit one field
856    //  that we have, we stop.
857    //
858    if (fProtocol != Unknown)
859        return true;
860    fProtocol = baseURL.fProtocol;
861
862    //
863    //  If the protocol is not file, and we either already have our own
864    //  host, or the base does not have one, then we are done.
865    //
866    if (fProtocol != File)
867    {
868        if (fHost || !baseURL.fHost)
869            return true;
870    }
871
872    // Replicate all of the hosty stuff if the base has one
873    if (baseURL.fHost)
874    {
875        // Just in case, make sure we don't leak a user or password field
876        fMemoryManager->deallocate(fUser);//delete [] fUser;
877        fUser = 0;
878        fMemoryManager->deallocate(fPassword);//delete [] fPassword;
879        fPassword = 0;
880        fMemoryManager->deallocate(fHost);//delete [] fHost;
881        fHost = 0;
882
883        fHost = XMLString::replicate(baseURL.fHost, fMemoryManager);
884        fUser = XMLString::replicate(baseURL.fUser, fMemoryManager);
885        fPassword = XMLString::replicate(baseURL.fPassword, fMemoryManager);
886
887        fPortNum = baseURL.fPortNum;
888    }
889
890    // If we have a path and its absolute, then we are done
891    const bool hadPath = (fPath != 0);
892    if (hadPath)
893    {
894        if (*fPath == chForwardSlash)
895            return true;
896    }
897
898    // Its a relative path, so weave them together.
899    if (baseURL.fPath) {
900        XMLCh* temp = XMLPlatformUtils::weavePaths(baseURL.fPath, fPath ,fMemoryManager);
901        fMemoryManager->deallocate(fPath);//delete [] fPath;
902        fPath = temp;
903    }
904
905    // If we had any original path, then we are done
906    if (hadPath)
907        return true;
908
909    // We had no original path, so go on to deal with the query/fragment parts
910    if (fQuery || !baseURL.fQuery)
911        return true;
912    fQuery = XMLString::replicate(baseURL.fQuery, fMemoryManager);
913
914    if (fFragment || !baseURL.fFragment)
915        return true;
916    fFragment = XMLString::replicate(baseURL.fFragment, fMemoryManager);
917        return true;
918}
919
920
921void XMLURL::parse(const XMLCh* const urlText)
922{
923    // Simplify things by checking for the psycho scenarios first
924    if (!*urlText)
925        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
926
927    // Before we start, check if this urlText contains valid uri characters
928    if (!XMLUri::isURIString(urlText))
929        fHasInvalidChar = true;
930    else
931        fHasInvalidChar = false;
932
933    //
934    //  The first thing we will do is to check for a file name, so that
935    //  we don't waste time thinking its a URL. If its in the form x:\ or x:/
936    //  and x is an ASCII letter, then assume that's the deal.
937    //
938    if (((*urlText >= chLatin_A) && (*urlText <= chLatin_Z))
939    ||  ((*urlText >= chLatin_a) && (*urlText <= chLatin_z)))
940    {
941        if (*(urlText + 1) == chColon)
942        {
943            if ((*(urlText + 2) == chForwardSlash)
944            ||  (*(urlText + 2) == chBackSlash))
945            {
946                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
947            }
948        }
949    }
950
951    // Get a copy of the URL that we can modify
952    XMLCh* srcCpy = XMLString::replicate(urlText, fMemoryManager);
953    ArrayJanitor<XMLCh> janSrcCopy(srcCpy, fMemoryManager);
954
955    //
956    //  Get a pointer now that we can run up thrown the source as we parse
957    //  bits and pieces out of it.
958    //
959    XMLCh* srcPtr = srcCpy;
960
961    // Run up past any spaces
962    while (*srcPtr)
963    {
964        if (!XMLChar1_0::isWhitespace(*srcPtr))
965            break;
966        srcPtr++;
967    }
968
969    // Make sure it wasn't all space
970    if (!*srcPtr)
971        ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager);
972
973    //
974    //  Ok, the next thing we have to do is to find either a / or : character.
975    //  If the : is first, we assume we have a protocol. If the / is first,
976    //  then we skip to the host processing.
977    //
978    XMLCh* ptr1 = XMLString::findAny(srcPtr, gListOne);
979    XMLCh* ptr2;
980
981    // If we found a protocol, then deal with it
982    if (ptr1)
983    {
984        if (*ptr1 == chColon)
985        {
986            // Cap the string at the colon
987            *ptr1 = 0;
988
989            // And try to find it in our list of protocols
990            fProtocol = lookupByName(srcPtr);
991
992            if (fProtocol == Unknown)
993            {
994                ThrowXMLwithMemMgr1
995                (
996                    MalformedURLException
997                    , XMLExcepts::URL_UnsupportedProto1
998                    , srcPtr
999                    , fMemoryManager
1000                );
1001            }
1002
1003            // And move our source pointer up past what we've processed
1004            srcPtr = (ptr1 + 1);
1005        }
1006    }
1007
1008    //
1009    //  Ok, next we need to see if we have any host part. If the next
1010    //  two characters are //, then we need to check, else move on.
1011    //
1012    if ((*srcPtr == chForwardSlash) && (*(srcPtr + 1) == chForwardSlash))
1013    {
1014        // Move up past the slashes
1015        srcPtr += 2;
1016
1017        //
1018        //  If we aren't at the end of the string, then there has to be a
1019        //  host part at this point. we will just look for the next / char
1020        //  or end of string and make all of that the host for now.
1021        //
1022        if (*srcPtr)
1023        {
1024            // Search from here for a / character
1025            ptr1 = XMLString::findAny(srcPtr, gListFour);
1026
1027            //
1028            //  If we found something, then the host is between where
1029            //  we are and what we found. Else the host is the rest of
1030            //  the content and we are done. If its empty, leave it null.
1031            //
1032            if (ptr1)
1033            {
1034                if (ptr1 != srcPtr)
1035                {
1036                    fMemoryManager->deallocate(fHost);//delete [] fHost;
1037                    fHost = (XMLCh*) fMemoryManager->allocate
1038                    (
1039                        ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1040                    );//new XMLCh[(ptr1 - srcPtr) + 1];
1041                    ptr2 = fHost;
1042                    while (srcPtr < ptr1)
1043                        *ptr2++ = *srcPtr++;
1044                    *ptr2 = 0;
1045                }
1046            }
1047             else
1048            {
1049                fMemoryManager->deallocate(fHost);//delete [] fHost;
1050                fHost = XMLString::replicate(srcPtr, fMemoryManager);
1051
1052                // Update source pointer to the end
1053                srcPtr += XMLString::stringLen(fHost);
1054            }
1055        }
1056    }
1057    else
1058    {
1059        //
1060        // http protocol requires two forward slashes
1061        // we didn't get them, so throw an exception
1062        //
1063        if (fProtocol == HTTP) {
1064            ThrowXMLwithMemMgr
1065                (
1066                    MalformedURLException
1067                    , XMLExcepts::URL_ExpectingTwoSlashes
1068                    , fMemoryManager
1069                );
1070        }
1071    }
1072
1073    //
1074    //  If there was a host part, then we have to grovel through it for
1075    //  all the bits and pieces it can hold.
1076    //
1077    if (fHost)
1078    {
1079        //
1080        //  Look for a '@' character, which indicates a user name. If we
1081        //  find one, then everything between the start of the host data
1082        //  and the character is the user name.
1083        //
1084        ptr1 = XMLString::findAny(fHost, gListTwo);
1085        if (ptr1)
1086        {
1087            // Get this info out as the user name
1088            *ptr1 = 0;
1089            fMemoryManager->deallocate(fUser);//delete [] fUser;
1090            fUser = XMLString::replicate(fHost, fMemoryManager);
1091            ptr1++;
1092
1093            // And now cut these chars from the host string
1094            XMLString::cut(fHost, ptr1 - fHost);
1095
1096            // Is there a password inside the user string?
1097            ptr2 = XMLString::findAny(fUser, gListThree);
1098            if (ptr2)
1099            {
1100                // Remove it from the user name string
1101                *ptr2 = 0;
1102
1103                // And copy out the remainder to the password field
1104                ptr2++;
1105                fMemoryManager->deallocate(fPassword);//delete [] fPassword;
1106                fPassword = XMLString::replicate(ptr2, fMemoryManager);
1107            }
1108        }
1109
1110        //
1111        //  Ok, so now we are at the actual host name, if any. If we are
1112        //  not at the end of the host data, then lets see if we have a
1113        //  port trailing the
1114        //
1115        ptr1 = XMLString::findAny(fHost, gListThree);
1116        if (ptr1)
1117        {
1118            // Remove it from the host name
1119            *ptr1 = 0;
1120
1121            // Try to convert it to a numeric port value and store it
1122            ptr1++;
1123            if (!XMLString::textToBin(ptr1, fPortNum, fMemoryManager))
1124                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_BadPortField, fMemoryManager);
1125        }
1126
1127        // If the host ended up empty, then toss is
1128        if (!*fHost)
1129        {
1130            fMemoryManager->deallocate(fHost);//delete[] fHost;
1131            fHost = 0;
1132        }
1133    }
1134
1135    // If we are at the end, then we are done now
1136    if (!*srcPtr) {
1137        if(fHost) {
1138            static const XMLCh slash[] = { chForwardSlash, chNull };
1139            fPath = XMLString::replicate(slash, fMemoryManager);
1140        }
1141        return;
1142    }
1143
1144    //
1145    //  Next is the path part. It can be absolute, i.e. starting with a
1146    //  forward slash character, or relative. Its basically everything up
1147    //  to the end of the string or to any trailing query or fragment.
1148    //
1149    ptr1 = XMLString::findAny(srcPtr, gListFive);
1150    if (!ptr1)
1151    {
1152        fMemoryManager->deallocate(fPath);//delete [] fPath;
1153        fPath = XMLString::replicate(srcPtr, fMemoryManager);
1154        return;
1155    }
1156
1157    // Everything from where we are to what we found is the path
1158    if (ptr1 > srcPtr)
1159    {
1160        fMemoryManager->deallocate(fPath);//delete [] fPath;
1161        fPath = (XMLCh*) fMemoryManager->allocate
1162        (
1163            ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1164        );//new XMLCh[(ptr1 - srcPtr) + 1];
1165        ptr2 = fPath;
1166        while (srcPtr < ptr1)
1167            *ptr2++ = *srcPtr++;
1168        *ptr2 = 0;
1169    }
1170
1171    //
1172    //  If we found a fragment, then it is the rest of the string and we
1173    //  are done.
1174    //
1175    if (*srcPtr == chPound)
1176    {
1177        srcPtr++;
1178        fMemoryManager->deallocate(fFragment);//delete [] fFragment;
1179        fFragment = XMLString::replicate(srcPtr, fMemoryManager);
1180        return;
1181    }
1182
1183    //
1184    //  The query is either the rest of the string, or up to the fragment
1185    //  separator.
1186    //
1187    srcPtr++;
1188    ptr1 = XMLString::findAny(srcPtr, gListSix);
1189    fMemoryManager->deallocate(fQuery);//delete [] fQuery;
1190    if (!ptr1)
1191    {
1192        fQuery = XMLString::replicate(srcPtr, fMemoryManager);
1193        return;
1194    }
1195     else
1196    {
1197        fQuery = (XMLCh*) fMemoryManager->allocate
1198        (
1199            ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1200        );//new XMLCh[(ptr1 - srcPtr) + 1];
1201        ptr2 = fQuery;
1202        while (srcPtr < ptr1)
1203            *ptr2++ = *srcPtr++;
1204        *ptr2 = 0;
1205    }
1206
1207    // If we are not at the end now, then everything else is the fragment
1208    if (*srcPtr == chPound)
1209    {
1210        srcPtr++;
1211        fMemoryManager->deallocate(fFragment);//delete [] fFragment;
1212        fFragment = XMLString::replicate(srcPtr, fMemoryManager);
1213    }
1214}
1215
1216bool XMLURL::parse(const XMLCh* const urlText, XMLURL& xmlURL)
1217{
1218    // Simplify things by checking for the psycho scenarios first
1219    if (!*urlText)
1220        return false;
1221
1222    // Before we start, check if this urlText contains valid uri characters
1223    if (!XMLUri::isURIString(urlText))
1224        xmlURL.fHasInvalidChar = true;
1225    else
1226        xmlURL.fHasInvalidChar = false;
1227
1228    //
1229    //  The first thing we will do is to check for a file name, so that
1230    //  we don't waste time thinking its a URL. If its in the form x:\ or x:/
1231    //  and x is an ASCII letter, then assume that's the deal.
1232    //
1233    if (((*urlText >= chLatin_A) && (*urlText <= chLatin_Z))
1234    ||  ((*urlText >= chLatin_a) && (*urlText <= chLatin_z)))
1235    {
1236        if (*(urlText + 1) == chColon)
1237        {
1238            if ((*(urlText + 2) == chForwardSlash)
1239            ||  (*(urlText + 2) == chBackSlash))
1240            {
1241                return false;
1242            }
1243        }
1244    }
1245
1246    // Get a copy of the URL that we can modify
1247    XMLCh* srcCpy = XMLString::replicate(urlText, xmlURL.fMemoryManager);
1248    ArrayJanitor<XMLCh> janSrcCopy(srcCpy, xmlURL.fMemoryManager);
1249
1250    //
1251    //  Get a pointer now that we can run up thrown the source as we parse
1252    //  bits and pieces out of it.
1253    //
1254    XMLCh* srcPtr = srcCpy;
1255
1256    // Run up past any spaces
1257    while (*srcPtr)
1258    {
1259        if (!XMLChar1_0::isWhitespace(*srcPtr))
1260            break;
1261        srcPtr++;
1262    }
1263
1264    // Make sure it wasn't all space
1265    if (!*srcPtr)
1266        return false;
1267
1268    //
1269    //  Ok, the next thing we have to do is to find either a / or : character.
1270    //  If the : is first, we assume we have a protocol. If the / is first,
1271    //  then we skip to the host processing.
1272    //
1273    XMLCh* ptr1 = XMLString::findAny(srcPtr, gListOne);
1274    XMLCh* ptr2;
1275
1276    // If we found a protocol, then deal with it
1277    if (ptr1)
1278    {
1279        if (*ptr1 == chColon)
1280        {
1281            // Cap the string at the colon
1282            *ptr1 = 0;
1283
1284            // And try to find it in our list of protocols
1285            xmlURL.fProtocol = lookupByName(srcPtr);
1286
1287            if (xmlURL.fProtocol == Unknown)
1288                return false;
1289
1290            // And move our source pointer up past what we've processed
1291            srcPtr = (ptr1 + 1);
1292        }
1293    }
1294
1295    //
1296    //  Ok, next we need to see if we have any host part. If the next
1297    //  two characters are //, then we need to check, else move on.
1298    //
1299    if ((*srcPtr == chForwardSlash) && (*(srcPtr + 1) == chForwardSlash))
1300    {
1301        // Move up past the slashes
1302        srcPtr += 2;
1303
1304        //
1305        //  If we aren't at the end of the string, then there has to be a
1306        //  host part at this point. we will just look for the next / char
1307        //  or end of string and make all of that the host for now.
1308        //
1309        if (*srcPtr)
1310        {
1311            // Search from here for a / character
1312            ptr1 = XMLString::findAny(srcPtr, gListFour);
1313
1314            //
1315            //  If we found something, then the host is between where
1316            //  we are and what we found. Else the host is the rest of
1317            //  the content and we are done. If its empty, leave it null.
1318            //
1319            if (ptr1)
1320            {
1321                if (ptr1 != srcPtr)
1322                {
1323                    xmlURL.fHost = (XMLCh*) xmlURL.fMemoryManager->allocate
1324                    (
1325                        ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1326                    );//new XMLCh[(ptr1 - srcPtr) + 1];
1327                    ptr2 = xmlURL.fHost;
1328                    while (srcPtr < ptr1)
1329                        *ptr2++ = *srcPtr++;
1330                    *ptr2 = 0;
1331                }
1332            }
1333             else
1334            {
1335                xmlURL.fHost = XMLString::replicate(srcPtr, xmlURL.fMemoryManager);
1336
1337                // Update source pointer to the end
1338                srcPtr += XMLString::stringLen(xmlURL.fHost);
1339            }
1340        }
1341    }
1342    else
1343    {
1344        //
1345        // http protocol requires two forward slashes
1346        // we didn't get them, so throw an exception
1347        //
1348        if (xmlURL.fProtocol == HTTP)
1349            return false;
1350    }
1351
1352    //
1353    //  If there was a host part, then we have to grovel through it for
1354    //  all the bits and pieces it can hold.
1355    //
1356    if (xmlURL.fHost)
1357    {
1358        //
1359        //  Look for a '@' character, which indicates a user name. If we
1360        //  find one, then everything between the start of the host data
1361        //  and the character is the user name.
1362        //
1363        ptr1 = XMLString::findAny(xmlURL.fHost, gListTwo);
1364        if (ptr1)
1365        {
1366            // Get this info out as the user name
1367            *ptr1 = 0;
1368            xmlURL.fUser = XMLString::replicate(xmlURL.fHost, xmlURL.fMemoryManager);
1369            ptr1++;
1370
1371            // And now cut these chars from the host string
1372            XMLString::cut(xmlURL.fHost, ptr1 - xmlURL.fHost);
1373
1374            // Is there a password inside the user string?
1375            ptr2 = XMLString::findAny(xmlURL.fUser, gListThree);
1376            if (ptr2)
1377            {
1378                // Remove it from the user name string
1379                *ptr2 = 0;
1380
1381                // And copy out the remainder to the password field
1382                ptr2++;
1383                xmlURL.fPassword = XMLString::replicate(ptr2, xmlURL.fMemoryManager);
1384            }
1385        }
1386
1387        //
1388        //  Ok, so now we are at the actual host name, if any. If we are
1389        //  not at the end of the host data, then lets see if we have a
1390        //  port trailing the
1391        //
1392        ptr1 = XMLString::findAny(xmlURL.fHost, gListThree);
1393        if (ptr1)
1394        {
1395            // Remove it from the host name
1396            *ptr1 = 0;
1397
1398            // Try to convert it to a numeric port value and store it
1399            ptr1++;
1400            if (!XMLString::textToBin(ptr1, xmlURL.fPortNum, xmlURL.fMemoryManager))
1401                return false;
1402        }
1403
1404        // If the host ended up empty, then toss is
1405        if (!*(xmlURL.fHost))
1406        {
1407            xmlURL.fMemoryManager->deallocate(xmlURL.fHost);//delete[] fHost;
1408            xmlURL.fHost = 0;
1409        }
1410    }
1411
1412    // If we are at the end, then we are done now
1413    if (!*srcPtr) {
1414        if(xmlURL.fHost) {
1415            static const XMLCh slash[] = { chForwardSlash, chNull };
1416            xmlURL.fPath = XMLString::replicate(slash, xmlURL.fMemoryManager);
1417        }
1418        return true;
1419    }
1420
1421    //
1422    //  Next is the path part. It can be absolute, i.e. starting with a
1423    //  forward slash character, or relative. Its basically everything up
1424    //  to the end of the string or to any trailing query or fragment.
1425    //
1426    ptr1 = XMLString::findAny(srcPtr, gListFive);
1427    if (!ptr1)
1428    {
1429        xmlURL.fPath = XMLString::replicate(srcPtr, xmlURL.fMemoryManager);
1430        return true;
1431    }
1432
1433    // Everything from where we are to what we found is the path
1434    if (ptr1 > srcPtr)
1435    {
1436        xmlURL.fPath = (XMLCh*) xmlURL.fMemoryManager->allocate
1437        (
1438            ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1439        );//new XMLCh[(ptr1 - srcPtr) + 1];
1440        ptr2 = xmlURL.fPath;
1441        while (srcPtr < ptr1)
1442            *ptr2++ = *srcPtr++;
1443        *ptr2 = 0;
1444    }
1445
1446    //
1447    //  If we found a fragment, then it is the rest of the string and we
1448    //  are done.
1449    //
1450    if (*srcPtr == chPound)
1451    {
1452        srcPtr++;
1453        xmlURL.fFragment = XMLString::replicate(srcPtr, xmlURL.fMemoryManager);
1454        return true;
1455    }
1456
1457    //
1458    //  The query is either the rest of the string, or up to the fragment
1459    //  separator.
1460    //
1461    srcPtr++;
1462    ptr1 = XMLString::findAny(srcPtr, gListSix);
1463    if (!ptr1)
1464    {
1465        xmlURL.fQuery = XMLString::replicate(srcPtr, xmlURL.fMemoryManager);
1466        return true;
1467    }
1468     else
1469    {
1470        xmlURL.fQuery = (XMLCh*) xmlURL.fMemoryManager->allocate
1471        (
1472            ((ptr1 - srcPtr) + 1) * sizeof(XMLCh)
1473        );//new XMLCh[(ptr1 - srcPtr) + 1];
1474        ptr2 = xmlURL.fQuery;
1475        while (srcPtr < ptr1)
1476            *ptr2++ = *srcPtr++;
1477        *ptr2 = 0;
1478    }
1479
1480    // If we are not at the end now, then everything else is the fragment
1481    if (*srcPtr == chPound)
1482    {
1483        srcPtr++;
1484        xmlURL.fFragment = XMLString::replicate(srcPtr, xmlURL.fMemoryManager);
1485    }
1486
1487    return true;
1488}
1489
1490XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.