/*
 * 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 1825016 2018-02-21 22:04:13Z rleigh $
 */

#if !defined(XERCESC_INCLUDE_GUARD_PLATFORMUTILS_HPP)
#define XERCESC_INCLUDE_GUARD_PLATFORMUTILS_HPP

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/XMLException.hpp>
#include <xercesc/util/PanicHandler.hpp>

#include <xercesc/util/XMLFileMgr.hpp>
#include <xercesc/util/XMLMutexMgr.hpp>

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 inside <code>src/util/Platforms
  * </code>.
  */
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.
      *
      * <i>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.</i>
      */
    static XMLNetAccessor*      fgNetAccessor;

    /** The transcoding service.
      *
      * This is provided by the per platform driver, so each platform can
      * choose what implementation it wants to use. When the platform
      * independent initialization code needs to get a transcoding service
      * object, it will call <code>makeTransService()</code> to ask the
      * per-platform code to create one. Only one transcoding service
      * object is requested 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;

    static XMLFileMgr*          fgFileMgr;
    static XMLMutexMgr*         fgMutexMgr;

    /** Global mutex for fast or infrequent operations.
      *
      *   Use this mutex only for fast (e.g., increment an integer,
      *   check flag, etc.) or infrequent (e.g., once-off initialization)
      *   operations.
      */
    static XMLMutex*            fgAtomicMutex;

    static bool                 fgXMLChBigEndian;
    static bool                 fgSSE2ok;
    //@}


    /** @name Initialization and Panic methods */
    //@{

    /** Perform per-process parser initialization
      *
      * Initialization <b>must</b> be called first in any client code.
      *
      * @param locale The locale to use for messages.
      *
      * The locale is set iff the Initialize() is invoked for the very first time,
      * to ensure that each and every message loader, 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".
      *
      * @param nlsHome User specified location where MsgLoader retrieves error message files.
      *                the discussion above with regard to locale, applies to nlsHome as well.
      *
      * @param 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().
      *
      * @param memoryManager Plugged-in memory manager which is owned by the
      *                      application. 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);

      /** Perform per-process parser initialization
      *
      * Initialization <b>must</b> be called first in any client code.
      *
      * @param initialDOMHeapAllocSize The size of the first memory block
      * allocated by the DOMDocument heap. Note that changing this parameter
      * may result in poor performance and/or excessive memory usage. For
      * the default value refer to dom/impl/DOMDocumentImpl.cpp.
      *
      * @param maxDOMHeapAllocSize The maximum size of the memory block
      * allocated by the DOMDocument heap. As the document grows, the
      * allocated by the heap memory blocks grow from initialDOMHeapAllocSize
      * to maxDOMHeapAllocSize. Note that changing this parameter may result
      * in poor performance and/or excessive memory usage. For the default
      * value refer to dom/impl/DOMDocumentImpl.cpp.
      *
      * @param maxDOMSubAllocationSize The maximum size of the memory block
      * requested that is handled by the DOMDocument heap. A request for a
      * larger block is handled directly by the memory manager. Note that
      * changing this parameter may result in poor performance and/or
      * excessive memory usage. For the default value refer to
      * dom/impl/DOMDocumentImpl.cpp.
      *
      * @param locale The locale to use for messages.
      *
      * The locale is set iff the Initialize() is invoked for the very first time,
      * to ensure that each and every message loader, 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".
      *
      * @param nlsHome User specified location where MsgLoader retrieves error message files.
      * the discussion above with regard to locale, applies to nlsHome as well.
      *
      * @param 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().
      *
      * @param memoryManager Plugged-in memory manager which is owned by the
      * application. Applications must make sure that the plugged-in memory
      * manager persist through the call to XMLPlatformUtils::Terminate()
      */
    static void Initialize(XMLSize_t initialDOMHeapAllocSize
                         , XMLSize_t maxDOMHeapAllocSize
                         , XMLSize_t maxDOMSubAllocationSize
                         , const char*          const locale = XMLUni::fgXercescDefaultLocale
                         , const char*          const nlsHome = 0
                         ,       PanicHandler*  const panicHandler = 0
                         ,       MemoryManager* const memoryManager = 0);

    /** 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.</p>
      *
      * 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 handling shall be implemented
      * here </p>.
      *
      * @param reason The enumeration that defines the cause of the failure
      */
    static void panic
    (
        const   PanicHandler::PanicReasons    reason
    );

    //@}

    /** @name File Methods */
    //@{

    /** Make a new file object appropriate for the platform.
      *
      * @param manager The MemoryManager to use to allocate objects
      */
    static XMLFileMgr* makeFileMgr(MemoryManager* const manager);

    /** Get the current file position
      *
      * This must be implemented by the per-platform driver, which should
      * use local file services to determine 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 XMLFilePos 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 XMLFilePos 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 XMLSize_t readFileBuffer
    (
                FileHandle      theFile
        , const XMLSize_t       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
        , XMLSize_t             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 character 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 occurrences 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 occurrences 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 underlying host system.
      *
      * @return Returns the system time as an unsigned long
      */
    static unsigned long getCurrentMillis();
    //@}

    /** @name Mutex Methods */
    //@{

    /** Factory method for creating MutexMgr object.
      *
      * This factory method creates a mutexmgr that will be used
      * on the particular platform.
      *
      * @param manager The MemoryManager to use to allocate objects
      */
    static XMLMutexMgr* makeMutexMgr(MemoryManager* const manager);

    /** 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
      * @param manager The MemoryManager used to allocate the object
      */
    static void closeMutex(void* const mtxHandle, MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);

    /** 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* const 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 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 XMLSize_t alignPointerForNewBlockAllocation(XMLSize_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 Transcoding 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();

    /** Search for sequence, slash dot dot slash
      *
      * @param srcPath the path to search
      *
      * @return   the position of the first occurrence 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 XMLSize_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 XMLSize_t
XMLPlatformUtils::alignPointerForNewBlockAllocation(XMLSize_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
    const XMLSize_t alignment = XML_PLATFORM_NEW_BLOCK_ALIGNMENT;
#else
    const XMLSize_t alignment = (sizeof(void*) >= sizeof(double)) ? sizeof(void*) : sizeof(double);
#endif

    //    Calculate current alignment of pointer
    XMLSize_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
