| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * $Id$ |
| */ |
| |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/util/BinFileInputStream.hpp> |
| #include <xercesc/util/Janitor.hpp> |
| #include <xercesc/util/PlatformUtils.hpp> |
| #include <xercesc/util/RuntimeException.hpp> |
| #include <xercesc/util/TransService.hpp> |
| #include <xercesc/util/XMLURL.hpp> |
| #include <xercesc/util/XMLNetAccessor.hpp> |
| #include <xercesc/util/XMLString.hpp> |
| #include <xercesc/util/XMLUniDefs.hpp> |
| #include <xercesc/util/XMLUni.hpp> |
| #include <xercesc/util/XMLUri.hpp> |
| #include <xercesc/util/OutOfMemoryException.hpp> |
| #include <xercesc/util/XMLChar.hpp> |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // Local types |
| // |
| // TypeEntry |
| // This structure defines a single entry in the list of URL types. Each |
| // entry indicates the prefix for that type of URL, and the SourceTypes |
| // value it maps to. |
| // --------------------------------------------------------------------------- |
| struct ProtoEntry |
| { |
| XMLURL::Protocols protocol; |
| const XMLCh* prefix; |
| unsigned int defPort; |
| }; |
| |
| |
| // --------------------------------------------------------------------------- |
| // Local data |
| // |
| // gXXXString |
| // These are the strings for our prefix types. They all have to be |
| // Unicode strings all the time, so we can't just do regular strings. |
| // |
| // gProtoList |
| // The list of URL types that we support and some info related to each |
| // one. |
| // |
| // gMaxProtoLen |
| // The length of the longest protocol string |
| // |
| // NOTE:!!! Be sure to keep this up to date if new protocols are added! |
| // --------------------------------------------------------------------------- |
| static const XMLCh gFileString[] = |
| { |
| chLatin_f, chLatin_i, chLatin_l, chLatin_e, chNull |
| }; |
| |
| static const XMLCh gFTPString[] = |
| { |
| chLatin_f, chLatin_t, chLatin_p, chNull |
| }; |
| |
| static const XMLCh gHTTPString[] = |
| { |
| chLatin_h, chLatin_t, chLatin_t, chLatin_p, chNull |
| }; |
| |
| static const XMLCh gHTTPSString[] = |
| { |
| chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chNull |
| }; |
| |
| static ProtoEntry gProtoList[XMLURL::Protocols_Count] = |
| { |
| { XMLURL::File , gFileString , 0 } |
| , { XMLURL::HTTP , gHTTPString , 80 } |
| , { XMLURL::FTP , gFTPString , 21 } |
| , { XMLURL::HTTPS , gHTTPSString , 443 } |
| }; |
| |
| // !!! Keep these up to date with list above! |
| static const unsigned int gMaxProtoLen = 5; |
| |
| static const XMLCh gListOne[] = { chColon, chForwardSlash, chNull }; |
| static const XMLCh gListTwo[] = { chAt, chNull }; |
| static const XMLCh gListThree[] = { chColon, chNull }; |
| static const XMLCh gListFour[] = { chForwardSlash, chNull }; |
| static const XMLCh gListFive[] = { chPound, chQuestion, chNull }; |
| static const XMLCh gListSix[] = { chPound, chNull }; |
| |
| // --------------------------------------------------------------------------- |
| // Local methods |
| // --------------------------------------------------------------------------- |
| static bool isHexDigit(const XMLCh toCheck) |
| { |
| if (((toCheck >= chDigit_0) && (toCheck <= chDigit_9)) |
| || ((toCheck >= chLatin_A) && (toCheck <= chLatin_F)) |
| || ((toCheck >= chLatin_a) && (toCheck <= chLatin_f))) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| static unsigned int xlatHexDigit(const XMLCh toXlat) |
| { |
| if ((toXlat >= chDigit_0) && (toXlat <= chDigit_9)) |
| return (unsigned int)(toXlat - chDigit_0); |
| |
| if ((toXlat >= chLatin_A) && (toXlat <= chLatin_F)) |
| return (unsigned int)(toXlat - chLatin_A) + 10; |
| |
| return (unsigned int)(toXlat - chLatin_a) + 10; |
| } |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Public, static methods |
| // --------------------------------------------------------------------------- |
| XMLURL::Protocols XMLURL::lookupByName(const XMLCh* const protoName) |
| { |
| for (unsigned int index = 0; index < XMLURL::Protocols_Count; index++) |
| { |
| if (!XMLString::compareIStringASCII(protoName, gProtoList[index].prefix)) |
| return gProtoList[index].protocol; |
| } |
| return XMLURL::Unknown; |
| } |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| XMLURL::XMLURL(MemoryManager* const manager) : |
| |
| fMemoryManager(manager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| } |
| |
| typedef JanitorMemFunCall<XMLURL> CleanupType; |
| |
| XMLURL::XMLURL(const XMLCh* const baseURL |
| , const XMLCh* const relativeURL |
| , MemoryManager* const manager) : |
| |
| fMemoryManager(manager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| try |
| { |
| setURL(baseURL, relativeURL); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const XMLCh* const baseURL |
| , const char* const relativeURL |
| , MemoryManager* const manager) : |
| |
| fMemoryManager(manager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| XMLCh* tmpRel = XMLString::transcode(relativeURL, fMemoryManager); |
| ArrayJanitor<XMLCh> janRel(tmpRel, fMemoryManager); |
| try |
| { |
| setURL(baseURL, tmpRel); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const XMLURL& baseURL |
| , const XMLCh* const relativeURL) : |
| |
| fMemoryManager(baseURL.fMemoryManager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| try |
| { |
| setURL(baseURL, relativeURL); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const XMLURL& baseURL |
| , const char* const relativeURL) : |
| |
| fMemoryManager(baseURL.fMemoryManager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| XMLCh* tmpRel = XMLString::transcode(relativeURL, fMemoryManager); |
| ArrayJanitor<XMLCh> janRel(tmpRel, fMemoryManager); |
| try |
| { |
| setURL(baseURL, tmpRel); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const XMLCh* const urlText, |
| MemoryManager* const manager) : |
| |
| fMemoryManager(manager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| try |
| { |
| setURL(urlText); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const char* const urlText, |
| MemoryManager* const manager) : |
| |
| fMemoryManager(manager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(0) |
| , fProtocol(XMLURL::Unknown) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(false) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| XMLCh* tmpText = XMLString::transcode(urlText, fMemoryManager); |
| ArrayJanitor<XMLCh> janRel(tmpText, fMemoryManager); |
| try |
| { |
| setURL(tmpText); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::XMLURL(const XMLURL& toCopy) : |
| XMemory(toCopy) |
| , fMemoryManager(toCopy.fMemoryManager) |
| , fFragment(0) |
| , fHost(0) |
| , fPassword(0) |
| , fPath(0) |
| , fPortNum(toCopy.fPortNum) |
| , fProtocol(toCopy.fProtocol) |
| , fQuery(0) |
| , fUser(0) |
| , fURLText(0) |
| , fHasInvalidChar(toCopy.fHasInvalidChar) |
| { |
| CleanupType cleanup(this, &XMLURL::cleanUp); |
| |
| try |
| { |
| fFragment = XMLString::replicate(toCopy.fFragment, fMemoryManager); |
| fHost = XMLString::replicate(toCopy.fHost, fMemoryManager); |
| fPassword = XMLString::replicate(toCopy.fPassword, fMemoryManager); |
| fPath = XMLString::replicate(toCopy.fPath, fMemoryManager); |
| fQuery = XMLString::replicate(toCopy.fQuery, fMemoryManager); |
| fUser = XMLString::replicate(toCopy.fUser, fMemoryManager); |
| fURLText = XMLString::replicate(toCopy.fURLText, fMemoryManager); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| cleanup.release(); |
| |
| throw; |
| } |
| |
| cleanup.release(); |
| } |
| |
| XMLURL::~XMLURL() |
| { |
| cleanUp(); |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Public operators |
| // --------------------------------------------------------------------------- |
| XMLURL& XMLURL::operator=(const XMLURL& toAssign) |
| { |
| if (this == &toAssign) |
| return *this; |
| |
| // Clean up our stuff |
| cleanUp(); |
| |
| // And copy his stuff |
| fMemoryManager = toAssign.fMemoryManager; |
| fFragment = XMLString::replicate(toAssign.fFragment, fMemoryManager); |
| fHost = XMLString::replicate(toAssign.fHost, fMemoryManager); |
| fPassword = XMLString::replicate(toAssign.fPassword, fMemoryManager); |
| fPath = XMLString::replicate(toAssign.fPath, fMemoryManager); |
| fPortNum = toAssign.fPortNum; |
| fProtocol = toAssign.fProtocol; |
| fQuery = XMLString::replicate(toAssign.fQuery, fMemoryManager); |
| fUser = XMLString::replicate(toAssign.fUser, fMemoryManager); |
| fURLText = XMLString::replicate(toAssign.fURLText, fMemoryManager); |
| fHasInvalidChar = toAssign.fHasInvalidChar; |
| |
| return *this; |
| } |
| |
| bool XMLURL::operator==(const XMLURL& toCompare) const |
| { |
| // |
| // Compare the two complete URLs (which have been processed the same |
| // way so they should now be the same even if they came in via different |
| // relative parts. |
| // |
| if (!XMLString::equals(getURLText(), toCompare.getURLText())) |
| return false; |
| |
| return true; |
| } |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Getter methods |
| // --------------------------------------------------------------------------- |
| unsigned int XMLURL::getPortNum() const |
| { |
| // |
| // If it was not provided explicitly, then lets return the default one |
| // for the protocol. |
| // |
| if (!fPortNum) |
| { |
| if (fProtocol == Unknown) |
| return 0; |
| return gProtoList[fProtocol].defPort; |
| } |
| return fPortNum; |
| } |
| |
| |
| const XMLCh* XMLURL::getProtocolName() const |
| { |
| // Check to see if its ever been set |
| if (fProtocol == Unknown) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager); |
| |
| return gProtoList[fProtocol].prefix; |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Setter methods |
| // --------------------------------------------------------------------------- |
| void XMLURL::setURL(const XMLCh* const urlText) |
| { |
| // |
| // Try to parse the URL. |
| // |
| cleanUp(); |
| parse(urlText); |
| } |
| |
| void XMLURL::setURL(const XMLCh* const baseURL |
| , const XMLCh* const relativeURL) |
| { |
| cleanUp(); |
| |
| // Parse our URL string |
| parse(relativeURL); |
| |
| // |
| // If its relative and the base is non-null and non-empty, then |
| // parse the base URL string and conglomerate them. |
| // |
| if (isRelative() && baseURL) |
| { |
| if (*baseURL) |
| { |
| XMLURL basePart(baseURL, fMemoryManager); |
| if (!conglomerateWithBase(basePart, false)) |
| { |
| cleanUp(); |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_RelativeBaseURL, fMemoryManager); |
| } |
| } |
| } |
| } |
| |
| // this version of setURL doesn't throw a malformedurl exception |
| // instead it returns false when it failed (or when it would of |
| // thrown a malformedurl exception) |
| bool XMLURL::setURL(const XMLCh* const baseURL |
| , const XMLCh* const relativeURL |
| , XMLURL& xmlURL) |
| { |
| cleanUp(); |
| |
| // Parse our URL string |
| if (parse(relativeURL, xmlURL)) |
| { |
| // If its relative and the base is non-null and non-empty, then |
| // parse the base URL string and conglomerate them. |
| // |
| if (isRelative() && baseURL && *baseURL) |
| { |
| XMLURL basePart(fMemoryManager); |
| if (parse(baseURL, basePart) && conglomerateWithBase(basePart, false)) |
| { |
| return true; |
| } |
| } |
| else |
| return true; |
| } |
| return false; |
| } |
| |
| void XMLURL::setURL(const XMLURL& baseURL |
| , const XMLCh* const relativeURL) |
| { |
| cleanUp(); |
| |
| // Parse our URL string |
| parse(relativeURL); |
| |
| // If its relative, then conglomerate with the base URL |
| if (isRelative()) |
| conglomerateWithBase(baseURL); |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Miscellaneous methods |
| // --------------------------------------------------------------------------- |
| bool XMLURL::isRelative() const |
| { |
| // If no protocol then relative |
| if (fProtocol == Unknown) |
| return true; |
| |
| // If no path, or the path is not absolute, then relative |
| if (!fPath) |
| return true; |
| |
| if (*fPath != chForwardSlash) |
| return true; |
| |
| return false; |
| } |
| |
| |
| bool XMLURL::hasInvalidChar() const { |
| return fHasInvalidChar; |
| } |
| |
| |
| BinInputStream* XMLURL::makeNewStream() const |
| { |
| // |
| // If its a local host, then we short circuit it and use our own file |
| // stream support. Otherwise, we just let it fall through and let the |
| // installed network access object provide a stream. |
| // |
| if (fProtocol == XMLURL::File) |
| { |
| if (!fHost || !XMLString::compareIStringASCII(fHost, XMLUni::fgLocalHostString)) |
| { |
| |
| XMLCh* realPath = XMLString::replicate(fPath, fMemoryManager); |
| ArrayJanitor<XMLCh> basePathName(realPath, fMemoryManager); |
| |
| // |
| // Need to manually replace any character reference %xx first |
| // HTTP protocol will be done automatically by the netaccessor |
| // |
| XMLSize_t end = XMLString::stringLen(realPath); |
| int percentIndex = XMLString::indexOf(realPath, chPercent, 0, fMemoryManager); |
| |
| while (percentIndex != -1) { |
| |
| // Isolate the length/boundary check so we don't try and copy off the end. |
| if (percentIndex+2 >= (int)end) |
| { |
| XMLCh value1[3]; |
| value1[1] = chNull; |
| value1[2] = chNull; |
| XMLString::moveChars(value1, &(realPath[percentIndex]), (percentIndex + 1 >= (int)end ? 1 : 2)); |
| ThrowXMLwithMemMgr2(MalformedURLException |
| , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence |
| , realPath |
| , value1 |
| , fMemoryManager); |
| } |
| else if (!isHexDigit(realPath[percentIndex+1]) || !isHexDigit(realPath[percentIndex+2])) |
| { |
| XMLCh value1[4]; |
| XMLString::moveChars(value1, &(realPath[percentIndex]), 3); |
| value1[3] = chNull; |
| ThrowXMLwithMemMgr2(MalformedURLException |
| , XMLExcepts::XMLNUM_URI_Component_Invalid_EscapeSequence |
| , realPath |
| , value1 |
| , fMemoryManager); |
| } |
| |
| unsigned int value = (xlatHexDigit(realPath[percentIndex+1]) * 16) + xlatHexDigit(realPath[percentIndex+2]); |
| |
| realPath[percentIndex] = XMLCh(value); |
| |
| XMLSize_t i =0; |
| for (i = percentIndex + 1; i < end - 2 ; i++) |
| realPath[i] = realPath[i+2]; |
| realPath[i] = chNull; |
| end = i; |
| |
| if (((XMLSize_t)(percentIndex + 1)) < end) |
| percentIndex = XMLString::indexOf(realPath, chPercent, percentIndex + 1, fMemoryManager); |
| else |
| percentIndex = -1; |
| } |
| |
| |
| BinFileInputStream* retStrm = new (fMemoryManager) BinFileInputStream(realPath, fMemoryManager); |
| if (!retStrm->getIsOpen()) |
| { |
| delete retStrm; |
| return 0; |
| } |
| return retStrm; |
| } |
| } |
| |
| // |
| // If we don't have have an installed net accessor object, then we |
| // have to just throw here. |
| // |
| if (!XMLPlatformUtils::fgNetAccessor) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_UnsupportedProto, fMemoryManager); |
| |
| // Else ask the net accessor to create the stream |
| return XMLPlatformUtils::fgNetAccessor->makeNew(*this); |
| } |
| |
| void XMLURL::makeRelativeTo(const XMLCh* const baseURLText) |
| { |
| // If this one is not relative, don't bother |
| if (!isRelative()) |
| return; |
| |
| XMLURL baseURL(baseURLText, fMemoryManager); |
| conglomerateWithBase(baseURL); |
| } |
| |
| void XMLURL::makeRelativeTo(const XMLURL& baseURL) |
| { |
| // If this one is not relative, don't bother |
| if (!isRelative()) |
| return; |
| conglomerateWithBase(baseURL); |
| } |
| |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLURL: Private helper methods |
| // --------------------------------------------------------------------------- |
| |
| // |
| // This method will take the broken out parts of the URL and build up the |
| // full text. We don't do this unless someone asks us to, since its often |
| // never required. |
| // |
| void XMLURL::buildFullText() |
| { |
| // Calculate the worst case size of the buffer required |
| XMLSize_t bufSize = gMaxProtoLen + 1 |
| + XMLString::stringLen(fFragment) + 1 |
| + XMLString::stringLen(fHost) + 2 |
| + XMLString::stringLen(fPassword) + 1 |
| + XMLString::stringLen(fPath) |
| + XMLString::stringLen(fQuery) + 1 |
| + XMLString::stringLen(fUser) + 1 |
| + 32; |
| |
| // Clean up the existing buffer and allocate another |
| fMemoryManager->deallocate(fURLText);//delete [] fURLText; |
| fURLText = (XMLCh*) fMemoryManager->allocate((bufSize) * sizeof(XMLCh));//new XMLCh[bufSize]; |
| *fURLText = 0; |
| |
| XMLCh* outPtr = fURLText; |
| if (fProtocol != Unknown) |
| { |
| XMLString::catString(fURLText, getProtocolName()); |
| outPtr += XMLString::stringLen(fURLText); |
| *outPtr++ = chColon; |
| *outPtr++ = chForwardSlash; |
| *outPtr++ = chForwardSlash; |
| } |
| |
| if (fUser) |
| { |
| XMLString::copyString(outPtr, fUser); |
| outPtr += XMLString::stringLen(fUser); |
| |
| if (fPassword) |
| { |
| *outPtr++ = chColon; |
| XMLString::copyString(outPtr, fPassword); |
| outPtr += XMLString::stringLen(fPassword); |
| } |
| |
| *outPtr++ = chAt; |
| } |
| |
| if (fHost) |
| { |
| XMLString::copyString(outPtr, fHost); |
| outPtr += XMLString::stringLen(fHost); |
| |
| // |
| // If the port is zero, then we don't put it in. Else we need |
| // to because it was explicitly provided. |
| // |
| if (fPortNum) |
| { |
| *outPtr++ = chColon; |
| |
| XMLCh tmpBuf[17]; |
| XMLString::binToText(fPortNum, tmpBuf, 16, 10, fMemoryManager); |
| XMLString::copyString(outPtr, tmpBuf); |
| outPtr += XMLString::stringLen(tmpBuf); |
| } |
| } |
| |
| if (fPath) |
| { |
| XMLString::copyString(outPtr, fPath); |
| outPtr += XMLString::stringLen(fPath); |
| } |
| |
| if (fQuery) |
| { |
| *outPtr++ = chQuestion; |
| XMLString::copyString(outPtr, fQuery); |
| outPtr += XMLString::stringLen(fQuery); |
| } |
| |
| if (fFragment) |
| { |
| *outPtr++ = chPound; |
| XMLString::copyString(outPtr, fFragment); |
| outPtr += XMLString::stringLen(fFragment); |
| } |
| |
| // Cap it off in case the last op was not a string copy |
| *outPtr = 0; |
| } |
| |
| |
| // |
| // Just a central place to handle cleanup, since its done from a number |
| // of different spots. |
| // |
| void XMLURL::cleanUp() |
| { |
| fMemoryManager->deallocate(fFragment);//delete [] fFragment; |
| fMemoryManager->deallocate(fHost);//delete [] fHost; |
| fMemoryManager->deallocate(fPassword);//delete [] fPassword; |
| fMemoryManager->deallocate(fPath);//delete [] fPath; |
| fMemoryManager->deallocate(fQuery);//delete [] fQuery; |
| fMemoryManager->deallocate(fUser);//delete [] fUser; |
| fMemoryManager->deallocate(fURLText);//delete [] fURLText; |
| |
| fFragment = 0; |
| fHost = 0; |
| fPassword = 0; |
| fPath = 0; |
| fQuery = 0; |
| fUser = 0; |
| fURLText = 0; |
| |
| fProtocol = Unknown; |
| fPortNum = 0; |
| fHasInvalidChar = false; |
| } |
| |
| |
| //This function has been modified to take a bool parameter and the |
| //functionality inside looks irrational but is only to make |
| //solaris 2.7 CC 5.0 optimized build happy. |
| |
| bool XMLURL::conglomerateWithBase(const XMLURL& baseURL, bool useExceptions) |
| { |
| // The base URL cannot be relative |
| if (baseURL.isRelative()) |
| { |
| if (useExceptions) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_RelativeBaseURL, fMemoryManager); |
| else |
| return false; |
| } |
| |
| // |
| // Check a special case. If all we have is a fragment, then we want |
| // to just take the base host and path, plus our fragment. |
| // |
| if ((fProtocol == Unknown) |
| && !fHost |
| && !fPath |
| && fFragment) |
| { |
| // Just in case, make sure we don't leak the user or password values |
| fMemoryManager->deallocate(fUser);//delete [] fUser; |
| fUser = 0; |
| fMemoryManager->deallocate(fPassword);//delete [] fPassword; |
| fPassword = 0; |
| |
| // Copy over the protocol and port number as is |
| fProtocol = baseURL.fProtocol; |
| fPortNum = baseURL.fPortNum; |
| |
| // Replicate the base fields that are provided |
| fHost = XMLString::replicate(baseURL.fHost, fMemoryManager); |
| fUser = XMLString::replicate(baseURL.fUser, fMemoryManager); |
| fPassword = XMLString::replicate(baseURL.fPassword, fMemoryManager); |
| fPath = XMLString::replicate(baseURL.fPath, fMemoryManager); |
| return true; |
| } |
| |
| // |
| // All we have to do is run up through our fields and, for each one |
| // that we don't have, use the based URL's. Once we hit one field |
| // that we have, we stop. |
| // |
| if (fProtocol != Unknown) |
| return true; |
| fProtocol = baseURL.fProtocol; |
| |
| // |
| // If the protocol is not file, and we either already have our own |
| // host, or the base does not have one, then we are done. |
| // |
| if (fProtocol != File) |
| { |
| if (fHost || !baseURL.fHost) |
| return true; |
| } |
| |
| // Replicate all of the hosty stuff if the base has one |
| if (baseURL.fHost) |
| { |
| // Just in case, make sure we don't leak a user or password field |
| fMemoryManager->deallocate(fUser);//delete [] fUser; |
| fUser = 0; |
| fMemoryManager->deallocate(fPassword);//delete [] fPassword; |
| fPassword = 0; |
| fMemoryManager->deallocate(fHost);//delete [] fHost; |
| fHost = 0; |
| |
| fHost = XMLString::replicate(baseURL.fHost, fMemoryManager); |
| fUser = XMLString::replicate(baseURL.fUser, fMemoryManager); |
| fPassword = XMLString::replicate(baseURL.fPassword, fMemoryManager); |
| |
| fPortNum = baseURL.fPortNum; |
| } |
| |
| // If we have a path and its absolute, then we are done |
| const bool hadPath = (fPath != 0); |
| if (hadPath) |
| { |
| if (*fPath == chForwardSlash) |
| return true; |
| } |
| |
| // Its a relative path, so weave them together. |
| if (baseURL.fPath) { |
| XMLCh* temp = XMLPlatformUtils::weavePaths(baseURL.fPath, fPath ,fMemoryManager); |
| fMemoryManager->deallocate(fPath);//delete [] fPath; |
| fPath = temp; |
| } |
| |
| // If we had any original path, then we are done |
| if (hadPath) |
| return true; |
| |
| // We had no original path, so go on to deal with the query/fragment parts |
| if (fQuery || !baseURL.fQuery) |
| return true; |
| fQuery = XMLString::replicate(baseURL.fQuery, fMemoryManager); |
| |
| if (fFragment || !baseURL.fFragment) |
| return true; |
| fFragment = XMLString::replicate(baseURL.fFragment, fMemoryManager); |
| return true; |
| } |
| |
| |
| void XMLURL::parse(const XMLCh* const urlText) |
| { |
| // Simplify things by checking for the psycho scenarios first |
| if (!*urlText) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager); |
| |
| // Before we start, check if this urlText contains valid uri characters |
| if (!XMLUri::isURIString(urlText)) |
| fHasInvalidChar = true; |
| else |
| fHasInvalidChar = false; |
| |
| // |
| // The first thing we will do is to check for a file name, so that |
| // we don't waste time thinking its a URL. If its in the form x:\ or x:/ |
| // and x is an ASCII letter, then assume that's the deal. |
| // |
| if (((*urlText >= chLatin_A) && (*urlText <= chLatin_Z)) |
| || ((*urlText >= chLatin_a) && (*urlText <= chLatin_z))) |
| { |
| if (*(urlText + 1) == chColon) |
| { |
| if ((*(urlText + 2) == chForwardSlash) |
| || (*(urlText + 2) == chBackSlash)) |
| { |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager); |
| } |
| } |
| } |
| |
| // Get a copy of the URL that we can modify |
| XMLCh* srcCpy = XMLString::replicate(urlText, fMemoryManager); |
| ArrayJanitor<XMLCh> janSrcCopy(srcCpy, fMemoryManager); |
| |
| // |
| // Get a pointer now that we can run up thrown the source as we parse |
| // bits and pieces out of it. |
| // |
| XMLCh* srcPtr = srcCpy; |
| |
| // Run up past any spaces |
| while (*srcPtr) |
| { |
| if (!XMLChar1_0::isWhitespace(*srcPtr)) |
| break; |
| srcPtr++; |
| } |
| |
| // Make sure it wasn't all space |
| if (!*srcPtr) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_NoProtocolPresent, fMemoryManager); |
| |
| // |
| // Ok, the next thing we have to do is to find either a / or : character. |
| // If the : is first, we assume we have a protocol. If the / is first, |
| // then we skip to the host processing. |
| // |
| XMLCh* ptr1 = XMLString::findAny(srcPtr, gListOne); |
| XMLCh* ptr2; |
| |
| // If we found a protocol, then deal with it |
| if (ptr1) |
| { |
| if (*ptr1 == chColon) |
| { |
| // Cap the string at the colon |
| *ptr1 = 0; |
| |
| // And try to find it in our list of protocols |
| fProtocol = lookupByName(srcPtr); |
| |
| if (fProtocol == Unknown) |
| { |
| ThrowXMLwithMemMgr1 |
| ( |
| MalformedURLException |
| , XMLExcepts::URL_UnsupportedProto1 |
| , srcPtr |
| , fMemoryManager |
| ); |
| } |
| |
| // And move our source pointer up past what we've processed |
| srcPtr = (ptr1 + 1); |
| } |
| } |
| |
| // |
| // Ok, next we need to see if we have any host part. If the next |
| // two characters are //, then we need to check, else move on. |
| // |
| if ((*srcPtr == chForwardSlash) && (*(srcPtr + 1) == chForwardSlash)) |
| { |
| // Move up past the slashes |
| srcPtr += 2; |
| |
| // |
| // If we aren't at the end of the string, then there has to be a |
| // host part at this point. we will just look for the next / char |
| // or end of string and make all of that the host for now. |
| // |
| if (*srcPtr) |
| { |
| // Search from here for a / character |
| ptr1 = XMLString::findAny(srcPtr, gListFour); |
| |
| // |
| // If we found something, then the host is between where |
| // we are and what we found. Else the host is the rest of |
| // the content and we are done. If its empty, leave it null. |
| // |
| if (ptr1) |
| { |
| if (ptr1 != srcPtr) |
| { |
| fMemoryManager->deallocate(fHost);//delete [] fHost; |
| fHost = (XMLCh*) fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = fHost; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| } |
| else |
| { |
| fMemoryManager->deallocate(fHost);//delete [] fHost; |
| fHost = XMLString::replicate(srcPtr, fMemoryManager); |
| |
| // Update source pointer to the end |
| srcPtr += XMLString::stringLen(fHost); |
| } |
| } |
| } |
| else |
| { |
| // |
| // http protocol requires two forward slashes |
| // we didn't get them, so throw an exception |
| // |
| if (fProtocol == HTTP) { |
| ThrowXMLwithMemMgr |
| ( |
| MalformedURLException |
| , XMLExcepts::URL_ExpectingTwoSlashes |
| , fMemoryManager |
| ); |
| } |
| } |
| |
| // |
| // If there was a host part, then we have to grovel through it for |
| // all the bits and pieces it can hold. |
| // |
| if (fHost) |
| { |
| // |
| // Look for a '@' character, which indicates a user name. If we |
| // find one, then everything between the start of the host data |
| // and the character is the user name. |
| // |
| ptr1 = XMLString::findAny(fHost, gListTwo); |
| if (ptr1) |
| { |
| // Get this info out as the user name |
| *ptr1 = 0; |
| fMemoryManager->deallocate(fUser);//delete [] fUser; |
| fUser = XMLString::replicate(fHost, fMemoryManager); |
| ptr1++; |
| |
| // And now cut these chars from the host string |
| XMLString::cut(fHost, ptr1 - fHost); |
| |
| // Is there a password inside the user string? |
| ptr2 = XMLString::findAny(fUser, gListThree); |
| if (ptr2) |
| { |
| // Remove it from the user name string |
| *ptr2 = 0; |
| |
| // And copy out the remainder to the password field |
| ptr2++; |
| fMemoryManager->deallocate(fPassword);//delete [] fPassword; |
| fPassword = XMLString::replicate(ptr2, fMemoryManager); |
| } |
| } |
| |
| // |
| // Ok, so now we are at the actual host name, if any. If we are |
| // not at the end of the host data, then lets see if we have a |
| // port trailing the |
| // |
| ptr1 = XMLString::findAny(fHost, gListThree); |
| if (ptr1) |
| { |
| // Remove it from the host name |
| *ptr1 = 0; |
| |
| // Try to convert it to a numeric port value and store it |
| ptr1++; |
| if (!XMLString::textToBin(ptr1, fPortNum, fMemoryManager)) |
| ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_BadPortField, fMemoryManager); |
| } |
| |
| // If the host ended up empty, then toss is |
| if (!*fHost) |
| { |
| fMemoryManager->deallocate(fHost);//delete[] fHost; |
| fHost = 0; |
| } |
| } |
| |
| // If we are at the end, then we are done now |
| if (!*srcPtr) { |
| if(fHost) { |
| static const XMLCh slash[] = { chForwardSlash, chNull }; |
| fPath = XMLString::replicate(slash, fMemoryManager); |
| } |
| return; |
| } |
| |
| // |
| // Next is the path part. It can be absolute, i.e. starting with a |
| // forward slash character, or relative. Its basically everything up |
| // to the end of the string or to any trailing query or fragment. |
| // |
| ptr1 = XMLString::findAny(srcPtr, gListFive); |
| if (!ptr1) |
| { |
| fMemoryManager->deallocate(fPath);//delete [] fPath; |
| fPath = XMLString::replicate(srcPtr, fMemoryManager); |
| return; |
| } |
| |
| // Everything from where we are to what we found is the path |
| if (ptr1 > srcPtr) |
| { |
| fMemoryManager->deallocate(fPath);//delete [] fPath; |
| fPath = (XMLCh*) fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = fPath; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| |
| // |
| // If we found a fragment, then it is the rest of the string and we |
| // are done. |
| // |
| if (*srcPtr == chPound) |
| { |
| srcPtr++; |
| fMemoryManager->deallocate(fFragment);//delete [] fFragment; |
| fFragment = XMLString::replicate(srcPtr, fMemoryManager); |
| return; |
| } |
| |
| // |
| // The query is either the rest of the string, or up to the fragment |
| // separator. |
| // |
| srcPtr++; |
| ptr1 = XMLString::findAny(srcPtr, gListSix); |
| fMemoryManager->deallocate(fQuery);//delete [] fQuery; |
| if (!ptr1) |
| { |
| fQuery = XMLString::replicate(srcPtr, fMemoryManager); |
| return; |
| } |
| else |
| { |
| fQuery = (XMLCh*) fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = fQuery; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| |
| // If we are not at the end now, then everything else is the fragment |
| if (*srcPtr == chPound) |
| { |
| srcPtr++; |
| fMemoryManager->deallocate(fFragment);//delete [] fFragment; |
| fFragment = XMLString::replicate(srcPtr, fMemoryManager); |
| } |
| } |
| |
| bool XMLURL::parse(const XMLCh* const urlText, XMLURL& xmlURL) |
| { |
| // Simplify things by checking for the psycho scenarios first |
| if (!*urlText) |
| return false; |
| |
| // Before we start, check if this urlText contains valid uri characters |
| if (!XMLUri::isURIString(urlText)) |
| xmlURL.fHasInvalidChar = true; |
| else |
| xmlURL.fHasInvalidChar = false; |
| |
| // |
| // The first thing we will do is to check for a file name, so that |
| // we don't waste time thinking its a URL. If its in the form x:\ or x:/ |
| // and x is an ASCII letter, then assume that's the deal. |
| // |
| if (((*urlText >= chLatin_A) && (*urlText <= chLatin_Z)) |
| || ((*urlText >= chLatin_a) && (*urlText <= chLatin_z))) |
| { |
| if (*(urlText + 1) == chColon) |
| { |
| if ((*(urlText + 2) == chForwardSlash) |
| || (*(urlText + 2) == chBackSlash)) |
| { |
| return false; |
| } |
| } |
| } |
| |
| // Get a copy of the URL that we can modify |
| XMLCh* srcCpy = XMLString::replicate(urlText, xmlURL.fMemoryManager); |
| ArrayJanitor<XMLCh> janSrcCopy(srcCpy, xmlURL.fMemoryManager); |
| |
| // |
| // Get a pointer now that we can run up thrown the source as we parse |
| // bits and pieces out of it. |
| // |
| XMLCh* srcPtr = srcCpy; |
| |
| // Run up past any spaces |
| while (*srcPtr) |
| { |
| if (!XMLChar1_0::isWhitespace(*srcPtr)) |
| break; |
| srcPtr++; |
| } |
| |
| // Make sure it wasn't all space |
| if (!*srcPtr) |
| return false; |
| |
| // |
| // Ok, the next thing we have to do is to find either a / or : character. |
| // If the : is first, we assume we have a protocol. If the / is first, |
| // then we skip to the host processing. |
| // |
| XMLCh* ptr1 = XMLString::findAny(srcPtr, gListOne); |
| XMLCh* ptr2; |
| |
| // If we found a protocol, then deal with it |
| if (ptr1) |
| { |
| if (*ptr1 == chColon) |
| { |
| // Cap the string at the colon |
| *ptr1 = 0; |
| |
| // And try to find it in our list of protocols |
| xmlURL.fProtocol = lookupByName(srcPtr); |
| |
| if (xmlURL.fProtocol == Unknown) |
| return false; |
| |
| // And move our source pointer up past what we've processed |
| srcPtr = (ptr1 + 1); |
| } |
| } |
| |
| // |
| // Ok, next we need to see if we have any host part. If the next |
| // two characters are //, then we need to check, else move on. |
| // |
| if ((*srcPtr == chForwardSlash) && (*(srcPtr + 1) == chForwardSlash)) |
| { |
| // Move up past the slashes |
| srcPtr += 2; |
| |
| // |
| // If we aren't at the end of the string, then there has to be a |
| // host part at this point. we will just look for the next / char |
| // or end of string and make all of that the host for now. |
| // |
| if (*srcPtr) |
| { |
| // Search from here for a / character |
| ptr1 = XMLString::findAny(srcPtr, gListFour); |
| |
| // |
| // If we found something, then the host is between where |
| // we are and what we found. Else the host is the rest of |
| // the content and we are done. If its empty, leave it null. |
| // |
| if (ptr1) |
| { |
| if (ptr1 != srcPtr) |
| { |
| xmlURL.fHost = (XMLCh*) xmlURL.fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = xmlURL.fHost; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| } |
| else |
| { |
| xmlURL.fHost = XMLString::replicate(srcPtr, xmlURL.fMemoryManager); |
| |
| // Update source pointer to the end |
| srcPtr += XMLString::stringLen(xmlURL.fHost); |
| } |
| } |
| } |
| else |
| { |
| // |
| // http protocol requires two forward slashes |
| // we didn't get them, so throw an exception |
| // |
| if (xmlURL.fProtocol == HTTP) |
| return false; |
| } |
| |
| // |
| // If there was a host part, then we have to grovel through it for |
| // all the bits and pieces it can hold. |
| // |
| if (xmlURL.fHost) |
| { |
| // |
| // Look for a '@' character, which indicates a user name. If we |
| // find one, then everything between the start of the host data |
| // and the character is the user name. |
| // |
| ptr1 = XMLString::findAny(xmlURL.fHost, gListTwo); |
| if (ptr1) |
| { |
| // Get this info out as the user name |
| *ptr1 = 0; |
| xmlURL.fUser = XMLString::replicate(xmlURL.fHost, xmlURL.fMemoryManager); |
| ptr1++; |
| |
| // And now cut these chars from the host string |
| XMLString::cut(xmlURL.fHost, ptr1 - xmlURL.fHost); |
| |
| // Is there a password inside the user string? |
| ptr2 = XMLString::findAny(xmlURL.fUser, gListThree); |
| if (ptr2) |
| { |
| // Remove it from the user name string |
| *ptr2 = 0; |
| |
| // And copy out the remainder to the password field |
| ptr2++; |
| xmlURL.fPassword = XMLString::replicate(ptr2, xmlURL.fMemoryManager); |
| } |
| } |
| |
| // |
| // Ok, so now we are at the actual host name, if any. If we are |
| // not at the end of the host data, then lets see if we have a |
| // port trailing the |
| // |
| ptr1 = XMLString::findAny(xmlURL.fHost, gListThree); |
| if (ptr1) |
| { |
| // Remove it from the host name |
| *ptr1 = 0; |
| |
| // Try to convert it to a numeric port value and store it |
| ptr1++; |
| if (!XMLString::textToBin(ptr1, xmlURL.fPortNum, xmlURL.fMemoryManager)) |
| return false; |
| } |
| |
| // If the host ended up empty, then toss is |
| if (!*(xmlURL.fHost)) |
| { |
| xmlURL.fMemoryManager->deallocate(xmlURL.fHost);//delete[] fHost; |
| xmlURL.fHost = 0; |
| } |
| } |
| |
| // If we are at the end, then we are done now |
| if (!*srcPtr) { |
| if(xmlURL.fHost) { |
| static const XMLCh slash[] = { chForwardSlash, chNull }; |
| xmlURL.fPath = XMLString::replicate(slash, xmlURL.fMemoryManager); |
| } |
| return true; |
| } |
| |
| // |
| // Next is the path part. It can be absolute, i.e. starting with a |
| // forward slash character, or relative. Its basically everything up |
| // to the end of the string or to any trailing query or fragment. |
| // |
| ptr1 = XMLString::findAny(srcPtr, gListFive); |
| if (!ptr1) |
| { |
| xmlURL.fPath = XMLString::replicate(srcPtr, xmlURL.fMemoryManager); |
| return true; |
| } |
| |
| // Everything from where we are to what we found is the path |
| if (ptr1 > srcPtr) |
| { |
| xmlURL.fPath = (XMLCh*) xmlURL.fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = xmlURL.fPath; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| |
| // |
| // If we found a fragment, then it is the rest of the string and we |
| // are done. |
| // |
| if (*srcPtr == chPound) |
| { |
| srcPtr++; |
| xmlURL.fFragment = XMLString::replicate(srcPtr, xmlURL.fMemoryManager); |
| return true; |
| } |
| |
| // |
| // The query is either the rest of the string, or up to the fragment |
| // separator. |
| // |
| srcPtr++; |
| ptr1 = XMLString::findAny(srcPtr, gListSix); |
| if (!ptr1) |
| { |
| xmlURL.fQuery = XMLString::replicate(srcPtr, xmlURL.fMemoryManager); |
| return true; |
| } |
| else |
| { |
| xmlURL.fQuery = (XMLCh*) xmlURL.fMemoryManager->allocate |
| ( |
| ((ptr1 - srcPtr) + 1) * sizeof(XMLCh) |
| );//new XMLCh[(ptr1 - srcPtr) + 1]; |
| ptr2 = xmlURL.fQuery; |
| while (srcPtr < ptr1) |
| *ptr2++ = *srcPtr++; |
| *ptr2 = 0; |
| } |
| |
| // If we are not at the end now, then everything else is the fragment |
| if (*srcPtr == chPound) |
| { |
| srcPtr++; |
| xmlURL.fFragment = XMLString::replicate(srcPtr, xmlURL.fMemoryManager); |
| } |
| |
| return true; |
| } |
| |
| XERCES_CPP_NAMESPACE_END |