/* * 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: PlatformUtils.hpp 568078 2007-08-21 11:43:25Z amassari $ */ #if !defined(PLATFORMUTILS_HPP) #define PLATFORMUTILS_HPP #include #include XERCES_CPP_NAMESPACE_BEGIN class XMLMsgLoader; class XMLNetAccessor; class XMLTransService; class MemoryManager; class XMLMutex; // // For internal use only // // This class provides a simple abstract API via which lazily evaluated // data can be cleaned up. // class XMLUTIL_EXPORT XMLDeleter { public : virtual ~XMLDeleter(); protected : XMLDeleter(); private : XMLDeleter(const XMLDeleter&); XMLDeleter& operator=(const XMLDeleter&); }; /** * Utilities that must be implemented in a platform-specific way. * * This class contains methods that must be implemented in a platform * specific manner. The actual implementations of these methods are * available in the per-platform files indide src/util/Platforms * . */ class XMLUTIL_EXPORT XMLPlatformUtils { public : /** @name Public Static Data */ //@{ /** The network accessor * * This is provided by the per-platform driver, so each platform can * choose what actual implementation it wants to use. The object must * be dynamically allocated. * * Note that you may optionally, if your platform driver does not * install a network accessor, set it manually from your client code * after calling Initialize(). This works because this object is * not required during initialization, and only comes into play during * actual XML parsing. */ static XMLNetAccessor* fgNetAccessor; /** The transcoding service. * * This is provided by the per platform driver, so each platform can * choose what implemenation it wants to use. When the platform * independent initialization code needs to get a transcoding service * object, it will call makeTransService() to ask the * per-platform code to create one. Only one transcoding service * object is reqeusted per-process, so it is shared and synchronized * among parser instances within that process. */ static XMLTransService* fgTransService; #ifdef OS390 static XMLTransService* fgTransService2; #endif /** The Panic Handler * * This is the application provided panic handler. */ static PanicHandler* fgUserPanicHandler; /** The Panic Handler * * This is the default panic handler. */ static PanicHandler* fgDefaultPanicHandler; /** The configurable memory manager * * This is the pluggable memory manager. If it is not provided by an * application, a default implementation is used. */ static MemoryManager* fgMemoryManager; /** The array-allocating memory manager * * This memory manager always allocates memory by calling the * global new[] operator. It may be used to allocate memory * where such memory needs to be deletable by calling delete []. * Since this allocator is always guaranteed to do the same thing * there is no reason, nor facility, to override it. */ static MemoryManager* fgArrayMemoryManager; static XMLMutex* fgAtomicMutex; //@} /** @name Initialization amd Panic methods */ //@{ /** Perform per-process parser initialization * * Initialization must be called first in any client code. * * The locale is set iff the Initialize() is invoked for the very first time, * to ensure that each and every message loaders, in the process space, share * the same locale. * * All subsequent invocations of Initialize(), with a different locale, have * no effect on the message loaders, either instantiated, or to be instantiated. * * To set to a different locale, client application needs to Terminate() (or * multiple Terminate() in the case where multiple Initialize() have been invoked * before), followed by Initialize(new_locale). * * The default locale is "en_US". * * nlsHome: user specified location where MsgLoader retrieves error message files. * the discussion above with regard to locale, applies to this nlsHome * as well. * * panicHandler: application's panic handler, application owns this handler. * Application shall make sure that the plugged panic handler persists * through the call to XMLPlatformUtils::terminate(). * * memoryManager: plugged-in memory manager which is owned by user * applications. Applications must make sure that the * plugged-in memory manager persist through the call to * XMLPlatformUtils::terminate() */ static void Initialize(const char* const locale = XMLUni::fgXercescDefaultLocale , const char* const nlsHome = 0 , PanicHandler* const panicHandler = 0 , MemoryManager* const memoryManager = 0 , bool toInitStatics = false); /** Perform per-process parser termination * * The termination call is currently optional, to aid those dynamically * loading the parser to clean up before exit, or to avoid spurious * reports from leak detectors. */ static void Terminate(); /** The panic mechanism. * * If, during initialization, we cannot even get far enough along * to get transcoding up or get message loading working, we call * this method.

* * Each platform can implement it however they want. This method will * delegate the panic handling to a user specified panic handler or * in the absence of it, the default panic handler. * * In case the default panic handler does not support a particular * platform, the platform specific panic hanlding shall be implemented * here

. * * @param reason The enumeration that defines the cause of the failure */ static void panic ( const PanicHandler::PanicReasons reason ); //@} /** @name File Methods */ //@{ /** Get the current file position * * This must be implemented by the per-platform driver, which should * use local file services to deterine the current position within * the passed file. * * Since the file API provided here only reads, if the host platform * supports separate read/write positions, only the read position is * of any interest, and hence should be the one returned. * * @param theFile The file handle * @param manager The MemoryManager to use to allocate objects */ static unsigned int curFilePos(FileHandle theFile , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Closes the file handle * * This must be implemented by the per-platform driver, which should * use local file services to close the passed file handle, and to * destroy the passed file handle and any allocated data or system * resources it contains. * * @param theFile The file handle to close * @param manager The MemoryManager to use to allocate objects */ static void closeFile(FileHandle theFile , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Returns the file size * * This must be implemented by the per-platform driver, which should * use local file services to determine the current size of the file * represented by the passed handle. * * @param theFile The file handle whose size you want * @param manager The MemoryManager to use to allocate objects * @return Returns the size of the file in bytes */ static unsigned int fileSize(FileHandle theFile , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Opens the file * * This must be implemented by the per-platform driver, which should * use local file services to open passed file. If it fails, a * null handle pointer should be returned. * * @param fileName The string containing the name of the file * @param manager The MemoryManager to use to allocate objects * @return The file handle of the opened file */ static FileHandle openFile(const char* const fileName , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Opens a named file * * This must be implemented by the per-platform driver, which should * use local file services to open the passed file. If it fails, a * null handle pointer should be returned. * * @param fileName The string containing the name of the file * @param manager The MemoryManager to use to allocate objects * @return The file handle of the opened file */ static FileHandle openFile(const XMLCh* const fileName , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Open a named file to write * * This must be implemented by the per-platform driver, which should * use local file services to open passed file. If it fails, a * null handle pointer should be returned. * * @param fileName The string containing the name of the file * @param manager The MemoryManager to use to allocate objects * @return The file handle of the opened file */ static FileHandle openFileToWrite(const char* const fileName , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Open a named file to write * * This must be implemented by the per-platform driver, which should * use local file services to open the passed file. If it fails, a * null handle pointer should be returned. * * @param fileName The string containing the name of the file * @param manager The MemoryManager to use to allocate objects * @return The file handle of the opened file */ static FileHandle openFileToWrite(const XMLCh* const fileName , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Opens the standard input as a file * * This must be implemented by the per-platform driver, which should * use local file services to open a handle to the standard input. * It should be a copy of the standard input handle, since it will * be closed later! * * @param manager The MemoryManager to use to allocate objects * @return The file handle of the standard input stream */ static FileHandle openStdInHandle(MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Reads the file buffer * * This must be implemented by the per-platform driver, which should * use local file services to read up to 'toRead' bytes of data from * the passed file, and return those bytes in the 'toFill' buffer. It * is not an error not to read the requested number of bytes. When the * end of file is reached, zero should be returned. * * @param theFile The file handle to be read from. * @param toRead The maximum number of byte to read from the current * position * @param toFill The byte buffer to fill * @param manager The MemoryManager to use to allocate objects * * @return Returns the number of bytes read from the stream or file */ static unsigned int readFileBuffer ( FileHandle theFile , const unsigned int toRead , XMLByte* const toFill , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); /** Writes the buffer to the file * * This must be implemented by the per-platform driver, which should * use local file services to write up to 'toWrite' bytes of data to * the passed file. Unless exception raised by local file services, * 'toWrite' bytes of data is to be written to the passed file. * * @param theFile The file handle to be written to. * @param toWrite The maximum number of byte to write from the current * position * @param toFlush The byte buffer to flush * @param manager The MemoryManager to use to allocate objects * @return void */ static void writeBufferToFile ( FileHandle const theFile , long toWrite , const XMLByte* const toFlush , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); /** Resets the file handle * * This must be implemented by the per-platform driver which will use * local file services to reset the file position to the start of the * the file. * * @param theFile The file handle that you want to reset * @param manager The MemoryManager to use to allocate objects */ static void resetFile(FileHandle theFile , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); //@} /** @name File System Methods */ //@{ /** Gets the full path from a relative path * * This must be implemented by the per-platform driver. It should * complete a relative path using the 'current directory', or whatever * the local equivalent of a current directory is. If the passed * source path is actually fully qualified, then a straight copy of it * will be returned. * * @param srcPath The path of the file for which you want the full path * * @param manager Pointer to the memory manager to be used to * allocate objects. * * @return Returns the fully qualified path of the file name including * the file name. This is dyanmically allocated and must be * deleted by the caller when its no longer needed! The memory * returned will beallocated using the static memory manager, if * user do not supply a memory manager. Users then need to make * sure to use either the default or user specific memory manager * to deallocate the memory. */ static XMLCh* getFullPath ( const XMLCh* const srcPath , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); /** Gets the current working directory * * This must be implemented by the per-platform driver. It returns * the current working directory is. * @param manager The MemoryManager to use to allocate objects * @return Returns the current working directory. * This is dyanmically allocated and must be deleted * by the caller when its no longer needed! The memory returned * will be allocated using the static memory manager, if users * do not supply a memory manager. Users then need to make sure * to use either the default or user specific memory manager to * deallocate the memory. */ static XMLCh* getCurrentDirectory ( MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); /** Check if a charater is a slash * * This must be implemented by the per-platform driver. * * @param c the character to be examined * * @return true if the character examined is a slash * false otherwise */ static inline bool isAnySlash(XMLCh c); /** Remove occurences of the pair of dot slash * * To remove the sequence, dot slash if it is part of the sequence, * slash dot slash. * * @param srcPath The path for which you want to remove the dot slash sequence. * @param manager The MemoryManager to use to allocate objects * @return */ static void removeDotSlash(XMLCh* const srcPath , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Remove occurences of the dot dot slash * * To remove the sequence, slash dot dot slash and its preceding path segment * if and only if the preceding path segment is not slash dot dot slash. * * @param srcPath The path for which you want to remove the slash dot * dot slash sequence and its preceding path segment. * @param manager The MemoryManager to use to allocate objects * @return */ static void removeDotDotSlash(XMLCh* const srcPath , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** Determines if a path is relative or absolute * * This must be implemented by the per-platform driver, which should * determine whether the passed path is relative or not. The concept * of relative and absolute might be... well relative on different * platforms. But, as long as the determination is made consistently * and in coordination with the weavePaths() method, it should work * for any platform. * * @param toCheck The file name which you want to check * @param manager The MemoryManager to use to allocate objects * @return Returns true if the filename appears to be relative */ static bool isRelative(const XMLCh* const toCheck , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); /** Utility to join two paths * * This must be implemented by the per-platform driver, and should * weave the relative path part together with the base part and return * a new path that represents this combination. * * If the relative part turns out to be fully qualified, it will be * returned as is. If it is not, then it will be woven onto the * passed base path, by removing one path component for each leading * "../" (or whatever is the equivalent in the local system) in the * relative path. * * @param basePath The string containing the base path * @param relativePath The string containing the relative path * @param manager The MemoryManager to use to allocate objects * @return Returns a string containing the 'woven' path. It should * be dynamically allocated and becomes the responsibility of the * caller to delete. */ static XMLCh* weavePaths ( const XMLCh* const basePath , const XMLCh* const relativePath , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager ); //@} /** @name Timing Methods */ //@{ /** Gets the system time in milliseconds * * This must be implemented by the per-platform driver, which should * use local services to return the current value of a running * millisecond timer. Note that the value returned is only as accurate * as the millisecond time of the underyling host system. * * @return Returns the system time as an unsigned long */ static unsigned long getCurrentMillis(); //@} /** @name Mutex Methods */ //@{ /** Closes a mutex handle * * Each per-platform driver must implement this. Only it knows what * the actual content of the passed mutex handle is. * * @param mtxHandle The mutex handle that you want to close */ static void closeMutex(void* const mtxHandle); /** Locks a mutex handle * * Each per-platform driver must implement this. Only it knows what * the actual content of the passed mutex handle is. * * @param mtxHandle The mutex handle that you want to lock */ static void lockMutex(void* const mtxHandle); /** Make a new mutex * * Each per-platform driver must implement this. Only it knows what * the actual content of the passed mutex handle is. The returned * handle pointer will be eventually passed to closeMutex() which is * also implemented by the platform driver. * * @param manager The MemoryManager to use to allocate objects */ static void* makeMutex(MemoryManager* manager = XMLPlatformUtils::fgMemoryManager); /** Unlocks a mutex * * Each per-platform driver must implement this. Only it knows what * the actual content of the passed mutex handle is. * * Note that, since the underlying system synchronization services * are used, Xerces cannot guarantee that lock/unlock operations are * correctly enforced on a per-thread basis or that incorrect nesting * of lock/unlock operations will be caught. * * @param mtxHandle The mutex handle that you want to unlock */ static void unlockMutex(void* const mtxHandle); //@} /** @name External Message Support */ //@{ /** Loads the message set from among the available domains * * The returned object must be dynamically allocated and the caller * becomes responsible for cleaning it up. * * @param msgDomain The message domain which you want to load */ static XMLMsgLoader* loadMsgSet(const XMLCh* const msgDomain); //@} /** @name Miscellaneous synchronization methods */ //@{ /** Conditionally updates or returns a single word variable atomically * * This must be implemented by the per-platform driver. The * compareAndSwap subroutine performs an atomic operation which * compares the contents of a single word variable with a stored old * value. If the values are equal, a new value is stored in the single * word variable and TRUE is returned; otherwise, the old value is set * to the current value of the single word variable and FALSE is * returned. * * The compareAndSwap subroutine is useful when a word value must be * updated only if it has not been changed since it was last read. * * Note: The word containing the single word variable must be aligned * on a full word boundary. * * @param toFill Specifies the address of the single word variable * @param newValue Specifies the new value to be conditionally assigned * to the single word variable. * @param toCompare Specifies the address of the old value to be checked * against (and conditionally updated with) the value of the single word * variable. * * @return Returns the new value assigned to the single word variable */ static void* compareAndSwap ( void** toFill , const void* const newValue , const void* const toCompare ); //@} /** @name Atomic Increment and Decrement */ //@{ /** Increments a single word variable atomically. * * This must be implemented by the per-platform driver. The * atomicIncrement subroutine increments one word in a single atomic * operation. This operation is useful when a counter variable is shared * between several threads or processes. When updating such a counter * variable, it is important to make sure that the fetch, update, and * store operations occur atomically (are not interruptible). * * @param location Specifies the address of the word variable to be * incremented. * * @return The function return value is positive if the result of the * operation was positive. Zero if the result of the operation was zero. * Negative if the result of the operation was negative. Except for the * zero case, the value returned may differ from the actual result of * the operation - only the sign and zero/nonzero state is guaranteed * to be correct. */ static int atomicIncrement(int& location); /** Decrements a single word variable atomically. * * This must be implemented by the per-platform driver. The * atomicDecrement subroutine increments one word in a single atomic * operation. This operation is useful when a counter variable is shared * between several threads or processes. When updating such a counter * variable, it is important to make sure that the fetch, update, and * store operations occur atomically (are not interruptible). * * @param location Specifies the address of the word variable to be * decremented. * * @return The function return value is positive if the result of the * operation was positive. Zero if the result of the operation was zero. * Negative if the result of the operation was negative. Except for the * zero case, the value returned may differ from the actual result of the * operation - only the sign and zero/nonzero state is guaranteed to be * correct. */ static int atomicDecrement(int& location); //@} /** @name NEL Character Handling */ //@{ /** * This function enables the recognition of NEL(0x85) char and LSEP (0x2028) as newline chars * which is disabled by default. * It is only called once per process. Once it is set, any subsequent calls * will result in exception being thrown. * * Note: 1. Turning this option on will make the parser non compliant to XML 1.0. * 2. This option has no effect to document conforming to XML 1.1 compliant, * which always recognize these two chars (0x85 and 0x2028) as newline characters. * */ static void recognizeNEL(bool state , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager); /** * Return the value of fgNEL flag. */ static bool isNELRecognized(); //@} /** @name Strict IANA Encoding Checking */ //@{ /** * This function enables/disables strict IANA encoding names checking. * * The strict checking is disabled by default. * * @param state If true, a strict IANA encoding name check is performed, * otherwise, no checking. * */ static void strictIANAEncoding(const bool state); /** * Returns whether a strict IANA encoding name check is enabled or * disabled. */ static bool isStrictIANAEncoding(); //@} /** * Aligns the specified pointer per platform block allocation * requirements. * * The results of this function may be altered by defining * XML_PLATFORM_NEW_BLOCK_ALIGNMENT. */ static inline size_t alignPointerForNewBlockAllocation(size_t ptrSize); private : // ----------------------------------------------------------------------- // Unimplemented constructors and operators // ----------------------------------------------------------------------- XMLPlatformUtils(); /** @name Private static methods */ //@{ /** Loads a message set from the available domains * * @param msgDomain The message domain containing the message to be * loaded */ static XMLMsgLoader* loadAMsgSet(const XMLCh* const msgDomain); /** Creates a net accessor object. * * Each per-platform driver must implement this method. However, * having a Net Accessor is optional and this method can return a * null pointer if remote access via HTTP and FTP URLs is not required. * * @return An object derived from XMLNetAccessor. It must be dynamically * allocated, since it will be deleted later. */ static XMLNetAccessor* makeNetAccessor(); /** Creates a Transoding service * * Each per-platform driver must implement this method and return some * derivative of the XMLTransService class. This object serves as the * transcoder factory for this process. The object must be dynamically * allocated and the caller is responsible for cleaning it up. * * @return A dynamically allocated object of some class derived from * the XMLTransService class. */ static XMLTransService* makeTransService(); /** Does initialization for a particular platform * * Each per-platform driver must implement this to do any low level * system initialization required. It cannot use any XML * parser or utilities services! */ static void platformInit(); /** Does termination for a particular platform * * Each per-platform driver must implement this to do any low level * system resource cleanup required. It cannot use any XML * parser or utilities services! */ static void platformTerm(); /** Search for sequence, slash dot dot slash * * @param srcPath the path to search * * @return the position of the first occurence of slash dot dot slash * -1 if no such sequence is found */ static int searchSlashDotDotSlash(XMLCh* const srcPath); //@} /** @name Private static methods */ //@{ /** * Indicates whether the memory manager was supplied by the user * or not. Users own the memory manager, and if none is supplied, * Xerces uses a default one that it owns and is responsible for * deleting in Terminate(). */ static bool fgMemMgrAdopted; //@} }; MakeXMLException(XMLPlatformUtilsException, XMLUTIL_EXPORT) // --------------------------------------------------------------------------- // XMLPlatformUtils: alignPointerForNewBlockAllocation // --------------------------------------------------------------------------- // Calculate alignment required by platform for a new // block allocation. We use this in our custom allocators // to ensure that returned blocks are properly aligned. // Note that, although this will take a pointer and return the position // at which it should be placed for correct alignment, in our code // we normally use size_t parameters to discover what the alignment // of header blocks should be. Thus, if this is to be // used for the former purpose, to make compilers happy // some casting will be necessary - neilg. // // Note: XML_PLATFORM_NEW_BLOCK_ALIGNMENT may be specified on a // per-architecture basis to dictate the alignment requirements // of the architecture. In the absense of this specification, // this routine guesses at the correct alignment value. // // A XML_PLATFORM_NEW_BLOCK_ALIGNMENT value of zero is illegal. // If a platform requires absolutely no alignment, a value // of 1 should be specified ("align pointers on 1 byte boundaries"). // inline size_t XMLPlatformUtils::alignPointerForNewBlockAllocation(size_t ptrSize) { // Macro XML_PLATFORM_NEW_BLOCK_ALIGNMENT may be defined // as needed to dictate alignment requirements on a // per-architecture basis. In the absense of that we // take an educated guess. #ifdef XML_PLATFORM_NEW_BLOCK_ALIGNMENT size_t alignment = XML_PLATFORM_NEW_BLOCK_ALIGNMENT; #else size_t alignment = (sizeof(void*) >= sizeof(double)) ? sizeof(void*) : sizeof(double); #endif // Calculate current alignment of pointer size_t current = ptrSize % alignment; // Adjust pointer alignment as needed return (current == 0) ? ptrSize : (ptrSize + alignment - current); } // --------------------------------------------------------------------------- // XMLDeleter: Public Destructor // --------------------------------------------------------------------------- inline XMLDeleter::~XMLDeleter() { } // --------------------------------------------------------------------------- // XMLDeleter: Hidden constructors and operators // --------------------------------------------------------------------------- inline XMLDeleter::XMLDeleter() { } XERCES_CPP_NAMESPACE_END #endif