blob: d5a25c53d8af67ec6bf94c898e0f2fa63c33910b [file] [log] [blame]
/*
* 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 <config.h>
#endif
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#if HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#if !HAVE_GETTIMEOFDAY && HAVE_SYS_TIMEB_H
# include <sys/timeb.h>
#endif
#if HAVE_CPUID_H && !XERCES_HAVE_INTRIN_H
# include <cpuid.h>
#endif
#include <xercesc/util/Mutexes.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/RefVectorOf.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/internal/XMLReader.hpp>
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/util/DefaultPanicHandler.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/internal/MemoryManagerImpl.hpp>
#if XERCES_HAVE_INTRIN_H
# include <intrin.h>
#endif
#include <xercesc/util/XMLFileMgr.hpp>
#if XERCES_USE_FILEMGR_POSIX
# include <xercesc/util/FileManagers/PosixFileMgr.hpp>
#endif
#if XERCES_USE_FILEMGR_WINDOWS
# include <xercesc/util/FileManagers/WindowsFileMgr.hpp>
#endif
#include <xercesc/util/XMLMutexMgr.hpp>
#if XERCES_USE_MUTEXMGR_NOTHREAD
# include <xercesc/util/MutexManagers/NoThreadMutexMgr.hpp>
#endif
#if XERCES_USE_MUTEXMGR_POSIX
# include <xercesc/util/MutexManagers/PosixMutexMgr.hpp>
#endif
#if XERCES_USE_MUTEXMGR_WINDOWS
# include <xercesc/util/MutexManagers/WindowsMutexMgr.hpp>
#endif
#include <xercesc/util/XMLNetAccessor.hpp>
#if XERCES_USE_NETACCESSOR_CURL
# include <xercesc/util/NetAccessors/Curl/CurlNetAccessor.hpp>
#endif
#if XERCES_USE_NETACCESSOR_SOCKET
# include <xercesc/util/NetAccessors/Socket/SocketNetAccessor.hpp>
#endif
#if XERCES_USE_NETACCESSOR_CFURL
# include <xercesc/util/NetAccessors/MacOSURLAccessCF/MacOSURLAccessCF.hpp>
#endif
#if XERCES_USE_NETACCESSOR_WINSOCK
# include <xercesc/util/NetAccessors/WinSock/WinSockNetAccessor.hpp>
#endif
#include <xercesc/util/XMLMsgLoader.hpp>
#if XERCES_USE_MSGLOADER_ICU
# include <xercesc/util/MsgLoaders/ICU/ICUMsgLoader.hpp>
#endif
#if XERCES_USE_MSGLOADER_ICONV
# include <xercesc/util/MsgLoaders/MsgCatalog/MsgCatalogLoader.hpp>
#endif
#if XERCES_USE_MSGLOADER_INMEMORY
# include <xercesc/util/MsgLoaders/InMemory/InMemMsgLoader.hpp>
#endif
#include <xercesc/util/TransService.hpp>
#if XERCES_USE_TRANSCODER_ICU
# include <xercesc/util/Transcoders/ICU/ICUTransService.hpp>
#endif
#if XERCES_USE_TRANSCODER_GNUICONV
# include <xercesc/util/Transcoders/IconvGNU/IconvGNUTransService.hpp>
#endif
#if XERCES_USE_TRANSCODER_ICONV
# include <xercesc/util/Transcoders/Iconv/IconvTransService.hpp>
#endif
#if XERCES_USE_TRANSCODER_MACOSUNICODECONVERTER
# include <xercesc/util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.hpp>
#endif
#if XERCES_USE_TRANSCODER_WINDOWS
# include <xercesc/util/Transcoders/Win32/Win32TransService.hpp>
#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_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 <OS>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 <OS>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 <OS>PlatformUtils.cpp. When PlatformUtils.cp get compiled,
* the weavePath(), remove**Slash() have dependency upon isAnySlash() which
* is in <OS>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 <OS>PlatformUtils.cpp.
*
* The solution to this is <os>PlatformUtils.cpp will include this file so that
* we have only one copy of these methods while get compiled in <os>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;
if (relativePath)
{
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<XMLCh> 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<XMLCh> tmp1Name(tmp1, manager);
XMLCh* tmp2 = (XMLCh*) manager->allocate
(
(pathLen+1) * sizeof(XMLCh)
);//new XMLCh [pathLen+1];
ArrayJanitor<XMLCh> tmp2Name(tmp2, manager);
// remove all "<segment>/../" where "<segment>" 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 <segment> 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 <segment> 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