XMLURL.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:33k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: XMLURL.cpp,v 1.20 2001/10/10 23:16:46 jasons Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <util/BinFileInputStream.hpp>
  63. #include <util/Janitor.hpp>
  64. #include <util/PlatformUtils.hpp>
  65. #include <util/RuntimeException.hpp>
  66. #include <util/TransService.hpp>
  67. #include <util/XMLURL.hpp>
  68. #include <util/XMLNetAccessor.hpp>
  69. #include <util/XMLString.hpp>
  70. #include <util/XMLUniDefs.hpp>
  71. #include <util/XMLUni.hpp>
  72. // ---------------------------------------------------------------------------
  73. //  Local types
  74. //
  75. //  TypeEntry
  76. //      This structure defines a single entry in the list of URL types. Each
  77. //      entry indicates the prefix for that type of URL, and the SourceTypes
  78. //      value it maps to.
  79. // ---------------------------------------------------------------------------
  80. struct ProtoEntry
  81. {
  82.     XMLURL::Protocols   protocol;
  83.     const XMLCh*        prefix;
  84.     unsigned int        defPort;
  85. };
  86. // ---------------------------------------------------------------------------
  87. //  Local data
  88. //
  89. //  gXXXString
  90. //      These are the strings for our prefix types. They all have to be
  91. //      Unicode strings all the time, so we can't just do regular strings.
  92. //
  93. //  gProtoList
  94. //      The list of URL types that we support and some info related to each
  95. //      one.
  96. //
  97. //  gMaxProtoLen
  98. //      The length of the longest protocol string
  99. //
  100. //      NOTE:!!! Be sure to keep this up to date if new protocols are added!
  101. // ---------------------------------------------------------------------------
  102. static const XMLCh  gFileString[] =
  103. {
  104.         chLatin_f, chLatin_i, chLatin_l, chLatin_e, chNull
  105. };
  106. static const XMLCh gFTPString[]  =
  107. {
  108.         chLatin_f, chLatin_t, chLatin_p, chNull
  109. };
  110. static const XMLCh gHTTPString[] =
  111. {
  112.         chLatin_h, chLatin_t, chLatin_t, chLatin_p, chNull
  113. };
  114. static ProtoEntry gProtoList[XMLURL::Protocols_Count] =
  115. {
  116.         { XMLURL::File     , gFileString    , 0  }
  117.     ,   { XMLURL::HTTP     , gHTTPString    , 80 }
  118.     ,   { XMLURL::FTP      , gFTPString     , 21 }
  119. };
  120. // !!! Keep these up to date with list above!
  121. static const unsigned int gMaxProtoLen = 4;
  122. // ---------------------------------------------------------------------------
  123. //  Local methods
  124. // ---------------------------------------------------------------------------
  125. static bool isHexDigit(const XMLCh toCheck)
  126. {
  127.     if ((toCheck >= chDigit_0) && (toCheck <= chDigit_9)
  128.     ||  (toCheck >= chLatin_A) && (toCheck <= chLatin_Z)
  129.     ||  (toCheck >= chLatin_a) && (toCheck <= chLatin_z))
  130.     {
  131.         return true;
  132.     }
  133.     return false;
  134. }
  135. static unsigned int xlatHexDigit(const XMLCh toXlat)
  136. {
  137.     if ((toXlat >= chDigit_0) && (toXlat <= chDigit_9))
  138.         return (unsigned int)(toXlat - chDigit_0);
  139.     if ((toXlat >= chLatin_A) && (toXlat <= chLatin_Z))
  140.         return (unsigned int)(toXlat - chLatin_A) + 10;
  141.     return (unsigned int)(toXlat - chLatin_a) + 10;
  142. }
  143. // ---------------------------------------------------------------------------
  144. //  XMLURL: Public, static methods
  145. // ---------------------------------------------------------------------------
  146. XMLURL::Protocols XMLURL::lookupByName(const XMLCh* const protoName)
  147. {
  148.     for (unsigned int index = 0; index < XMLURL::Protocols_Count; index++)
  149.     {
  150.         if (!XMLString::compareIString(gProtoList[index].prefix, protoName))
  151.             return gProtoList[index].protocol;
  152.     }
  153.     return XMLURL::Unknown;
  154. }
  155. // ---------------------------------------------------------------------------
  156. //  XMLURL: Constructors and Destructor
  157. // ---------------------------------------------------------------------------
  158. XMLURL::XMLURL() :
  159.     fFragment(0)
  160.     , fHost(0)
  161.     , fPassword(0)
  162.     , fPath(0)
  163.     , fPortNum(0)
  164.     , fProtocol(XMLURL::Unknown)
  165.     , fQuery(0)
  166.     , fUser(0)
  167.     , fURLText(0)
  168. {
  169. }
  170. XMLURL::XMLURL(const XMLCh* const    baseURL
  171.              , const XMLCh* const    relativeURL) :
  172.     fFragment(0)
  173.     , fHost(0)
  174.     , fPassword(0)
  175.     , fPath(0)
  176.     , fPortNum(0)
  177.     , fProtocol(XMLURL::Unknown)
  178.     , fQuery(0)
  179.     , fUser(0)
  180.     , fURLText(0)
  181. {
  182. try
  183. {
  184. setURL(baseURL, relativeURL);
  185. }
  186.     catch(...)
  187.     {
  188.         cleanup();
  189.         throw;
  190.     }
  191. }
  192. XMLURL::XMLURL(const XMLCh* const    baseURL
  193.              , const char* const     relativeURL) :
  194.     fFragment(0)
  195.     , fHost(0)
  196.     , fPassword(0)
  197.     , fPath(0)
  198.     , fPortNum(0)
  199.     , fProtocol(XMLURL::Unknown)
  200.     , fQuery(0)
  201.     , fUser(0)
  202.     , fURLText(0)
  203. {
  204.     XMLCh* tmpRel = XMLString::transcode(relativeURL);
  205.     ArrayJanitor<XMLCh> janRel(tmpRel);
  206. try
  207. {
  208. setURL(baseURL, tmpRel);
  209. }
  210.     catch(...)
  211.     {
  212.         cleanup();
  213.         throw;
  214.     }
  215. }
  216. XMLURL::XMLURL(const XMLURL&         baseURL
  217.              , const XMLCh* const    relativeURL) :
  218.     fFragment(0)
  219.     , fHost(0)
  220.     , fPassword(0)
  221.     , fPath(0)
  222.     , fPortNum(0)
  223.     , fProtocol(XMLURL::Unknown)
  224.     , fQuery(0)
  225.     , fUser(0)
  226.     , fURLText(0)
  227. {
  228. try
  229. {
  230. setURL(baseURL, relativeURL);
  231. }
  232.     catch(...)
  233.     {
  234.         cleanup();
  235.         throw;
  236.     }
  237. }
  238. XMLURL::XMLURL(const  XMLURL&        baseURL
  239.              , const char* const     relativeURL) :
  240.     fFragment(0)
  241.     , fHost(0)
  242.     , fPassword(0)
  243.     , fPath(0)
  244.     , fPortNum(0)
  245.     , fProtocol(XMLURL::Unknown)
  246.     , fQuery(0)
  247.     , fUser(0)
  248.     , fURLText(0)
  249. {
  250.     XMLCh* tmpRel = XMLString::transcode(relativeURL);
  251.     ArrayJanitor<XMLCh> janRel(tmpRel);
  252. try
  253. {
  254. setURL(baseURL, tmpRel);
  255. }
  256.     catch(...)
  257.     {
  258.         cleanup();
  259.         throw;
  260.     }
  261. }
  262. XMLURL::XMLURL(const XMLCh* const urlText) :
  263.     fFragment(0)
  264.     , fHost(0)
  265.     , fPassword(0)
  266.     , fPath(0)
  267.     , fPortNum(0)
  268.     , fProtocol(XMLURL::Unknown)
  269.     , fQuery(0)
  270.     , fUser(0)
  271.     , fURLText(0)
  272. {
  273. try
  274. {
  275.     setURL(urlText);
  276. }
  277.     catch(...)
  278.     {
  279.         cleanup();
  280.         throw;
  281.     }
  282. }
  283. XMLURL::XMLURL(const char* const urlText) :
  284.     fFragment(0)
  285.     , fHost(0)
  286.     , fPassword(0)
  287.     , fPath(0)
  288.     , fPortNum(0)
  289.     , fProtocol(XMLURL::Unknown)
  290.     , fQuery(0)
  291.     , fUser(0)
  292.     , fURLText(0)
  293. {
  294.     XMLCh* tmpText = XMLString::transcode(urlText);
  295.     ArrayJanitor<XMLCh> janRel(tmpText);
  296. try
  297. {
  298.     setURL(tmpText);
  299. }
  300.     catch(...)
  301.     {
  302.         cleanup();
  303.         throw;
  304.     }
  305. }
  306. XMLURL::XMLURL(const XMLURL& toCopy) :
  307.     fFragment(XMLString::replicate(toCopy.fFragment))
  308.     , fHost(XMLString::replicate(toCopy.fHost))
  309.     , fPassword(XMLString::replicate(toCopy.fPassword))
  310.     , fPath(XMLString::replicate(toCopy.fPath))
  311.     , fPortNum(toCopy.fPortNum)
  312.     , fProtocol(toCopy.fProtocol)
  313.     , fQuery(XMLString::replicate(toCopy.fQuery))
  314.     , fUser(XMLString::replicate(toCopy.fUser))
  315.     , fURLText(XMLString::replicate(toCopy.fURLText))
  316. {
  317. }
  318. XMLURL::~XMLURL()
  319. {
  320.     cleanup();
  321. }
  322. // ---------------------------------------------------------------------------
  323. //  XMLURL: Public operators
  324. // ---------------------------------------------------------------------------
  325. XMLURL& XMLURL::operator=(const XMLURL& toAssign)
  326. {
  327.     if (this == &toAssign)
  328.         return *this;
  329.     // Clean up our stuff
  330.     cleanup();
  331.     // And copy his stuff
  332.     fFragment = XMLString::replicate(toAssign.fFragment);
  333.     fHost = XMLString::replicate(toAssign.fHost);
  334.     fPassword = XMLString::replicate(toAssign.fPassword);
  335.     fPath = XMLString::replicate(toAssign.fPath);
  336.     fProtocol = toAssign.fProtocol;
  337.     fQuery = XMLString::replicate(toAssign.fQuery);
  338.     fUser = XMLString::replicate(toAssign.fUser);
  339.     fURLText = XMLString::replicate(toAssign.fURLText);
  340.     return *this;
  341. }
  342. bool XMLURL::operator==(const XMLURL& toCompare) const
  343. {
  344.     //
  345.     //  Compare the two complete URLs (which have been processed the same
  346.     //  way so they should now be the same even if they came in via different
  347.     //  relative parts.
  348.     //
  349.     if (XMLString::compareString(getURLText(), toCompare.getURLText()))
  350.         return false;
  351.     return true;
  352. }
  353. // ---------------------------------------------------------------------------
  354. //  XMLURL: Getter methods
  355. // ---------------------------------------------------------------------------
  356. unsigned int XMLURL::getPortNum() const
  357. {
  358.     //
  359.     //  If it was not provided explicitly, then lets return the default one
  360.     //  for the protocol.
  361.     //
  362.     if (!fPortNum)
  363.     {
  364.         if (fProtocol == Unknown)
  365.             return 0;
  366.         return gProtoList[fProtocol].defPort;
  367.     }
  368.     return fPortNum;
  369. }
  370. const XMLCh* XMLURL::getProtocolName() const
  371. {
  372.     // Check to see if its ever been set
  373.     if (fProtocol == Unknown)
  374.         ThrowXML(MalformedURLException, XMLExcepts::URL_NoProtocolPresent);
  375.     return gProtoList[fProtocol].prefix;
  376. }
  377. // ---------------------------------------------------------------------------
  378. //  XMLURL: Setter methods
  379. // ---------------------------------------------------------------------------
  380. void XMLURL::setURL(const XMLCh* const urlText)
  381. {
  382.     //
  383.     //  Try to parse the URL.
  384.     //
  385.     cleanup();
  386.     parse(urlText);
  387. }
  388. void XMLURL::setURL(const XMLCh* const    baseURL
  389.                   , const XMLCh* const    relativeURL)
  390. {
  391.     cleanup();
  392.     // Parse our URL string
  393.     parse(relativeURL);
  394. //
  395. //  If its relative and the base is non-null and non-empty, then
  396. //  parse the base URL string and conglomerate them.
  397. //
  398. if (isRelative() && baseURL)
  399. {
  400. if (*baseURL)
  401. {
  402. XMLURL basePart(baseURL);
  403. if (!conglomerateWithBase(basePart, false))
  404. {
  405. cleanup();
  406. ThrowXML(MalformedURLException, XMLExcepts::URL_RelativeBaseURL);
  407. }
  408. }
  409. }
  410. }
  411. void XMLURL::setURL(const XMLURL&         baseURL
  412.                   , const XMLCh* const    relativeURL)
  413. {
  414.     cleanup();
  415. // Parse our URL string
  416.     parse(relativeURL);
  417.     // If its relative, then conglomerate with the base URL
  418.     if (isRelative())
  419. conglomerateWithBase(baseURL);
  420. }
  421. // ---------------------------------------------------------------------------
  422. //  XMLURL: Miscellaneous methods
  423. // ---------------------------------------------------------------------------
  424. bool XMLURL::isRelative() const
  425. {
  426.     // If no protocol then relative
  427.     if (fProtocol == Unknown)
  428.         return true;
  429.     // If no path, or the path is not absolute, then relative
  430.     if (!fPath)
  431.         return true;
  432.     if (*fPath != chForwardSlash)
  433.         return true;
  434.     return false;
  435. }
  436. BinInputStream* XMLURL::makeNewStream() const
  437. {
  438.     //
  439.     //  If its a local host, then we short circuit it and use our own file
  440.     //  stream support. Otherwise, we just let it fall through and let the
  441.     //  installed network access object provide a stream.
  442.     //
  443.     if (fProtocol == XMLURL::File)
  444.     {
  445.         if (!fHost || !XMLString::compareIString(fHost, XMLUni::fgLocalHostString))
  446.         {
  447.             //
  448.             //  We have to play a little trick here. If its really a Windows
  449.             //  style fully qualified path, we have to toss the leading /
  450.             //  character.
  451.             //
  452.             const XMLCh* realPath = fPath;
  453.             if (*fPath == chForwardSlash)
  454.             {
  455.                 if (XMLString::stringLen(fPath) > 3)
  456.                 {
  457.                     if (*(fPath + 2) == chColon)
  458.                     {
  459.                         const XMLCh chDrive = *(fPath + 1);
  460.                         if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z))
  461.                         ||  ((chDrive >= chLatin_a) && (chDrive <= chLatin_z)))
  462.                         {
  463.                             realPath = fPath + 1;
  464.                         }
  465.                     }
  466.                     // Similarly for UNC paths
  467.                     if ( *(fPath + 1) == *(fPath + 2) &&
  468.                          (*(fPath + 1) == chForwardSlash ||
  469.                           *(fPath + 1) == chBackSlash) )
  470.                     {
  471.                         realPath = fPath + 1;
  472.                     }
  473.                 }
  474.             }
  475.             BinFileInputStream* retStrm = new BinFileInputStream(realPath);
  476.             if (!retStrm->getIsOpen())
  477.             {
  478.                 delete retStrm;
  479.                 return 0;
  480.             }
  481.             return retStrm;
  482.         }
  483.     }
  484.     //
  485.     //  If we don't have have an installed net accessor object, then we
  486.     //  have to just throw here.
  487.     //
  488.     if (!XMLPlatformUtils::fgNetAccessor)
  489.         ThrowXML(MalformedURLException, XMLExcepts::URL_UnsupportedProto);
  490.     // Else ask the net accessor to create the stream
  491.     return XMLPlatformUtils::fgNetAccessor->makeNew(*this);
  492. }
  493. void XMLURL::makeRelativeTo(const XMLCh* const baseURLText)
  494. {
  495.     // If this one is not relative, don't bother
  496.     if (!isRelative())
  497.         return;
  498.     XMLURL baseURL(baseURLText);
  499.     conglomerateWithBase(baseURL);
  500. }
  501. void XMLURL::makeRelativeTo(const XMLURL& baseURL)
  502. {
  503.     // If this one is not relative, don't bother
  504.     if (!isRelative())
  505.         return;
  506.     conglomerateWithBase(baseURL);
  507. }
  508. // ---------------------------------------------------------------------------
  509. //  XMLURL: Private helper methods
  510. // ---------------------------------------------------------------------------
  511. //
  512. //  This method will take the broken out parts of the URL and build up the
  513. //  full text. We don't do this unless someone asks us to, since its often
  514. //  never required.
  515. //
  516. void XMLURL::buildFullText()
  517. {
  518.     // Calculate the worst case size of the buffer required
  519.     unsigned int bufSize = gMaxProtoLen + 1
  520.                            + XMLString::stringLen(fFragment) + 1
  521.                            + XMLString::stringLen(fHost) + 2
  522.                            + XMLString::stringLen(fPassword) + 1
  523.                            + XMLString::stringLen(fPath)
  524.                            + XMLString::stringLen(fQuery) + 1
  525.                            + XMLString::stringLen(fUser) + 1
  526.                            + 32;
  527.     // Clean up the existing buffer and allocate another
  528.     delete [] fURLText;
  529.     fURLText = new XMLCh[bufSize];
  530.     *fURLText = 0;
  531.     XMLCh* outPtr = fURLText;
  532.     if (fProtocol != Unknown)
  533.     {
  534.         XMLString::catString(fURLText, getProtocolName());
  535.         outPtr += XMLString::stringLen(fURLText);
  536.         *outPtr++ = chColon;
  537.         *outPtr++ = chForwardSlash;
  538.         *outPtr++ = chForwardSlash;
  539.     }
  540.     if (fUser)
  541.     {
  542.         XMLString::copyString(outPtr, fUser);
  543.         outPtr += XMLString::stringLen(fUser);
  544.         if (fPassword)
  545.         {
  546.             *outPtr++ = chColon;
  547.             XMLString::copyString(outPtr, fPassword);
  548.             outPtr += XMLString::stringLen(fPassword);
  549.         }
  550.         *outPtr++ = chAt;
  551.     }
  552.     if (fHost)
  553.     {
  554.         XMLString::copyString(outPtr, fHost);
  555.         outPtr += XMLString::stringLen(fHost);
  556.         //
  557.         //  If the port is zero, then we don't put it in. Else we need
  558.         //  to because it was explicitly provided.
  559.         //
  560.         if (fPortNum)
  561.         {
  562.             *outPtr++ = chColon;
  563.             XMLCh tmpBuf[16];
  564.             XMLString::binToText(fPortNum, tmpBuf, 16, 10);
  565.             XMLString::copyString(outPtr, tmpBuf);
  566.             outPtr += XMLString::stringLen(tmpBuf);
  567.         }
  568.     }
  569.     if (fPath)
  570.     {
  571.         XMLString::copyString(outPtr, fPath);
  572.         outPtr += XMLString::stringLen(fPath);
  573.     }
  574.     if (fQuery)
  575.     {
  576.         *outPtr++ = chQuestion;
  577.         XMLString::copyString(outPtr, fQuery);
  578.         outPtr += XMLString::stringLen(fQuery);
  579.     }
  580.     if (fFragment)
  581.     {
  582.         *outPtr++ = chPound;
  583.         XMLString::copyString(outPtr, fFragment);
  584.         outPtr += XMLString::stringLen(fFragment);
  585.     }
  586.     // Cap it off in case the last op was not a string copy
  587.     *outPtr = 0;
  588. }
  589. //
  590. //  Just a central place to handle cleanup, since its done from a number
  591. //  of different spots.
  592. //
  593. void XMLURL::cleanup()
  594. {
  595.     delete [] fFragment;
  596.     delete [] fHost;
  597.     delete [] fPassword;
  598.     delete [] fPath;
  599.     delete [] fQuery;
  600.     delete [] fUser;
  601.     delete [] fURLText;
  602.     fFragment = 0;
  603.     fHost = 0;
  604.     fPassword = 0;
  605.     fPath = 0;
  606.     fQuery = 0;
  607.     fUser = 0;
  608.     fURLText = 0;
  609.     fProtocol = Unknown;
  610.     fPortNum = 0;
  611. }
  612. //This function  has been modified to take a bool parameter and the
  613. //functionality inside looks irrational but is only to make
  614. //solaris 2.7 CC 5.0 optimized build happy.
  615. bool XMLURL::conglomerateWithBase(const XMLURL& baseURL, bool useExceptions)
  616. {
  617.     // The base URL cannot be relative
  618.     if (baseURL.isRelative())
  619.     {
  620.         if (useExceptions)
  621. ThrowXML(MalformedURLException, XMLExcepts::URL_RelativeBaseURL);
  622.         else
  623.             return false;
  624.     }
  625.     //
  626.     //  Check a special case. If all we have is a fragment, then we want
  627.     //  to just take the base host and path, plus our fragment.
  628.     //
  629.     if ((fProtocol == Unknown)
  630.     &&  !fHost
  631.     &&  !fPath
  632.     &&  fFragment)
  633.     {
  634.         // Just in case, make sure we don't leak the user or password values
  635.         delete [] fUser;
  636.         fUser = 0;
  637.         delete [] fPassword;
  638.         fPassword = 0;
  639.         // Copy over the protocol and port number as is
  640.         fProtocol = baseURL.fProtocol;
  641.         fPortNum = baseURL.fPortNum;
  642.         // Replicate the base fields that are provided
  643.         fHost = XMLString::replicate(baseURL.fHost);
  644.         fUser = XMLString::replicate(baseURL.fUser);
  645.         fPassword = XMLString::replicate(baseURL.fPassword);
  646.         fPath = XMLString::replicate(baseURL.fPath);
  647.         return true;
  648.     }
  649.     //
  650.     //  All we have to do is run up through our fields and, for each one
  651.     //  that we don't have, use the based URL's. Once we hit one field
  652.     //  that we have, we stop.
  653.     //
  654.     if (fProtocol != Unknown)
  655.         return true;
  656.     fProtocol = baseURL.fProtocol;
  657.     //
  658.     //  If the protocol is not file, and we either already have our own
  659.     //  host, or the base does not have one, then we are done.
  660.     //
  661.     if (fProtocol != File)
  662.     {
  663.         if (fHost || !baseURL.fHost)
  664.             return true;
  665.     }
  666.     // Replicate all of the hosty stuff if the base has one
  667.     if (baseURL.fHost)
  668.     {
  669.         // Just in case, make sure we don't leak a user or password field
  670.         delete [] fUser;
  671.         fUser = 0;
  672.         delete [] fPassword;
  673.         fPassword = 0;
  674.         delete [] fHost;
  675.         fHost = 0;
  676.         fHost = XMLString::replicate(baseURL.fHost);
  677.         fUser = XMLString::replicate(baseURL.fUser);
  678.         fPassword = XMLString::replicate(baseURL.fPassword);
  679.         fPortNum = baseURL.fPortNum;
  680.     }
  681.     // If we have a path and its absolute, then we are done
  682.     const bool hadPath = (fPath != 0);
  683.     if (hadPath)
  684.     {
  685.         if (*fPath == chForwardSlash)
  686.             return true;
  687.     }
  688.     // Its a relative path, so weave them together.
  689.     if (baseURL.fPath)
  690.         weavePaths(baseURL.fPath);
  691.     // If we had any original path, then we are done
  692.     if (hadPath)
  693.         return true;
  694.     // We had no original path, so go on to deal with the query/fragment parts
  695.     if (fQuery || !baseURL.fQuery)
  696.         return true;
  697.     fQuery = XMLString::replicate(baseURL.fQuery);
  698.     if (fFragment || !baseURL.fFragment)
  699.         return true;
  700.     fFragment = XMLString::replicate(baseURL.fFragment);
  701. return true;
  702. }
  703. void XMLURL::parse(const XMLCh* const urlText)
  704. {
  705.     // Simplify things by checking for the psycho scenarios first
  706.     if (!*urlText)
  707.         ThrowXML(MalformedURLException, XMLExcepts::URL_NoProtocolPresent);
  708.     //
  709.     //  The first thing we will do is to check for a file name, so that
  710.     //  we don't waste time thinking its a URL. If its in the form x:
  711.     //  or x:/ and x is an ASCII letter, then assume that's the deal.
  712.     //
  713.     if (((*urlText >= chLatin_A) && (*urlText <= chLatin_Z))
  714.     ||  ((*urlText >= chLatin_a) && (*urlText <= chLatin_z)))
  715.     {
  716.         if (*(urlText + 1) == chColon)
  717.         {
  718.             if ((*(urlText + 2) == chForwardSlash)
  719.             ||  (*(urlText + 2) == chBackSlash))
  720.             {
  721.                 ThrowXML(MalformedURLException, XMLExcepts::URL_NoProtocolPresent);
  722.             }
  723.         }
  724.     }
  725.     // Get a copy of the URL that we can modify
  726.     XMLCh* srcCpy = XMLString::replicate(urlText);
  727.     ArrayJanitor<XMLCh> janSrcCopy(srcCpy);
  728.     //
  729.     //  Get a pointer now that we can run up thrown the source as we parse
  730.     //  bits and pieces out of it.
  731.     //
  732.     XMLCh* srcPtr = srcCpy;
  733.     // Run up past any spaces
  734.     while (*srcPtr)
  735.     {
  736.         if (!XMLPlatformUtils::fgTransService->isSpace(*srcPtr))
  737.             break;
  738.         srcPtr++;
  739.     }
  740.     // Make sure it wasn't all space
  741.     if (!*srcPtr)
  742.         ThrowXML(MalformedURLException, XMLExcepts::URL_NoProtocolPresent);
  743.     //
  744.     //  Ok, the next thing we have to do is to find either a / or : character.
  745.     //  If the : is first, we assume we have a protocol. If the / is first,
  746.     //  then we skip to the host processing.
  747.     //
  748.     static const XMLCh listOne[]    = { chColon, chForwardSlash, chNull };
  749.     static const XMLCh listTwo[]    = { chAt, chNull };
  750.     static const XMLCh listThree[]  = { chColon, chNull };
  751.     static const XMLCh listFour[]   = { chForwardSlash, chNull };
  752.     static const XMLCh listFive[]   = { chPound, chQuestion, chNull };
  753.     static const XMLCh listSix[]    = { chPound, chNull };
  754.     XMLCh* ptr1 = XMLString::findAny(srcPtr, listOne);
  755.     XMLCh* ptr2;
  756.     // If we found a protocol, then deal with it
  757.     if (ptr1)
  758.     {
  759.         if (*ptr1 == chColon)
  760.         {
  761.             // Cap the string at the colon
  762.             *ptr1 = 0;
  763.             // And try to find it in our list of protocols
  764.             fProtocol = lookupByName(srcPtr);
  765.             if (fProtocol == Unknown)
  766.             {
  767.                 ThrowXML1
  768.                 (
  769.                     MalformedURLException
  770.                     , XMLExcepts::URL_UnsupportedProto1
  771.                     , srcPtr
  772.                 );
  773.             }
  774.             // And move our source pointer up past what we've processed
  775.             srcPtr = (ptr1 + 1);
  776.         }
  777.     }
  778.     //
  779.     //  Ok, next we need to see if we have any host part. If the next
  780.     //  two characters are //, then we need to check, else move on.
  781.     //
  782.     if ((*srcPtr == chForwardSlash) && (*(srcPtr + 1) == chForwardSlash))
  783.     {
  784.         // Move up past the slashes
  785.         srcPtr += 2;
  786.         //
  787.         //  If we aren't at the end of the string, then there has to be a
  788.         //  host part at this point. we will just look for the next / char
  789.         //  or end of string and make all of that the host for now.
  790.         //
  791.         if (*srcPtr)
  792.         {
  793.             // Search from here for a / character
  794.             ptr1 = XMLString::findAny(srcPtr, listFour);
  795.             //
  796.             //  If we found something, then the host is between where
  797.             //  we are and what we found. Else the host is the rest of
  798.             //  the content and we are done. If its empty, leave it null.
  799.             //
  800.             if (ptr1)
  801.             {
  802.                 if (ptr1 != srcPtr)
  803.                 {
  804.                     delete [] fHost;
  805.                     fHost = new XMLCh[(ptr1 - srcPtr) + 1];
  806.                     ptr2 = fHost;
  807.                     while (srcPtr < ptr1)
  808.                         *ptr2++ = *srcPtr++;
  809.                     *ptr2 = 0;
  810.                 }
  811.             }
  812.              else
  813.             {
  814.                 delete [] fHost;
  815.                 fHost = XMLString::replicate(srcPtr);
  816.                 // Update source pointer to the end
  817.                 srcPtr += XMLString::stringLen(fHost);
  818.             }
  819.         }
  820.     } 
  821.     else 
  822.     {
  823.     //
  824.     // http protocol requires two forward slashes
  825.     // we didn't get them, so throw an exception
  826.     //
  827. if (fProtocol == HTTP) {
  828.                 ThrowXML1
  829.                 (
  830.                     MalformedURLException
  831.                     , XMLExcepts::URL_ExpectingTwoSlashes
  832.                     , "Found 'http' protocol"
  833.                 );
  834. }
  835.     }
  836.     //
  837.     //  If there was a host part, then we have to grovel through it for
  838.     //  all the bits and pieces it can hold.
  839.     //
  840.     if (fHost)
  841.     {
  842.         //
  843.         //  Look for a '@' character, which indicates a user name. If we
  844.         //  find one, then everything between the start of the host data
  845.         //  and the character is the user name.
  846.         //
  847.         ptr1 = XMLString::findAny(fHost, listTwo);
  848.         if (ptr1)
  849.         {
  850.             // Get this info out as the user name
  851.             *ptr1 = 0;
  852.             delete [] fUser;
  853.             fUser = XMLString::replicate(fHost);
  854.             ptr1++;
  855.             // And now cut these chars from the host string
  856.             XMLString::cut(fHost, ptr1 - fHost);
  857.             // Is there a password inside the user string?
  858.             ptr2 = XMLString::findAny(fUser, listThree);
  859.             if (ptr2)
  860.             {
  861.                 // Remove it from the user name string
  862.                 *ptr2 = 0;
  863.                 // And copy out the remainder to the password field
  864.                 ptr2++;
  865.                 delete [] fPassword;
  866.                 fPassword = XMLString::replicate(ptr2);
  867.             }
  868.         }
  869.         //
  870.         //  Ok, so now we are at the actual host name, if any. If we are
  871.         //  not at the end of the host data, then lets see if we have a
  872.         //  port trailing the
  873.         //
  874.         ptr1 = XMLString::findAny(fHost, listThree);
  875.         if (ptr1)
  876.         {
  877.             // Remove it from the host name
  878.             *ptr1 = 0;
  879.             // Try to convert it to a numeric port value and store it
  880.             ptr1++;
  881.             if (!XMLString::textToBin(ptr1, fPortNum))
  882.                 ThrowXML(MalformedURLException, XMLExcepts::URL_BadPortField);
  883.         }
  884.         // If the host ended up empty, then toss is
  885.         if (!*fHost)
  886.         {
  887.             delete[] fHost;
  888.             fHost = 0;
  889.         }
  890.     }
  891.     // If we are at the end, then we are done now
  892.     if (!*srcPtr)
  893. {
  894.         return;
  895. }
  896.     //
  897.     //  Next is the path part. It can be absolute, i.e. starting with a
  898.     //  forward slash character, or relative. Its basically everything up
  899.     //  to the end of the string or to any trailing query or fragment.
  900.     //
  901.     ptr1 = XMLString::findAny(srcPtr, listFive);
  902.     if (!ptr1)
  903.     {
  904.         delete [] fPath;
  905.         fPath = XMLString::replicate(srcPtr);
  906.         return;
  907.     }
  908.     // Everything from where we are to what we found is the path
  909.     if (ptr1 > srcPtr)
  910.     {
  911.         delete [] fPath;
  912.         fPath = new XMLCh[(ptr1 - srcPtr) + 1];
  913.         ptr2 = fPath;
  914.         while (srcPtr < ptr1)
  915.             *ptr2++ = *srcPtr++;
  916.         *ptr2 = 0;
  917.     }
  918.     //
  919.     //  If we found a fragment, then it is the rest of the string and we
  920.     //  are done.
  921.     //
  922.     if (*srcPtr == chPound)
  923.     {
  924.         srcPtr++;
  925.         delete [] fFragment;
  926.         fFragment = XMLString::replicate(srcPtr);
  927.         return;
  928.     }
  929.     //
  930.     //  The query is either the rest of the string, or up to the fragment
  931.     //  separator.
  932.     //
  933.     srcPtr++;
  934.     ptr1 = XMLString::findAny(srcPtr, listSix);
  935.     delete [] fQuery;
  936.     if (!ptr1)
  937.     {
  938.         fQuery = XMLString::replicate(srcPtr);
  939.         return;
  940.     }
  941.      else
  942.     {
  943.         fQuery = new XMLCh[(ptr1 - srcPtr) + 1];
  944.         ptr2 = fQuery;
  945.         while (srcPtr < ptr1)
  946.             *ptr2++ = *srcPtr++;
  947.         *ptr2 = 0;
  948.     }
  949.     // If we are not at the end now, then everything else is the fragment
  950.     if (*srcPtr == chPound)
  951.     {
  952.         srcPtr++;
  953.         delete [] fFragment;
  954.         fFragment = XMLString::replicate(srcPtr);
  955.     }
  956. }
  957. void XMLURL::weavePaths(const XMLCh* const basePart)
  958. {
  959.     // Watch for stupid stuff
  960.     if (!basePart)
  961.         return;
  962.     if (!*basePart)
  963.         return;
  964.     //
  965.     //  Ok, lets start at the end of the base path and work backwards and
  966.     //  our path part and work forwards. For each leading . we see, we just
  967.     //  eat it. For each leading .. we see, we eat it and throw away one
  968.     //  level in the source URL.
  969.     //
  970.     //  If the last character in the base part is a forward slash, back
  971.     //  up one first before we look for the last slash.
  972.     //
  973.     const XMLCh* basePtr = basePart + (XMLString::stringLen(basePart) - 1);
  974.     if (*basePtr == chForwardSlash)
  975.         basePtr--;
  976.     while ((basePtr >= basePart)
  977.     &&     ((*basePtr != chForwardSlash) && (*basePtr != chBackSlash)))
  978.     {
  979.         basePtr--;
  980.     }
  981.     if (basePtr < basePart)
  982.         return;
  983.     // Create a buffer as large as both parts
  984.     XMLCh* tmpBuf = new XMLCh[XMLString::stringLen(fPath)
  985.                               + XMLString::stringLen(basePart)
  986.                               + 2];
  987.     //
  988.     //  If we have no path part, then copy the base part up to the
  989.     //  base pointer
  990.     //
  991.     if (!fPath)
  992.     {
  993.         XMLCh* bufPtr = tmpBuf;
  994.         const XMLCh* tmpPtr = basePart;
  995.         while (tmpPtr <= basePtr)
  996.             *bufPtr++ = *tmpPtr++;
  997.         *bufPtr = 0;
  998.         fPath = tmpBuf;
  999.         return;
  1000.     }
  1001.     // After this, make sure the buffer gets handled if we exit early
  1002.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  1003.     //
  1004.     //  We have some path part, so we need to check to see if we ahve to
  1005.     //  weave any of the parts together.
  1006.     //
  1007.     XMLCh* pathPtr = fPath;
  1008.     while (true)
  1009.     {
  1010.         // If it does not start with some period, then we are done
  1011.         if (*pathPtr != chPeriod)
  1012.             break;
  1013.         unsigned int periodCount = 1;
  1014.         pathPtr++;
  1015.         if (*pathPtr == chPeriod)
  1016.         {
  1017.             pathPtr++;
  1018.             periodCount++;
  1019.         }
  1020.         // Has to be followed by a / or  or the null to mean anything
  1021.         if ((*pathPtr != chForwardSlash) && (*pathPtr != chBackSlash)
  1022.         &&  *pathPtr)
  1023.         {
  1024.             break;
  1025.         }
  1026.         if (*pathPtr)
  1027.             pathPtr++;
  1028.         // If its one period, just eat it, else move backwards in the base
  1029.         if (periodCount == 2)
  1030.         {
  1031.             basePtr--;
  1032.             while ((basePtr >= basePart)
  1033.             &&     ((*basePtr != chForwardSlash) && (*basePtr != chBackSlash)))
  1034.             {
  1035.                 basePtr--;
  1036.             }
  1037.             // There are not enough levels to handle all the .. parts
  1038.             if (basePtr < basePart)
  1039.                 ThrowXML(MalformedURLException, XMLExcepts::URL_BaseUnderflow);
  1040.         }
  1041.     }
  1042.     // Copy the base part up to the base pointer
  1043.     XMLCh* bufPtr = tmpBuf;
  1044.     const XMLCh* tmpPtr = basePart;
  1045.     while (tmpPtr <= basePtr)
  1046.         *bufPtr++ = *tmpPtr++;
  1047.     // And then copy on the rest of our path
  1048.     XMLString::copyString(bufPtr, pathPtr);
  1049.     // Now delete our path and make the new buffer our path
  1050.     delete [] fPath;
  1051.     janBuf.orphan();
  1052.     fPath = tmpBuf;
  1053. }