Skip to content
Snippets Groups Projects
PlatformUtils.cpp 32.5 KiB
Newer Older
PeiYong Zhang's avatar
PeiYong Zhang committed
/*
 * Copyright 1999-2004 The Apache Software Foundation.
 * 
 * Licensed 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.
PeiYong Zhang's avatar
PeiYong Zhang committed
 */

/*
PeiYong Zhang's avatar
PeiYong Zhang committed
 *
 */


// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#if HAVE_CONFIG_H
#	include <config.h>
#else
#	include <xercesc/util/Xerces_no_autoconf_config.hpp>
#endif

#if HAVE_LIMITS_H
#	include <limits.h>
#endif
#if HAVE_SYS_TIME_H
#	include <sys/time.h>
#endif
#if HAVE_SYS_TIMEB_H
#	include <sys/timeb.h>
#endif

PeiYong Zhang's avatar
PeiYong Zhang committed
#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>
PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/util/XMLRegisterCleanup.hpp>
PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/util/DefaultPanicHandler.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/internal/MemoryManagerImpl.hpp>
#include <xercesc/internal/MemoryManagerArrayImpl.hpp>
PeiYong Zhang's avatar
PeiYong Zhang committed

#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/XMLAtomicOpMgr.hpp>
#if XERCES_USE_ATOMICOPMGR_NOTHREAD
#	include <xercesc/util/AtomicOpManagers/NoThreadAtomicOpMgr.hpp>
#endif
#if XERCES_USE_ATOMICOPMGR_POSIX
#	include <xercesc/util/AtomicOpManagers/PosixAtomicOpMgr.hpp>
#endif
#if XERCES_USE_ATOMICOPMGR_MACOS
#	include <xercesc/util/AtomicOpManagers/MacOSAtomicOpMgr.hpp>
#endif
#if XERCES_USE_ATOMICOPMGR_WINDOWS
#	include <xercesc/util/AtomicOpManagers/WindowsAtomicOpMgr.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_LIBWWW
#	include <xercesc/util/NetAccessors/libWWW/LibWWWNetAccessor.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
#if XERCES_USE_WIN32_MSGLOADER
#	include <xercesc/util/MsgLoaders/Win32/Win32MsgLoader.hpp>
#endif

#include <xercesc/util/TransService.hpp>
#if XERCES_USE_TRANSCODER_ICU
#	include <xercesc/util/Transcoders/ICU/ICUTransService.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
PeiYong Zhang's avatar
PeiYong Zhang committed

Tinny Ng's avatar
Tinny Ng committed
XERCES_CPP_NAMESPACE_BEGIN
PeiYong Zhang's avatar
PeiYong Zhang committed

// ---------------------------------------------------------------------------
//  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;

// ---------------------------------------------------------------------------
//  Global data
//
//	gXMLCleanupList
Tinny Ng's avatar
Tinny Ng committed
//		This is a list of cleanup functions to be called on
PeiYong Zhang's avatar
PeiYong Zhang committed
//		XMLPlatformUtils::Terminate.  Their function is to reset static
//		data in classes that use it.
//
//	gXMLCleanupListMutex
//		This is a mutex that will be used to synchronise access to the global
//		static data cleanup list
// ---------------------------------------------------------------------------
XMLRegisterCleanup*	gXMLCleanupList = 0;
XMLMutex*           gXMLCleanupListMutex = 0;
PeiYong Zhang's avatar
PeiYong Zhang committed


// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Static Data Members
// ---------------------------------------------------------------------------
XMLNetAccessor*         XMLPlatformUtils::fgNetAccessor = 0;
XMLTransService*        XMLPlatformUtils::fgTransService = 0;
PanicHandler*           XMLPlatformUtils::fgUserPanicHandler = 0;
PanicHandler*           XMLPlatformUtils::fgDefaultPanicHandler = 0;
MemoryManager*          XMLPlatformUtils::fgMemoryManager = 0;
MemoryManagerArrayImpl  gArrayMemoryManager;
MemoryManager*          XMLPlatformUtils::fgArrayMemoryManager = &gArrayMemoryManager;
bool                    XMLPlatformUtils::fgMemMgrAdopted = true;

XMLFileMgr*             XMLPlatformUtils::fgFileMgr = 0;
XMLMutexMgr*            XMLPlatformUtils::fgMutexMgr = 0;
XMLAtomicOpMgr*         XMLPlatformUtils::fgAtomicOpMgr = 0;

XMLMutex*				XMLPlatformUtils::fgAtomicMutex = 0;

bool					XMLPlatformUtils::fgXMLChBigEndian = true;
PeiYong Zhang's avatar
PeiYong Zhang committed

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Init/term methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::Initialize(const char*          const locale 
                                , const char*          const nlsHome
                                ,       PanicHandler*  const panicHandler
                                ,       MemoryManager* const memoryManager
                                ,       bool                 toInitStatics)
PeiYong Zhang's avatar
PeiYong Zhang committed
{
    //
    //  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
Tinny Ng's avatar
Tinny Ng committed
    //
PeiYong Zhang's avatar
PeiYong Zhang committed
    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;
PeiYong Zhang's avatar
PeiYong Zhang committed

    // Set pluggable memory manager
    if (!fgMemoryManager)
    {
        if (memoryManager)
        {
            fgMemoryManager = memoryManager;
            fgMemMgrAdopted = false;
        }
        else
        {
            fgMemoryManager = new MemoryManagerImpl();
        }
    }
PeiYong Zhang's avatar
PeiYong Zhang committed

PeiYong Zhang's avatar
PeiYong Zhang committed
    /***
     * 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);
    
    
    // Initialize the platform-specific mutex file, and atomic op mgrs
    fgMutexMgr		= makeMutexMgr(fgMemoryManager);
    fgAtomicOpMgr	= makeAtomicOpMgr(fgMemoryManager);
    fgFileMgr		= makeFileMgr(fgMemoryManager);
    
    
PeiYong Zhang's avatar
PeiYong Zhang committed
    // Create the local sync mutex
    gSyncMutex = new XMLMutex(fgMemoryManager);
PeiYong Zhang's avatar
PeiYong Zhang committed

	// Create the mutex for the static data cleanup list
    gXMLCleanupListMutex = new XMLMutex(fgMemoryManager);
    fgAtomicMutex = new XMLMutex(fgMemoryManager);
PeiYong Zhang's avatar
PeiYong Zhang committed

    //
    //  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.
    //
    fgTransService = makeTransService();

    if (!fgTransService)
PeiYong Zhang's avatar
PeiYong Zhang committed
        panic(PanicHandler::Panic_NoTransService);
PeiYong Zhang's avatar
PeiYong Zhang committed

    // 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();
    if (!defXCode)
PeiYong Zhang's avatar
PeiYong Zhang committed
        panic(PanicHandler::Panic_NoDefTranscoder);
    XMLString::initString(defXCode, fgMemoryManager);
PeiYong Zhang's avatar
PeiYong Zhang committed

    //
    //  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();
     ***/
    XMLMsgLoader::setLocale(locale);
PeiYong Zhang's avatar
PeiYong Zhang committed

    if (toInitStatics) {
        XMLInitializer::InitializeAllStaticData();
    }
PeiYong Zhang's avatar
PeiYong Zhang committed
}


void XMLPlatformUtils::Terminate()
{
    //
    // To prevent it from running underflow.
    // otherwise we come to delete non-existing resources.
    //
    //  no error or exception
Tinny Ng's avatar
Tinny Ng committed
    //
PeiYong Zhang's avatar
PeiYong Zhang committed
    if (gInitFlag == 0)
        return;

	gInitFlag--;
	
	if (gInitFlag > 0)
		return;

    // 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;

    // Clean up mutexes
    delete gSyncMutex;		gSyncMutex = 0;
    delete fgAtomicMutex;	fgAtomicMutex = 0;
PeiYong Zhang's avatar
PeiYong Zhang committed
	// Clean up statically allocated, lazily cleaned data in each class
	// that has registered for it.
	// Note that calling doCleanup() also unregisters the cleanup
	// function, so that we are chewing the list down to nothing here
	while (gXMLCleanupList)
		gXMLCleanupList->doCleanup();

	// Clean up the mutex for accessing gXMLCleanupList
	delete gXMLCleanupListMutex;
	gXMLCleanupListMutex = 0;

	// Clean up our mgrs
	delete fgFileMgr;		fgFileMgr = 0;
	delete fgAtomicOpMgr;	fgAtomicOpMgr = 0;
	delete fgMutexMgr;		fgMutexMgr = 0;
	
    /***
     *  de-allocate resource
     *
     *  refer to discussion in the Initialize()
     ***/
    XMLMsgLoader::setLocale(0);
    fgDefaultPanicHandler = 0;
    fgUserPanicHandler = 0;
PeiYong Zhang's avatar
PeiYong Zhang committed

    // de-allocate default memory manager
    if (fgMemMgrAdopted)
        delete fgMemoryManager;
    else
        fgMemMgrAdopted = true;

    // set memory manager to 0
Khaled Noaman's avatar
Khaled Noaman committed
    fgMemoryManager = 0;
PeiYong Zhang's avatar
PeiYong Zhang committed
    // And say we are no longer initialized
    gInitFlag = 0;
}


393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824


// ---------------------------------------------------------------------------
//  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_LIBWWW)
		na = new LibWWWNetAccessor();
	#elif defined (XERCES_USE_NETACCESSOR_CFURL)
		na = new MacOSURLAccessCF();
    #elif defined (XERCES_USE_NETACCESSOR_WINSOCK)
		na = new WinSockNetAccessor();
	#else
		#warning No NetAccessor is configured for this platform. Xerces will have no net access.
	#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;
    
    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);
	#else // XERCES_USE_MSGLOADER_INMEMORY
		ms = new InMemMsgLoader(msgDomain);
	#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;
	#elif defined (XERCES_USE_TRANSCODER_ICONV)
		tc = new IconvTransService;
	#elif defined (XERCES_USE_TRANSCODER_MACOSUNICODECONVERTER)
		tc = new MacOSUnicodeConverter;
	#elif defined (XERCES_USE_TRANSCODER_WINDOWS)
		tc = new Win32TransService;
	#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->open(fileName, false, memmgr);
}


FileHandle
XMLPlatformUtils::openFile(const XMLCh* const fileName, MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	return fgFileMgr->open(fileName, false, memmgr);
}


FileHandle
XMLPlatformUtils::openFileToWrite(const char* const fileName
                                  , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	return fgFileMgr->open(fileName, true, memmgr);
}


FileHandle
XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName
                                  , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

 	return fgFileMgr->open(fileName, true, memmgr);
}


FileHandle
XMLPlatformUtils::openStdInHandle(MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	return fgFileMgr->openStdIn(memmgr);
}


void
XMLPlatformUtils::closeFile(const FileHandle theFile
                            , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	fgFileMgr->close(theFile, memmgr);
}

void
XMLPlatformUtils::resetFile(FileHandle theFile
                            , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	fgFileMgr->reset(theFile, memmgr);
}


XMLFilePos
XMLPlatformUtils::curFilePos(const FileHandle theFile
                             , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	return fgFileMgr->curPos(theFile, memmgr);
}

XMLFilePos
XMLPlatformUtils::fileSize(const FileHandle theFile
                           , MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	return fgFileMgr->size(theFile, memmgr);
}


XMLSize_t
XMLPlatformUtils::readFileBuffer(   const FileHandle      theFile
                                 ,  const XMLSize_t		  toRead
                                 ,        XMLByte* const  toFill
                                 ,  MemoryManager* const  memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

    return fgFileMgr->read(theFile, toRead, toFill, memmgr);
}


void
XMLPlatformUtils::writeBufferToFile(   const   FileHandle   theFile
                                    ,  const XMLSize_t		toWrite
                                    ,  const XMLByte* const toFlush
                                    ,  MemoryManager* const memmgr)
{
    if (!fgFileMgr)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, memmgr);

	fgFileMgr->write(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);
}


// -----------------------------------------------------------------------
//  Miscellaneous synchronization methods
// -----------------------------------------------------------------------
XMLAtomicOpMgr* XMLPlatformUtils::makeAtomicOpMgr(MemoryManager* const memmgr)
{
	XMLAtomicOpMgr* mgr = NULL;
	
	#if XERCES_USE_ATOMICOPMGR_NOTHREAD
		mgr = new (memmgr) NoThreadAtomicOpMgr;
	#elif XERCES_USE_ATOMICOPMGR_POSIX
		mgr = new (memmgr) PosixAtomicOpMgr;
	#elif XERCES_USE_ATOMICOPMGR_MACOS
		mgr = new (memmgr) MacOSAtomicOpMgr;
	#elif XERCES_USE_ATOMICOPMGR_WINDOWS
		mgr = new (memmgr) WindowsAtomicOpMgr;
	#else
		#error No AtomicOp Manager configured for platform! You must configure it.
	#endif
	
	return mgr;
}


void* XMLPlatformUtils::compareAndSwap(void**            toFill
                                     , const void* const newValue
                                     , const void* const toCompare)
{
    if (!fgAtomicOpMgr)
		ThrowXML(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero);

	return fgAtomicOpMgr->compareAndSwap(toFill, newValue, toCompare);
}


int XMLPlatformUtils::atomicIncrement(int &location)
{
    if (!fgAtomicOpMgr)
		ThrowXML(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero);

	return fgAtomicOpMgr->increment(location);
}


int XMLPlatformUtils::atomicDecrement(int &location)
{
    if (!fgAtomicOpMgr)
		ThrowXML(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero);

	return fgAtomicOpMgr->decrement(location);
}




PeiYong Zhang's avatar
PeiYong Zhang committed
// ---------------------------------------------------------------------------
//  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) {
PeiYong Zhang's avatar
PeiYong Zhang committed

    //Make sure initialize has been called
    if (gInitFlag == 0) {
        return;
    }

    if (state) {

Tinny Ng's avatar
Tinny Ng committed
        if (!XMLChar1_0::isNELRecognized()) {
            XMLChar1_0::enableNELWS();
PeiYong Zhang's avatar
PeiYong Zhang committed
        }
    }
    else {

Tinny Ng's avatar
Tinny Ng committed
        if (XMLChar1_0::isNELRecognized()) {
            ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::NEL_RepeatedCalls, manager);
PeiYong Zhang's avatar
PeiYong Zhang committed
        }
    }
}


bool XMLPlatformUtils::isNELRecognized() {

Tinny Ng's avatar
Tinny Ng committed
    return XMLChar1_0::isNELRecognized();
PeiYong Zhang's avatar
PeiYong Zhang committed
}

// ---------------------------------------------------------------------------
//  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;
    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);
    int    srcLen = XMLString::stringLen(srcPtr);
    ArrayJanitor<XMLCh>   janName(srcPtr, manager);   
    XMLCh* tarPtr = path;

    while (*srcPtr)