/* * 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 // --------------------------------------------------------------------------- #if HAVE_CONFIG_H # include #endif #if HAVE_LIMITS_H # include #endif #if HAVE_SYS_TIME_H # include #endif #if HAVE_SYS_TIMEB_H # include #endif #if HAVE_CPUID_H && !XERCES_HAVE_INTRIN_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #if XERCES_HAVE_INTRIN_H # include #endif #include #if XERCES_USE_FILEMGR_POSIX # include #endif #if XERCES_USE_FILEMGR_WINDOWS # include #endif #include #if XERCES_USE_MUTEXMGR_NOTHREAD # include #endif #if XERCES_USE_MUTEXMGR_POSIX # include #endif #if XERCES_USE_MUTEXMGR_WINDOWS # include #endif #include #if XERCES_USE_NETACCESSOR_CURL # include #endif #if XERCES_USE_NETACCESSOR_SOCKET # include #endif #if XERCES_USE_NETACCESSOR_CFURL # include #endif #if XERCES_USE_NETACCESSOR_WINSOCK # include #endif #include #if XERCES_USE_MSGLOADER_ICU # include #endif #if XERCES_USE_MSGLOADER_ICONV # include #endif #if XERCES_USE_MSGLOADER_INMEMORY # include #endif #if XERCES_USE_WIN32_MSGLOADER # include #endif #include #if XERCES_USE_TRANSCODER_ICU # include #endif #if XERCES_USE_TRANSCODER_GNUICONV # include #endif #if XERCES_USE_TRANSCODER_ICONV # include #endif #if XERCES_USE_TRANSCODER_MACOSUNICODECONVERTER # include #endif #if XERCES_USE_TRANSCODER_WINDOWS # include #endif XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // Local data members // // gSyncMutex // This is a mutex that will be used to synchronize access to some of // the static data of the platform utilities class and here locally. // --------------------------------------------------------------------------- static XMLMutex* gSyncMutex = 0; static long gInitFlag = 0; // --------------------------------------------------------------------------- // XMLPlatformUtils: Static Data Members // --------------------------------------------------------------------------- XMLNetAccessor* XMLPlatformUtils::fgNetAccessor = 0; XMLTransService* XMLPlatformUtils::fgTransService = 0; #ifdef OS390 XMLTransService* XMLPlatformUtils::fgTransService2 = 0; #endif PanicHandler* XMLPlatformUtils::fgUserPanicHandler = 0; PanicHandler* XMLPlatformUtils::fgDefaultPanicHandler = 0; MemoryManager* XMLPlatformUtils::fgMemoryManager = 0; bool XMLPlatformUtils::fgMemMgrAdopted = true; XMLFileMgr* XMLPlatformUtils::fgFileMgr = 0; XMLMutexMgr* XMLPlatformUtils::fgMutexMgr = 0; XMLMutex* XMLPlatformUtils::fgAtomicMutex = 0; bool XMLPlatformUtils::fgXMLChBigEndian = true; bool XMLPlatformUtils::fgSSE2ok = false; // --------------------------------------------------------------------------- // XMLPlatformUtils: Init/term methods // --------------------------------------------------------------------------- void XMLPlatformUtils::Initialize(const char* const locale , const char* const nlsHome , PanicHandler* const panicHandler , MemoryManager* const memoryManager) { // // Effects of overflow: // . resouce re-allocations // . consequently resource leaks // . potentially terminate() may never get executed // // We got to prevent overflow from happening. // no error or exception // if (gInitFlag == LONG_MAX) return; // // Make sure we haven't already been initialized. Note that this is not // thread safe and is not intended for that. Its more for those COM // like processes that cannot keep up with whether they have initialized // us yet or not. // gInitFlag++; if (gInitFlag > 1) return; // Set pluggable memory manager if (!fgMemoryManager) { if (memoryManager) { fgMemoryManager = memoryManager; fgMemMgrAdopted = false; } else { fgMemoryManager = new MemoryManagerImpl(); } } /*** * Panic Handler: * ***/ if (!panicHandler) { fgDefaultPanicHandler = new DefaultPanicHandler(); } else { fgUserPanicHandler = panicHandler; } // Determine our endianness (with regard to a XMLCh 16-bit word) union { XMLCh ch; unsigned char ar[sizeof(XMLCh)]; } endianTest; endianTest.ch = 1; fgXMLChBigEndian = (endianTest.ar[sizeof(XMLCh)-1] == 1); // Determine if we can use SSE2 functions #if defined(XERCES_HAVE_CPUID_INTRINSIC) int CPUInfo[4]={0}; __cpuid(CPUInfo, 1); if(CPUInfo[3] & (1UL << 26)) fgSSE2ok = true; else fgSSE2ok = false; #elif defined(XERCES_HAVE_GETCPUID) unsigned int eax, ebx, ecx, edx; if(!__get_cpuid (1, &eax, &ebx, &ecx, &edx) || (edx & (1UL << 26))==0) fgSSE2ok = false; else fgSSE2ok = true; #elif defined(XERCES_HAVE_SSE2_INTRINSIC) // if we cannot find out at runtime, assume the define has it right fgSSE2ok = true; #else fgSSE2ok = false; #endif // Initialize the platform-specific mutex and file mgrs fgMutexMgr = makeMutexMgr(fgMemoryManager); fgFileMgr = makeFileMgr(fgMemoryManager); // Create the local sync mutex gSyncMutex = new XMLMutex(fgMemoryManager); // Create the global "atomic operations" mutex. fgAtomicMutex = new XMLMutex(fgMemoryManager); // // Ask the per-platform code to make the desired transcoding service for // us to use. This call cannot throw any exceptions or do anything that // cause any transcoding to happen. It should create the service and // return it or zero if it cannot. // // This one also cannot use any utility services. It can only create a // transcoding service object and return it. // // If we cannot make one, then we call panic to end the process. // XMLInitializer::initializeTransService(); // TransService static data. fgTransService = makeTransService(); if (!fgTransService) panic(PanicHandler::Panic_NoTransService); // Initialize the transcoder service fgTransService->initTransService(); // // Try to create a default local code page transcoder. This is the one // that will be used internally by the XMLString class. If we cannot // create one, then call the panic method. // XMLLCPTranscoder* defXCode = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(fgMemoryManager); if (!defXCode) panic(PanicHandler::Panic_NoDefTranscoder); XMLString::initString(defXCode, fgMemoryManager); // // Now lets ask the per-platform code to give us an instance of the type // of network access implementation he wants to use. This can return // a zero pointer if this platform doesn't want to support this. // fgNetAccessor = makeNetAccessor(); /*** * Message Loader: * * Locale setting * nlsHome setting ***/ XMLMsgLoader::setLocale(locale); XMLMsgLoader::setNLSHome(nlsHome); // Initialize static data. // XMLInitializer::initializeStaticData(); } void XMLPlatformUtils::Initialize(XMLSize_t initialDOMHeapAllocSize , XMLSize_t maxDOMHeapAllocSize , XMLSize_t maxDOMSubAllocationSize , const char* const locale , const char* const nlsHome , PanicHandler* const panicHandler , MemoryManager* const memoryManager) { Initialize (locale, nlsHome, panicHandler, memoryManager); // Don't change the parameters unless it is the first time. // if (gInitFlag == 1) XMLInitializer::initializeDOMHeap(initialDOMHeapAllocSize, maxDOMHeapAllocSize, maxDOMSubAllocationSize); } void XMLPlatformUtils::Terminate() { // // To prevent it from running underflow. // otherwise we come to delete non-existing resources. // // no error or exception // if (gInitFlag == 0) return; gInitFlag--; if (gInitFlag > 0) return; // Terminate static data. // XMLInitializer::terminateStaticData(); // Delete any net accessor that got installed delete fgNetAccessor; fgNetAccessor = 0; // // Call some other internal modules to give them a chance to clean up. // Do the string class last in case something tries to use it during // cleanup. // XMLString::termString(); // Clean up the the transcoding service delete fgTransService; fgTransService = 0; XMLInitializer::terminateTransService(); // TransService static data. // Clean up mutexes delete gSyncMutex; gSyncMutex = 0; delete fgAtomicMutex; fgAtomicMutex = 0; // Clean up our mgrs delete fgFileMgr; fgFileMgr = 0; delete fgMutexMgr; fgMutexMgr = 0; /*** * de-allocate resource * * refer to discussion in the Initialize() ***/ XMLMsgLoader::setLocale(0); XMLMsgLoader::setNLSHome(0); delete fgDefaultPanicHandler; fgDefaultPanicHandler = 0; fgUserPanicHandler = 0; // de-allocate default memory manager if (fgMemMgrAdopted) delete fgMemoryManager; else fgMemMgrAdopted = true; // set memory manager to 0 fgMemoryManager = 0; // And say we are no longer initialized gInitFlag = 0; } // --------------------------------------------------------------------------- // XMLPlatformUtils: The panic method // --------------------------------------------------------------------------- void XMLPlatformUtils::panic(const PanicHandler::PanicReasons reason) { fgUserPanicHandler? fgUserPanicHandler->panic(reason) : fgDefaultPanicHandler->panic(reason); } // --------------------------------------------------------------------------- // XMLPlatformUtils: Private Static Methods // --------------------------------------------------------------------------- XMLNetAccessor* XMLPlatformUtils::makeNetAccessor() { XMLNetAccessor* na = 0; #if defined (XERCES_USE_NETACCESSOR_CURL) na = new CurlNetAccessor(); #elif defined (XERCES_USE_NETACCESSOR_SOCKET) na = new SocketNetAccessor(); #elif defined (XERCES_USE_NETACCESSOR_CFURL) na = new MacOSURLAccessCF(); #elif defined (XERCES_USE_NETACCESSOR_WINSOCK) na = new WinSockNetAccessor(); #endif return na; } // // This method is called by the platform independent part of this class // when client code asks to have one of the supported message sets loaded. // XMLMsgLoader* XMLPlatformUtils::loadAMsgSet(const XMLCh* const msgDomain) { XMLMsgLoader* ms=0; try { #if defined (XERCES_USE_MSGLOADER_ICU) ms = new ICUMsgLoader(msgDomain); #elif defined (XERCES_USE_MSGLOADER_ICONV) ms = new MsgCatalogLoader(msgDomain); #elif defined (XERCES_USE_WIN32_MSGLOADER) ms = new Win32MsgLoader(msgDomain); #elif defined (XERCES_USE_MSGLOADER_INMEMORY) ms = new InMemMsgLoader(msgDomain); #else #error No MsgLoader configured for platform! You must configure it. #endif } catch(const OutOfMemoryException&) { throw; } catch(...) { panic(PanicHandler::Panic_CantLoadMsgDomain); } return ms; } // // This method is called very early in the bootstrapping process. This guy // must create a transcoding service and return it. It cannot use any string // methods, any transcoding services, throw any exceptions, etc... It just // makes a transcoding service and returns it, or returns zero on failure. // XMLTransService* XMLPlatformUtils::makeTransService() { XMLTransService* tc = 0; #if defined (XERCES_USE_TRANSCODER_ICU) tc = new ICUTransService(fgMemoryManager); #elif defined (XERCES_USE_TRANSCODER_GNUICONV) tc = new IconvGNUTransService(fgMemoryManager); #elif defined (XERCES_USE_TRANSCODER_ICONV) tc = new IconvTransService(fgMemoryManager); #elif defined (XERCES_USE_TRANSCODER_MACOSUNICODECONVERTER) tc = new MacOSUnicodeConverter(fgMemoryManager); #elif defined (XERCES_USE_TRANSCODER_WINDOWS) tc = new Win32TransService(fgMemoryManager); #else #error No Transcoder configured for platform! You must configure it. #endif return tc; } // --------------------------------------------------------------------------- // XMLPlatformUtils: File Methods // --------------------------------------------------------------------------- XMLFileMgr* XMLPlatformUtils::makeFileMgr(MemoryManager* const memmgr) { XMLFileMgr* mgr = NULL; #if XERCES_USE_FILEMGR_POSIX mgr = new (memmgr) PosixFileMgr; #elif XERCES_USE_FILEMGR_WINDOWS mgr = new (memmgr) WindowsFileMgr; #else #error No File Manager configured for platform! You must configure it. #endif return mgr; } FileHandle XMLPlatformUtils::openFile(const char* const fileName , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileOpen(fileName, false, memmgr); } FileHandle XMLPlatformUtils::openFile(const XMLCh* const fileName, MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileOpen(fileName, false, memmgr); } FileHandle XMLPlatformUtils::openFileToWrite(const char* const fileName , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileOpen(fileName, true, memmgr); } FileHandle XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileOpen(fileName, true, memmgr); } FileHandle XMLPlatformUtils::openStdInHandle(MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->openStdIn(memmgr); } void XMLPlatformUtils::closeFile(FileHandle theFile , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); fgFileMgr->fileClose(theFile, memmgr); } void XMLPlatformUtils::resetFile(FileHandle theFile , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); fgFileMgr->fileReset(theFile, memmgr); } XMLFilePos XMLPlatformUtils::curFilePos(FileHandle theFile , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->curPos(theFile, memmgr); } XMLFilePos XMLPlatformUtils::fileSize(FileHandle theFile , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileSize(theFile, memmgr); } XMLSize_t XMLPlatformUtils::readFileBuffer( FileHandle theFile , const XMLSize_t toRead , XMLByte* const toFill , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->fileRead(theFile, toRead, toFill, memmgr); } void XMLPlatformUtils::writeBufferToFile( const FileHandle theFile , XMLSize_t toWrite , const XMLByte* const toFlush , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); fgFileMgr->fileWrite(theFile, toWrite, toFlush, memmgr); } // --------------------------------------------------------------------------- // XMLPlatformUtils: File system methods // --------------------------------------------------------------------------- XMLCh* XMLPlatformUtils::getFullPath(const XMLCh* const srcPath, MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->getFullPath(srcPath, memmgr); } XMLCh* XMLPlatformUtils::getCurrentDirectory(MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->getCurrentDirectory(memmgr); } bool XMLPlatformUtils::isRelative(const XMLCh* const toCheck , MemoryManager* const memmgr) { if (!fgFileMgr) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr); return fgFileMgr->isRelative(toCheck, memmgr); } inline bool XMLPlatformUtils::isAnySlash(XMLCh c) { // As far as we know, all supported Xerces // platforms use at least a forward slash // as a path delimiter. So we always check for // that. // // If XERCES_PATH_DELIMITER_BACKSLASH evaluates to true, // we also consider that as a slash. // // XERCES_PATH_DELIMITER_BACKSLASH may be set in config.h // by configure, or elsewhere by platform-specific // code. return ( false || chForwardSlash == c #if XERCES_PATH_DELIMITER_BACKSLASH || chBackSlash == c #endif ); } // --------------------------------------------------------------------------- // XMLPlatformUtils: Timing Methods // --------------------------------------------------------------------------- unsigned long XMLPlatformUtils::getCurrentMillis() { unsigned long ms = 0; // *** TODO: additional platform support? #if HAVE_GETTIMEOFDAY struct timeval aTime; gettimeofday(&aTime, NULL); ms = (unsigned long) (aTime.tv_sec * 1000 + aTime.tv_usec / 1000); #elif HAVE_FTIME timeb aTime; ftime(&aTime); ms = (unsigned long)(aTime.time*1000 + aTime.millitm); #else // Make this a warning instead? #error No timing support is configured for this platform. You must configure it. #endif return ms; } // ----------------------------------------------------------------------- // Mutex methods // ----------------------------------------------------------------------- XMLMutexMgr* XMLPlatformUtils::makeMutexMgr(MemoryManager* const memmgr) { XMLMutexMgr* mgr = NULL; #if XERCES_USE_MUTEXMGR_NOTHREAD mgr = new (memmgr) NoThreadMutexMgr; #elif XERCES_USE_MUTEXMGR_POSIX mgr = new (memmgr) PosixMutexMgr; #elif XERCES_USE_MUTEXMGR_WINDOWS mgr = new (memmgr) WindowsMutexMgr; #else #error No Mutex Manager configured for platform! You must configure it. #endif return mgr; } XMLMutexHandle XMLPlatformUtils::makeMutex(MemoryManager* const memmgr) { if (!fgMutexMgr) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); return fgMutexMgr->create(memmgr); } void XMLPlatformUtils::closeMutex(XMLMutexHandle const mtx, MemoryManager* const memmgr) { if (!fgMutexMgr) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); fgMutexMgr->destroy(mtx, memmgr); } void XMLPlatformUtils::lockMutex(XMLMutexHandle const mtx) { if (!fgMutexMgr) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); fgMutexMgr->lock(mtx); } void XMLPlatformUtils::unlockMutex(XMLMutexHandle const mtx) { if (!fgMutexMgr) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); fgMutexMgr->unlock(mtx); } // --------------------------------------------------------------------------- // XMLPlatformUtils: Msg support methods // --------------------------------------------------------------------------- XMLMsgLoader* XMLPlatformUtils::loadMsgSet(const XMLCh* const msgDomain) { // // Ask the platform support to load up the correct type of message // loader for the indicated message set. We don't check here whether it // works or not. That's their decision. // return loadAMsgSet(msgDomain); } // --------------------------------------------------------------------------- // XMLPlatformUtils: NEL Character Handling // --------------------------------------------------------------------------- void XMLPlatformUtils::recognizeNEL(bool state, MemoryManager* const manager) { //Make sure initialize has been called if (gInitFlag == 0) { return; } if (state) { if (!XMLChar1_0::isNELRecognized()) { XMLChar1_0::enableNELWS(); } } else { if (XMLChar1_0::isNELRecognized()) { ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::NEL_RepeatedCalls, manager); } } } bool XMLPlatformUtils::isNELRecognized() { return XMLChar1_0::isNELRecognized(); } // --------------------------------------------------------------------------- // XMLPlatformUtils: IANA Encoding checking setting // --------------------------------------------------------------------------- void XMLPlatformUtils::strictIANAEncoding(const bool state) { //Make sure initialize has been called if (gInitFlag == 0) { return; } fgTransService->strictIANAEncoding(state); } bool XMLPlatformUtils::isStrictIANAEncoding() { if (gInitFlag) return fgTransService->isStrictIANAEncoding(); return false; } /*** * * Previously, each PlatformUtils.cpp has its onw copy of the * method weavePaths(), and almost of them implemented the same logic, * with few platform specific difference, and unfortunately that * implementation was wrong. * * The only platform specific issue is slash character. * On all platforms other than Windows, chForwardSlash and chBackSlash * are considered slash, while on Windows, two additional characters, * chYenSign and chWonSign are slash as well. * * The idea is to maintain a SINGLE copy of this method rather than * each PlatformUtils.cpp has its own copy, we introduce a new * method, XMLPlatformUtils::isAnySlash(), to replace the direct checking * code ( if ( c == chForwardSlash || c == chBackSlash). * * With this approach, we might have a performance hit since isAnySlash() * is so frequently used in this implementation, so we intend to make it * inline. Then we face a complier issue. * * There are two compilation units involved, one is PlatformUtils.cpp and * the other PlatformUtils.cpp. When PlatformUtils.cp get compiled, * the weavePath(), remove**Slash() have dependency upon isAnySlash() which * is in PlatformUtils.cpp (and what is worse, it is inlined), so we have * undefined/unresolved symbol: isAnySlash() on AIX/xlc_r, Solaris/cc and * Linux/gcc, while MSVC and HP/aCC are fine with this. * * That means we can not place these new methods in PlatformUtils.cpp with * inlined XMLPlatformUtils::isAnySlash() in PlatformUtils.cpp. * * The solution to this is PlatformUtils.cpp will include this file so that * we have only one copy of these methods while get compiled in PlatformUtils * inlined isAnySlash(). * ***/ XMLCh* XMLPlatformUtils::weavePaths(const XMLCh* const basePath , const XMLCh* const relativePath , MemoryManager* const manager) { // Create a buffer as large as both parts and empty it XMLCh* tmpBuf = (XMLCh*) manager->allocate ( (XMLString::stringLen(basePath) + XMLString::stringLen(relativePath) + 2) * sizeof(XMLCh) );//new XMLCh[XMLString::stringLen(basePath) + XMLString::stringLen(relativePath) + 2]; *tmpBuf = 0; // // If we have no base path, then just take the relative path as is. // if ((!basePath) || (!*basePath)) { XMLString::copyString(tmpBuf, relativePath); return tmpBuf; } // // Remove anything after the last slash // const XMLCh* basePtr = basePath + (XMLString::stringLen(basePath) - 1); while ((basePtr >= basePath) && ((isAnySlash(*basePtr) == false))) { basePtr--; } // There is no relevant base path, so just take the relative part if (basePtr < basePath) { XMLString::copyString(tmpBuf, relativePath); return tmpBuf; } // // 1. concatenate the base and relative // 2. remove all occurences of "/./" // 3. remove all occurences of segment/../ where segment is not ../ // XMLString::subString(tmpBuf, basePath, 0, (basePtr - basePath + 1), manager); tmpBuf[basePtr - basePath + 1] = 0; XMLString::catString(tmpBuf, relativePath); removeDotSlash(tmpBuf, manager); removeDotDotSlash(tmpBuf, manager); return tmpBuf; } // // Remove all occurences of './' when it is part of '/./' // // Since it could be '.\' or other combination on windows ( eg, '.'+chYanSign) // we can't make use of patterMatch(). // // void XMLPlatformUtils::removeDotSlash(XMLCh* const path , MemoryManager* const manager) { if ((!path) || (!*path)) return; XMLCh* srcPtr = XMLString::replicate(path, manager); XMLSize_t srcLen = XMLString::stringLen(srcPtr); ArrayJanitor janName(srcPtr, manager); XMLCh* tarPtr = path; while (*srcPtr) { if ( 3 <= srcLen ) { if ( (isAnySlash(*srcPtr)) && (chPeriod == *(srcPtr+1)) && (isAnySlash(*(srcPtr+2))) ) { // "\.\x" seen // skip the first two, and start from the 3rd, // since "\x" could be another "\." srcPtr+=2; srcLen-=2; } else { *tarPtr++ = *srcPtr++; // eat the current char srcLen--; } } else if ( 1 == srcLen ) { *tarPtr++ = *srcPtr++; } else if ( 2 == srcLen) { *tarPtr++ = *srcPtr++; *tarPtr++ = *srcPtr++; } } *tarPtr = 0; return; } // // Remove all occurences of '/segment/../' when segment is not '..' // // Cases with extra /../ is left to the underlying file system. // void XMLPlatformUtils::removeDotDotSlash(XMLCh* const path , MemoryManager* const manager) { XMLSize_t pathLen = XMLString::stringLen(path); XMLCh* tmp1 = (XMLCh*) manager->allocate ( (pathLen+1) * sizeof(XMLCh) );//new XMLCh [pathLen+1]; ArrayJanitor tmp1Name(tmp1, manager); XMLCh* tmp2 = (XMLCh*) manager->allocate ( (pathLen+1) * sizeof(XMLCh) );//new XMLCh [pathLen+1]; ArrayJanitor tmp2Name(tmp2, manager); // remove all "/../" where "" is a complete // path segment not equal to ".." int index = -1; int segIndex = -1; int offset = 1; while ((index = searchSlashDotDotSlash(&(path[offset]))) != -1) { // Undo offset index += offset; // Find start of within substring ending at found point. XMLString::subString(tmp1, path, 0, index-1, manager); segIndex = index - 1; while ((segIndex >= 0) && (!isAnySlash(tmp1[segIndex]))) { segIndex--; } // Ensure exists and != ".." if (segIndex >= 0 && (path[segIndex+1] != chPeriod || path[segIndex+2] != chPeriod || segIndex + 3 != index)) { XMLString::subString(tmp1, path, 0, segIndex, manager); XMLString::subString(tmp2, path, index+3, XMLString::stringLen(path), manager); path[0] = 0; XMLString::catString(path, tmp1); XMLString::catString(path, tmp2); offset = (segIndex == 0 ? 1 : segIndex); } else { offset += 4; } }// while } int XMLPlatformUtils::searchSlashDotDotSlash(XMLCh* const srcPath) { if ((!srcPath) || (!*srcPath)) return -1; XMLCh* srcPtr = srcPath; XMLSize_t srcLen = XMLString::stringLen(srcPath); int retVal = -1; while (*srcPtr) { if ( 4 <= srcLen ) { if ( (isAnySlash(*srcPtr)) && (chPeriod == *(srcPtr+1)) && (chPeriod == *(srcPtr+2)) && (isAnySlash(*(srcPtr+3))) ) { retVal = (int)(srcPtr - srcPath); break; } else { srcPtr++; srcLen--; } } else { break; } } // while return retVal; } XERCES_CPP_NAMESPACE_END