MacOSPlatformUtils.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:47k
- /*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 1999-2000 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation, and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.ibm.com . For more information
- * on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- /*
- * $Id: MacOSPlatformUtils.cpp,v 1.18 2003/05/21 02:43:07 jberry Exp $
- */
- // ---------------------------------------------------------------------------
- // Includes
- // ---------------------------------------------------------------------------
- #include <cstring>
- #include <cstdlib>
- #include <cctype>
- #include <cstdio>
- #include <memory>
- #include <algorithm>
- #if defined(__APPLE__)
- // Include from Frameworks Headers under ProjectBuilder
- #include <Carbon/Carbon.h>
- #else
- // Classic include styles
- #include <Files.h>
- #include <Gestalt.h>
- #include <TextUtils.h>
- #include <TextEncodingConverter.h>
- #include <Multiprocessing.h>
- #include <DriverSynchronization.h>
- #include <DriverServices.h>
- #include <CFString.h>
- #include <URLAccess.h>
- #endif
- #include <xercesc/util/XercesDefs.hpp>
- #include <xercesc/util/Janitor.hpp>
- #include <xercesc/util/PlatformUtils.hpp>
- #include <xercesc/util/RuntimeException.hpp>
- #include <xercesc/util/XMLUniDefs.hpp>
- #include <xercesc/util/XMLUni.hpp>
- #include <xercesc/util/XMLString.hpp>
- #include <xercesc/util/Platforms/MacOS/MacOSPlatformUtils.hpp>
- #include <xercesc/util/Platforms/MacOS/MacCarbonFile.hpp>
- #include <xercesc/util/Platforms/MacOS/MacPosixFile.hpp>
- #include <xercesc/util/PanicHandler.hpp>
- #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
- #include <xercesc/util/MsgLoaders/InMemory/InMemMsgLoader.hpp>
- #endif
- #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
- #include <xercesc/util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.hpp>
- #endif
- // Make up our minds about which netaccessor we'll use
- #if (defined(XML_USE_NETACCESSOR_URLACCESSCF) || (defined(XML_USE_NETACCESSOR_NATIVE) && TARGET_API_MAC_CARBON))
- #define USE_URLACCESSCF
- #elif (defined(XML_USE_NETACCESSOR_URLACCESS) || (defined(XML_USE_NETACCESSOR_NATIVE) && !TARGET_API_MAC_CARBON))
- #define USE_URLACCESS
- #endif
- #if defined(USE_URLACCESSCF)
- #include <xercesc/util/NetAccessors/MacOSURLAccessCF/MacOSURLAccessCF.hpp>
- #elif defined(USE_URLACCESS)
- #include <xercesc/util/NetAccessors/MacOSURLAccess/MacOSURLAccess.hpp>
- #endif
- XERCES_CPP_NAMESPACE_BEGIN
- //----------------------------------------------------------------------------
- // Function Prototypes
- //----------------------------------------------------------------------------
- XMLCh* ConvertColonToSlash(XMLCh* p, std::size_t charCount);
- XMLCh* ConvertSlashToColon(XMLCh* p, std::size_t charCount);
- char* ConvertSlashToColon(char* p, std::size_t charCount);
- XMLCh* XMLCreateFullPathFromFSRef_X(const FSRef& startingRef, MemoryManager* const manager);
- XMLCh* XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef, MemoryManager* const manager);
- XMLCh* XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec,
- MemoryManager* const manager);
- bool XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager);
- bool XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager);
- bool XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec, MemoryManager* const manager);
- //----------------------------------------------------------------------------
- // Local Data
- //
- // gFileSystemCompatible
- // This flag indicates whether the file system APIs meet our minimum
- // requirements.
- //
- // gHasFSSpecAPIs
- // True if the FSSpecAPIs are available. These are required.
- //
- // gHasF2TBAPIs
- // True if the FS supports 2 terrabyte calls. These are required for
- // use under Carbon.
- //
- // gHasHFSPlusAPIs
- // True if the FS supports HFSPlus APIs. If this is true, then the
- // new Fork calls are used, and all file name and path handling
- // uses long unicode names. Note that once a file is opened with
- // the fork calls, only fork calls may be used to access it.
- //
- // gHasFSPathAPIs
- // True if the FS supports path creation APIs FSPathMakeRef and
- // FSRefMakePath.
- //
- // gPathAPIsUsePosixPaths
- // True if the path creation APIs FSPathMakeRef and FSRefMakePath
- // use posix, rather than HFS, style paths. If so, these routines
- // are used to support path creation and interpretation.
- //
- // gHasMPAPIs
- // True if the Multiprocessing APIs are available.
- //
- // gUsePosixFiles
- // True if we're using XMLMacPosixFile rather than XMLMacCarbonFile.
- //----------------------------------------------------------------------------
- bool gFileSystemCompatible = false;
- bool gHasFSSpecAPIs = false;
- bool gHasFS2TBAPIs = false;
- bool gHasHFSPlusAPIs = false;
- bool gHasFSPathAPIs = false;
- bool gPathAPIsUsePosixPaths = false;
- bool gHasMPAPIs = false;
- bool gUsePosixFiles = false;
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: The panic method
- // ---------------------------------------------------------------------------
- void
- XMLPlatformUtils::panic(const PanicHandler::PanicReasons reason)
- {
- if (fgUserPanicHandler)
- fgUserPanicHandler->panic(reason);
- else
- fgDefaultPanicHandler->panic(reason);
- }
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: File Methods
- // ---------------------------------------------------------------------------
- unsigned int
- XMLPlatformUtils::curFilePos(const FileHandle theFile)
- {
- return reinterpret_cast<XMLMacAbstractFile*>(theFile)->currPos();
- }
- void
- XMLPlatformUtils::closeFile(const FileHandle theFile)
- {
- reinterpret_cast<XMLMacAbstractFile*>(theFile)->close();
- }
- unsigned int
- XMLPlatformUtils::fileSize(const FileHandle theFile)
- {
- return reinterpret_cast<XMLMacAbstractFile*>(theFile)->size();
- }
- FileHandle
- XMLPlatformUtils::openFile(const char* const fileName)
- {
- // Check to make sure the file system is in a state where we can use it
- if (!gFileSystemCompatible)
- ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
- Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
-
- return (file->open(fileName, false)) ? file.release() : NULL;
- }
- FileHandle
- XMLPlatformUtils::openFile(const XMLCh* const fileName)
- {
- // Check to make sure the file system is in a state where we can use it
- if (!gFileSystemCompatible)
- ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
- Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
- return (file->open(fileName, false)) ? file.release() : NULL;
- }
- FileHandle
- XMLPlatformUtils::openFileToWrite(const char* const fileName)
- {
- // Check to make sure the file system is in a state where we can use it
- if (!gFileSystemCompatible)
- ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
- Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
- return (file->open(fileName, true)) ? file.release() : NULL;
- }
- FileHandle
- XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName)
- {
- // Check to make sure the file system is in a state where we can use it
- if (!gFileSystemCompatible)
- ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
- Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
- return (file->open(fileName, true)) ? file.release() : NULL;
- }
- FileHandle
- XMLPlatformUtils::openStdInHandle()
- {
- XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull};
- ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr);
- return NULL;
- }
- unsigned int
- XMLPlatformUtils::readFileBuffer( const FileHandle theFile
- , const unsigned int toRead
- , XMLByte* const toFill)
- {
- return reinterpret_cast<XMLMacAbstractFile*>(theFile)->read(toRead, toFill);
- }
- void
- XMLPlatformUtils::writeBufferToFile( const FileHandle theFile
- , const long toWrite
- , const XMLByte* const toFlush)
- {
- return reinterpret_cast<XMLMacAbstractFile*>(theFile)->write(toWrite, toFlush);
- }
- void
- XMLPlatformUtils::resetFile(FileHandle theFile)
- {
- reinterpret_cast<XMLMacAbstractFile*>(theFile)->reset();
- }
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: File system methods
- // ---------------------------------------------------------------------------
- XMLCh*
- XMLPlatformUtils::getFullPath(const XMLCh* const srcPath,
- MemoryManager* const manager)
- {
- XMLCh* path = NULL;
- if (gHasHFSPlusAPIs)
- {
- FSRef ref;
- if ( !XMLParsePathToFSRef(srcPath, ref, manager)
- || (path = XMLCreateFullPathFromFSRef(ref, manager)) == NULL
- )
- path = XMLString::replicate(srcPath, manager);
- }
- else
- {
- FSSpec spec;
- if ( !XMLParsePathToFSSpec(srcPath, spec, manager)
- || (path = XMLCreateFullPathFromFSSpec(spec, manager)) == NULL
- )
- path = XMLString::replicate(srcPath, manager);
- }
- return path;
- }
- bool
- XMLPlatformUtils::isRelative(const XMLCh* const toCheck)
- {
- return (toCheck[0] != L'/');
- }
- XMLCh* XMLPlatformUtils::getCurrentDirectory(MemoryManager* const manager)
- {
- // Get a newly allocated path to the current directory
- FSSpec spec;
- XMLCh* path =
- (noErr == FSMakeFSSpec(0, 0, NULL, &spec))
- ? XMLCreateFullPathFromFSSpec(spec, manager)
- : NULL;
-
- if (!path)
- ThrowXML(XMLPlatformUtilsException,
- XMLExcepts::File_CouldNotGetBasePathName);
-
- return path;
- }
- inline bool XMLPlatformUtils::isAnySlash(XMLCh c)
- {
- // We support only forward slash as a path delimiter
- return (chForwardSlash == c);
- }
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: Timing Methods
- // ---------------------------------------------------------------------------
- unsigned long
- XMLPlatformUtils::getCurrentMillis()
- {
- if ((void*)kUnresolvedCFragSymbolAddress != UpTime)
- {
- // Use Driver services routines, now in Carbon,
- // to get the elapsed milliseconds.
- AbsoluteTime time = UpTime();
- return AbsoluteToDuration(time);
- }
- else
- return TickCount() * 100 / 6;
- }
- // ---------------------------------------------------------------------------
- // Mutex methods
- //
- // There are a number of choices for multi-threading on Mac OS. Traditionally
- // there was the Thread Manager, which provided cooperative multitasking on
- // 68K and PPC platforms, and preemptive multitasking on 68K platforms only.
- // The primary threading model supported under Carbon is the Multiprocessing
- // library, which as of version 2.0 provides a nice set of primitives. Under
- // Mac OS X, the Multiprocessing library is a thin veneer over pthreads.
- //
- // For lack of any really universal solutions, I've implemented these mutexes
- // atop the Multiprocessing library. The critical regions employed here
- // support recursive behavior, which is required by Xerces.
- //
- // Please note that, despite this implementation, there may be other barriers
- // to using Xerces in a multithreaded environment. The memory allocator
- // under Mac OS 9, for instance, is not thread safe.
- // ---------------------------------------------------------------------------
- void*
- XMLPlatformUtils::makeMutex()
- {
- if (gHasMPAPIs)
- {
- MPCriticalRegionID criticalRegion = NULL;
- OSStatus status = MPCreateCriticalRegion(&criticalRegion);
- return (status == noErr) ? (void*)(criticalRegion) : NULL;
- }
- else
- return (void*)1;
- }
- void
- XMLPlatformUtils::closeMutex(void* const mtxHandle)
- {
- if (gHasMPAPIs)
- {
- MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
- OSStatus status = MPDeleteCriticalRegion(criticalRegion);
- status = noErr; // ignore any error and zap compiler warning
- }
- else
- ;
- }
- void
- XMLPlatformUtils::lockMutex(void* const mtxHandle)
- {
- if (gHasMPAPIs)
- {
- MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
- OSStatus status = MPEnterCriticalRegion(criticalRegion, kDurationForever);
- status = noErr; // ignore any error and zap compiler warning
- }
- else
- ;
- }
- void
- XMLPlatformUtils::unlockMutex(void* const mtxHandle)
- {
- if (gHasMPAPIs)
- {
- MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
- OSStatus status = MPExitCriticalRegion(criticalRegion);
- status = noErr; // ignore any error and zap compiler warning
- }
- else
- ;
- }
- // ---------------------------------------------------------------------------
- // Miscellaneous synchronization methods
- //
- // Atomic manipulation is implemented atop routines that were traditionally
- // part of DriverServices, but are now a part of Carbon.
- // ---------------------------------------------------------------------------
- void*
- XMLPlatformUtils::compareAndSwap( void** toFill
- , const void* const newValue
- , const void* const toCompare)
- {
- // Replace *toFill with newValue iff *toFill == toCompare,
- // returning previous value of *toFill
- Boolean success = CompareAndSwap(
- reinterpret_cast<UInt32>(toCompare),
- reinterpret_cast<UInt32>(newValue),
- reinterpret_cast<UInt32*>(toFill));
- return (success) ? const_cast<void*>(toCompare) : *toFill;
- }
- //
- // Atomic Increment and Decrement
- //
- // Apple's routines return the value as it was before the
- // operation, while these routines want to return it as it
- // is after. So we perform the translation before returning
- // the value.
- //
- int
- XMLPlatformUtils::atomicIncrement(int &location)
- {
- return IncrementAtomic(reinterpret_cast<long*>(&location)) + 1;
- }
- int
- XMLPlatformUtils::atomicDecrement(int &location)
- {
- return DecrementAtomic(reinterpret_cast<long*>(&location)) - 1;
- }
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: Private Static Methods
- // ---------------------------------------------------------------------------
- //
- // This method handles the MacOS basic init functions.
- //
- void
- XMLPlatformUtils::platformInit()
- {
- long value = 0;
- // Detect available functions
-
- // Look for file system services
- if (noErr == Gestalt(gestaltFSAttr, &value))
- {
- gHasFSSpecAPIs = (value & (1 << gestaltHasFSSpecCalls)) != 0;
- gHasFS2TBAPIs = (value & (1 << gestaltFSSupports2TBVols)) != 0;
- gHasHFSPlusAPIs = (value & (1 << gestaltHasHFSPlusAPIs)) != 0;
- #if TARGET_API_MAC_CARBON
- gHasFSPathAPIs = ((void*)kUnresolvedCFragSymbolAddress != FSPathMakeRef);
- #else
- gHasFSPathAPIs = false;
- #endif
- gPathAPIsUsePosixPaths = gHasFSPathAPIs
- && (value & (1 << gestaltFSUsesPOSIXPathsForConversion));
- }
- // We require FSSpecs at a minimum
- gFileSystemCompatible = gHasFSSpecAPIs;
- // Determine which file system to use (posix or carbon file access)
- // If we're using Metrowerks MSL, we surely don't want posix paths,
- // as MSL doesn't use them.
- #if __MSL__ && (__MSL__ < 0x08000 || _MSL_CARBON_FILE_APIS)
- gUsePosixFiles = false;
- #else
- gUsePosixFiles = noErr == Gestalt(gestaltSystemVersion, &value)
- && value >= 0x00001000
- ;
- #endif
- // Look for MP
- gHasMPAPIs = MPLibraryIsLoaded();
- }
- //
- // This method handles the MacOS basic termination functions.
- //
- void
- XMLPlatformUtils::platformTerm()
- {
- }
- // ---------------------------------------------------------------------------
- // XMLPlatformUtils: Private Static Methods
- // ---------------------------------------------------------------------------
- //
- // This method is called by the platform independent part of this class
- // during initialization. We have to create the type of net accessor that
- // we want to use. If none, then just return zero.
- //
- XMLNetAccessor*
- XMLPlatformUtils::makeNetAccessor()
- {
- // The selection of NetAcessor is made through
- // the following preprocessor defines:
- //
- // XML_USE_NETACCESSOR_URLACCESS -- Use netaccessor based on URLAccess
- // XML_USE_NETACCESSOR_URLACCESSCF -- Use netaccessor based on CFURLAccess (CoreFoundation based)
- // XML_USE_NETACCESSOR_NATIVE -- In absence of above selections, chooses URLACCESSCF
- // if targetting Carbon, and URLAccess otherwise
- //
- // These choices are resolved at the ^^^top^^^ of this file.
- #if (defined(USE_URLACCESSCF))
- // Use the URLAccess code that relies only on CoreFoundation
- return new MacOSURLAccessCF;
- #elif (defined(USE_URLACCESS))
- // Only try to use URLAccess if it's actually available
- if (URLAccessAvailable())
- return new MacOSURLAccess;
- #endif
- // No netaccessor available--we can live with it, but you won't
- // get net access.
- return 0;
- }
- //
- // 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)
- {
- #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
- return new InMemMsgLoader(msgDomain);
- #else
- #error You must provide a message loader
- return 0;
- #endif
- }
- //
- // 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()
- {
- #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
- if (MacOSUnicodeConverter::IsMacOSUnicodeConverterSupported())
- return new MacOSUnicodeConverter;
- #else
- #error You must provide a transcoding service implementation
- #endif
- // If we got here it's because we didn't detect the Mac OS
- // Unicode Converter or Text Encoding Converter routines
- // that we require to function properly. Xerces will not
- // survive this condition.
- return NULL;
- }
- // ---------------------------------------------------------------------------
- // Utility Functions
- // ---------------------------------------------------------------------------
- XMLCh*
- CopyUniCharsToXMLChs(const UniChar* src, XMLCh* dst, std::size_t charCount, std::size_t maxChars)
- {
- // Ensure we don't step on anybody's toes
- std::size_t cnt = std::min(charCount, maxChars);
-
- // Copy the characters. UniChar is unsigned, so we shouldn't have
- // any sign extension problems.
- // To allow copy within a identical range, we copy backwards,
- // since XMLCh (may be) larger than UniChar.
- dst += cnt;
- src += cnt;
- for (; cnt > 0; --cnt)
- *--dst = *--src;
-
- return dst;
- }
- UniChar*
- CopyXMLChsToUniChars(const XMLCh* src, UniChar* dst, std::size_t charCount, std::size_t maxChars)
- {
- UniChar* dstBegin = dst;
-
- // Ensure we don't step on anybody's toes
- std::size_t cnt = std::min(charCount, maxChars);
-
- // Copy the characters. XMLCh's will be truncated on copy to UniChar's.
- // To allow copy within a identical range, we copy forwards,
- // since XMLCh (may be) larger than UniChar.
- for (; cnt > 0; --cnt)
- *dst++ = *src++;
-
- return dstBegin;
- }
- XMLCh*
- ConvertColonToSlash(XMLCh* p, std::size_t charCount)
- {
- XMLCh* start = p;
- for (; charCount > 0; --charCount)
- {
- XMLCh c = *p;
- if (c == ':')
- *p++ = '/';
- else
- p++;
- }
- return start;
- }
- XMLCh*
- ConvertSlashToColon(XMLCh* p, std::size_t charCount)
- {
- XMLCh* start = p;
- for (; charCount > 0; --charCount)
- {
- XMLCh c = *p;
- if (c == '/')
- *p++ = ':';
- else
- p++;
- }
- return start;
- }
- char*
- ConvertSlashToColon(char* p, std::size_t charCount)
- {
- char* start = p;
- for (; charCount > 0; --charCount)
- {
- char c = *p;
- if (c == '/')
- *p++ = ':';
- else
- p++;
- }
- return start;
- }
- // Factory method to make an appropriate subclass of XMLMacAbstractFile
- // for our use
- XMLMacAbstractFile*
- XMLMakeMacFile(void)
- {
- XMLMacAbstractFile* result = NULL;
-
- if (gUsePosixFiles)
- result = new XMLMacPosixFile;
- else
- result = new XMLMacCarbonFile;
-
- return result;
- }
- bool
- XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
- {
- bool result;
-
- // If FSPathMakeRef is available, we use it to parse the
- // path: this gives us "standard" path support under MacOS X.
- // Without this, our paths in that environment would always
- // have a volume name at their root...which would look
- // "normal" to Mac users, but not normal to unix users. Since
- // we're making "unix" paths, we'll stick with the unix
- // style paths. This also allows us to easilly take paths
- // off the command line.
- //
- // FSPathMakeRef is available on Mac OS X and in CarbonLib 1.1
- // and greater. But on classic under CarbonLib, it expects paths
- // to contain ':' separators, for which we're not prepared. Since
- // this isn't a case where we need to use it, we drop back to the
- // classic case for this.
-
- if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths)
- result = XMLParsePathToFSRef_X(pathName, ref, manager);
- else
- result = XMLParsePathToFSRef_Classic(pathName, ref, manager);
-
- return result;
- }
- bool
- XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
- {
- // Parse Path to FSRef using FSPathMakeRef as available under
- // Mac OS X and CarbonLib 1.1 and greater.
-
- OSStatus err = noErr;
- std::size_t pathLen = XMLString::stringLen(pathName);
- // Transcode XMLCh into UniChar
- UniChar uniBuf[kMaxMacStaticPathChars];
- CopyXMLChsToUniChars(pathName, uniBuf, pathLen, kMaxMacStaticPathChars);
-
- // Transcode Unicode to UTF-8
- char utf8Buf[kMaxMacStaticPathChars];
- pathLen = TranscodeUniCharsToUTF8(uniBuf, utf8Buf, pathLen, kMaxMacStaticPathChars-1);
-
- // Terminate the path
- char* p = utf8Buf;
- p[pathLen++] = ' ';
-
- // If it's a relative path, pre-pend the current directory to the path.
- // FSPathMakeRef doesn't deal with relativity on the front of the path
- if (*p != '/')
- {
- // Right justify the user path to make room for the pre-pended path
- std::memmove(p + kMaxMacStaticPathChars - pathLen, p, pathLen);
-
- // Get the current directory
- FSSpec spec;
- if (err == noErr)
- err = FSMakeFSSpec(0, 0, NULL, &spec);
- if (err == noErr)
- err = FSpMakeFSRef(&spec, &ref);
-
- // Get pathname to the current directory
- if (err == noErr)
- err = FSRefMakePath(&ref, reinterpret_cast<UInt8*>(p), kMaxMacStaticPathChars - pathLen - 1); // leave room for one '/'
- std::size_t prefixLen = std::strlen(p);
-
- // Now munge the two paths back together
- if (err == noErr)
- {
- p[prefixLen++] = '/';
- std::memmove(p + prefixLen, p + kMaxMacStaticPathChars - pathLen, pathLen);
- }
-
- // We now have a path from an absolute starting point
- }
-
- // Let the OS discover the location
- Boolean isDirectory = false;
- if (err == noErr)
- err = FSPathMakeRef(reinterpret_cast<UInt8*>(p), &ref, &isDirectory);
-
- // Return true on success
- return (err == noErr);
- }
- bool
- XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
- {
- // Parse Path to FSRef by stepping manually through path components.
-
- // Path's parsed in this way must always begin with a volume name.
- // This assumption would fail for standard unix paths under Mac OS X,
- // so for those cases we use the routine XMLParsePathToFSRef_Carbon
- // above.
-
- const XMLCh* p = pathName;
- const XMLCh* pEnd;
- std::size_t segLen;
-
- const std::size_t kXMLBufCount = 256;
- XMLCh xmlBuf[kXMLBufCount];
- OSErr err = noErr;
- if (*p == L'/')
- {
- // Absolute name: grab the first component as volume name
- // Find the end of the path segment
- for (pEnd = ++p; *pEnd && *pEnd != L'/'; ++pEnd) ;
- segLen = pEnd - p;
- // Try to find a volume that matches this name
- for (ItemCount volIndex = 1; err == noErr; ++volIndex)
- {
- HFSUniStr255 hfsStr;
- hfsStr.length = 0;
- // Get the volume name
- err = FSGetVolumeInfo(
- 0,
- volIndex,
- static_cast<FSVolumeRefNum*>(NULL),
- 0,
- static_cast<FSVolumeInfo*>(NULL),
- &hfsStr,
- &ref
- );
- // Compare against our path segment
- if (err == noErr && segLen == hfsStr.length)
- {
- // Case-insensitive compare
- if (XMLString::compareNIString(
- ConvertSlashToColon(
- CopyUniCharsToXMLChs(hfsStr.unicode, xmlBuf, segLen, kXMLBufCount),
- segLen),
- p, segLen) == 0)
- break; // we found our volume
- }
- }
- p = pEnd;
- }
- else
- {
- // Relative name, so get the default directory as parent ref
- FSSpec spec;
- err = FSMakeFSSpec(0, 0, NULL, &spec);
- if (err == noErr)
- err = FSpMakeFSRef(&spec, &ref);
- }
- // ref now refers to the a parent directory: parse the rest of the path
- while (err == noErr && *p)
- {
- switch (*p)
- {
- case L'/': // Just skip any number of path separators
- ++p;
- break;
- case L'.': // Potentially "current directory" or "parent directory"
- if (p[1] == L'/' || p[1] == 0) // "current directory"
- {
- ++p;
- break;
- }
- else if (p[1] == L'.' && (p[2] == L'/' || p[2] == 0)) // "parent directory"
- {
- p += 2; // Get the parent of our parent
- FSCatalogInfo catalogInfo;
- err = FSGetCatalogInfo(
- &ref,
- kFSCatInfoParentDirID,
- &catalogInfo,
- static_cast<HFSUniStr255*>(NULL),
- static_cast<FSSpec*>(NULL),
- &ref
- );
- // Check that we didn't go too far
- if (err != noErr || catalogInfo.parentDirID == fsRtParID)
- return false;
- break;
- }
- else // some other sequence of periods...fall through and treat as segment
- ;
- default:
- // Find the end of the path segment
- for (pEnd = p; *pEnd && *pEnd != L'/'; ++pEnd) ;
- segLen = pEnd - p;
-
- // pEnd now points either to '/' or NUL
- // Create a new ref using this path segment
- err = FSMakeFSRefUnicode(
- &ref,
- segLen,
- ConvertColonToSlash(
- CopyXMLChsToUniChars(p, reinterpret_cast<UniChar*>(xmlBuf), segLen, kXMLBufCount),
- segLen),
- kTextEncodingUnknown,
- &ref
- );
- p = pEnd;
- break;
- }
- }
- return err == noErr;
- }
- bool
- XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec,
- MemoryManager* const manager)
- {
- // Parse Path to an FSSpec
- // If we've got HFS+ APIs, do this in terms of refs so that
- // we can grandfather in the use of FSPathMakeRef under Mac OS X
- // and CarbonLib 1.1. Otherwise, do it the hard way.
-
- bool result = false;
-
- if (gHasHFSPlusAPIs)
- {
- // Parse to a ref
- FSRef ref;
- result = XMLParsePathToFSRef(pathName, ref, manager);
-
- // Down convert to a spec
- if (result)
- result = (noErr == FSGetCatalogInfo(&ref,
- kFSCatInfoNone,
- static_cast<FSCatalogInfo*>(NULL), // catalogInfo
- static_cast<HFSUniStr255*>(NULL), // outName
- &spec,
- static_cast<FSRef*>(NULL) // parentRef
- ));
- }
- else
- result = XMLParsePathToFSSpec_Classic(pathName, spec, manager);
-
- // Return true on success
- return result;
- }
- bool
- XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec,
- MemoryManager* const manager)
- {
- // Manually parse the path using FSSpec APIs.
-
- // Transcode the path into ascii
- const char* p = XMLString::transcode(pathName, manager);
- ArrayJanitor<const char> janPath(p, manager);
- const char* pEnd;
- std::size_t segLen;
- OSStatus err = noErr;
- Str255 name; // Must be long enough for a partial pathname consisting of two segments (64 bytes)
- if (*p == '/')
- {
- // Absolute name: grab the first component as volume name
- // Find the end of the path segment
- for (pEnd = ++p; *pEnd && *pEnd != '/'; ++pEnd) ;
- segLen = pEnd - p;
- // Try to find a volume that matches this name
- for (ItemCount volIndex = 1; err == noErr; ++volIndex)
- {
- FSVolumeRefNum volRefNum;
- if (gHasFS2TBAPIs)
- {
- XVolumeParam xVolParam;
- name[0] = 0;
- xVolParam.ioNamePtr = name;
- xVolParam.ioVRefNum = 0;
- xVolParam.ioXVersion = 0;
- xVolParam.ioVolIndex = volIndex;
- err = PBXGetVolInfoSync(&xVolParam);
- volRefNum = xVolParam.ioVRefNum;
- }
- else
- {
- #if !TARGET_API_MAC_CARBON
- HParamBlockRec hfsParams;
- name[0] = 0;
- hfsParams.volumeParam.ioNamePtr = name;
- hfsParams.volumeParam.ioVRefNum = 0;
- hfsParams.volumeParam.ioVolIndex = volIndex;
- err = PBHGetVInfoSync(&hfsParams);
- volRefNum = hfsParams.volumeParam.ioVRefNum;
- #else
- err = nsvErr;
- #endif
- }
- // Compare against our path segment
- if (err == noErr && segLen == StrLength(name))
- {
- // Case-insensitive compare
- if (XMLString::compareNIString(
- ConvertSlashToColon(reinterpret_cast<char*>(&name[1]), segLen),
- p, segLen) == 0)
- {
- // we found our volume: fill in the spec
- err = FSMakeFSSpec(volRefNum, fsRtDirID, NULL, &spec);
- break;
- }
- }
- }
- p = pEnd;
- }
- else
- {
- // Relative name, so get the default directory as parent spec
- err = FSMakeFSSpec(0, 0, NULL, &spec);
- }
- // We now have a parent directory in the spec.
- while (err == noErr && *p)
- {
- switch (*p)
- {
- case '/': // Just skip any number of path separators
- ++p;
- break;
- case L'.': // Potentially "current directory" or "parent directory"
- if (p[1] == '/' || p[1] == 0) // "current directory"
- {
- ++p;
- break;
- }
- else if (p[1] == '.' && (p[2] == '/' || p[2] == 0)) // "parent directory"
- {
- p += 2; // Get the parent of our parent
- CInfoPBRec catInfo;
- catInfo.dirInfo.ioNamePtr = NULL;
- catInfo.dirInfo.ioVRefNum = spec.vRefNum;
- catInfo.dirInfo.ioFDirIndex = -1;
- catInfo.dirInfo.ioDrDirID = spec.parID;
- err = PBGetCatInfoSync(&catInfo);
- // Check that we didn't go too far
- if (err != noErr || catInfo.dirInfo.ioDrParID == fsRtParID)
- return false;
- // Update our spec
- if (err == noErr)
- err = FSMakeFSSpec(spec.vRefNum, catInfo.dirInfo.ioDrDirID, NULL, &spec);
- break;
- }
- else // some other sequence of periods...fall through and treat as segment
- ;
- default:
- {
- // Find the end of the path segment
- for (pEnd = p; *pEnd && *pEnd != '/'; ++pEnd) ;
- segLen = pEnd - p;
- // Check for name length overflow
- if (segLen > 31)
- return false;
- // Make a partial pathname from our current spec to the new object
- unsigned char* partial = &name[1];
- *partial++ = ':'; // Partial leads with :
- const unsigned char* specName = spec.name; // Copy in spec name
- for (int specCnt = *specName++; specCnt > 0; --specCnt)
- *partial++ = *specName++;
- *partial++ = ':'; // Separator
- while (p != pEnd) // Copy in new element
- {
- if (*p == ':') // Convert : to /
- {
- *partial++ = '/';
- p++;
- }
- else
- *partial++ = *p++;
- }
-
- name[0] = partial - &name[1]; // Set the name length
- // Update the spec
- err = FSMakeFSSpec(spec.vRefNum, spec.parID, name, &spec);
- }
- break;
- }
- }
- return err == noErr;
- }
- XMLCh*
- XMLCreateFullPathFromFSRef(const FSRef& startingRef,
- MemoryManager* const manager)
- {
- XMLCh* result = NULL;
-
- // If FSRefMakePath is available, we use it to create the
- // path: this gives us "standard" path support under MacOS X.
- // Without this, our paths in that environment would always
- // have a volume name at their root...which would look
- // "normal" to Mac users, but not normal to unix users. Since
- // we're making "unix" paths, we'll stick with the unix
- // style paths. This also allows us to easilly take paths
- // off the command line.
- //
- // FSRefMakePath is available on Mac OS X and in CarbonLib 1.1
- // and greater. But we use it only on X since on Classic it
- // makes paths with ':' separators, which really confuses us!
-
- if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths)
- result = XMLCreateFullPathFromFSRef_X(startingRef, manager);
- else
- result = XMLCreateFullPathFromFSRef_Classic(startingRef, manager);
-
- return result;
- }
- XMLCh*
- XMLCreateFullPathFromFSRef_X(const FSRef& startingRef,
- MemoryManager* const manager)
- {
- // Create the path using FSRefMakePath as available on Mac OS X
- // and under CarbonLib 1.1 and greater.
- OSStatus err = noErr;
-
- // Make the path in utf8 form
- char utf8Buf[kMaxMacStaticPathChars];
- utf8Buf[0] = ' ';
-
- if (err == noErr)
- err = FSRefMakePath(&startingRef, reinterpret_cast<UInt8*>(utf8Buf), kMaxMacStaticPathChars);
-
- // Bail if path conversion failed
- if (err != noErr)
- return NULL;
-
- // Transcode into UniChars
- UniChar uniBuf[kMaxMacStaticPathChars];
- std::size_t pathLen = TranscodeUTF8ToUniChars(utf8Buf, uniBuf, kMaxMacStaticPathChars-1);
- uniBuf[pathLen++] = 0;
-
- // Transcode into a dynamically allocated buffer of XMLChs
- ArrayJanitor<XMLCh> result((XMLCh*) manager->allocate(pathLen * sizeof(XMLCh))/*new XMLCh[pathLen]*/,
- manager);
- if (result.get() != NULL)
- CopyUniCharsToXMLChs(uniBuf, result.get(), pathLen, pathLen);
-
- return result.release();
- }
- XMLCh*
- XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef,
- MemoryManager* const manager)
- {
- // Manually create the path using FSRef APIs.
- OSStatus err = noErr;
- FSCatalogInfo catalogInfo;
- HFSUniStr255 name;
- FSRef ref = startingRef;
- XMLCh buf[kMaxMacStaticPathChars];
- std::size_t bufPos = kMaxMacStaticPathChars;
- std::size_t bufCnt = 0;
- ArrayJanitor<XMLCh> result(NULL);
- std::size_t resultLen = 0;
- buf[--bufPos] = L' ';
- ++bufCnt;
- do
- {
- err = FSGetCatalogInfo(
- &ref,
- kFSCatInfoParentDirID,
- &catalogInfo,
- &name,
- static_cast<FSSpec*>(NULL),
- &ref
- );
-
- if (err == noErr)
- {
- // If there's not room in our static buffer for the new
- // name plus separator, dump it to the dynamic result buffer.
- if (bufPos < (std::size_t)name.length + 1)
- {
- ArrayJanitor<XMLCh> temp
- (
- (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh)) //new XMLCh[bufCnt + resultLen]
- , manager
- );
-
- // Copy in the static buffer
- std::memcpy(temp.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
-
- // Copy in the old buffer
- if (resultLen > 0)
- std::memcpy(temp.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
-
- result.reset(temp.release());
- resultLen += bufCnt;
-
- bufPos = kMaxMacStaticPathChars;
- bufCnt = 0;
- }
-
- // Prepend our new name and a '/'
- bufPos -= name.length;
- ConvertSlashToColon(
- CopyUniCharsToXMLChs(name.unicode, &buf[bufPos], name.length, name.length),
- name.length);
- buf[--bufPos] = L'/';
- bufCnt += (name.length + 1);
- }
- }
- while (err == noErr && catalogInfo.parentDirID != fsRtParID);
-
- // Composite existing buffer + any previous result buffer
- ArrayJanitor<XMLCh> final
- (
- (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh))//new XMLCh[bufCnt + resultLen]
- , manager
- );
-
- // Copy in the static buffer
- std::memcpy(final.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
-
- // Copy in the old buffer
- if (resultLen > 0)
- std::memcpy(final.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
-
- return final.release();
- }
- XMLCh*
- XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec,
- MemoryManager* const manager)
- {
- XMLCh* result = NULL;
-
- // If FSRefs are available, do this operation in terms of refs...this
- // allows us to grandfather in the use of FSPathMakeRef and FSRefMakePath
- // if possible.
- if (gHasHFSPlusAPIs)
- {
- OSStatus err = noErr;
- FSRef ref;
-
- // Up convert to FSRef
- if (err == noErr)
- err = FSpMakeFSRef(&startingSpec, &ref);
-
- // Create the path
- if (err == noErr)
- result = XMLCreateFullPathFromFSRef(ref, manager);
- }
- else
- {
- // Create using FSSpecs only
- result = XMLCreateFullPathFromFSSpec_Classic(startingSpec, manager);
- }
-
- return result;
- }
- XMLCh*
- XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec,
- MemoryManager* const manager)
- {
- // Manually create the path using FSSpec APIs.
- OSStatus err = noErr;
- FSSpec spec = startingSpec;
- char buf[kMaxMacStaticPathChars];
- std::size_t bufPos = kMaxMacStaticPathChars;
- std::size_t bufCnt = 0;
- ArrayJanitor<char> result(NULL);
- std::size_t resultLen = 0;
- buf[--bufPos] = ' ';
- ++bufCnt;
- short index = 0;
- do
- {
- CInfoPBRec catInfo;
- catInfo.dirInfo.ioNamePtr = spec.name;
- catInfo.dirInfo.ioVRefNum = spec.vRefNum;
- catInfo.dirInfo.ioFDirIndex = index;
- catInfo.dirInfo.ioDrDirID = spec.parID;
- err = PBGetCatInfoSync(&catInfo);
-
- if (err == noErr)
- {
- std::size_t nameLen = StrLength(spec.name);
-
- // If there's not room in our static buffer for the new
- // name plus separator, dump it to the dynamic result buffer.
- if (bufPos < nameLen + 1)
- {
- ArrayJanitor<char> temp
- (
- (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen]
- , manager
- );
-
- // Copy in the static buffer
- std::memcpy(temp.get(), &buf[bufPos], bufCnt);
-
- // Copy in the old buffer
- if (resultLen > 0)
- std::memcpy(temp.get() + bufCnt, result.get(), resultLen);
-
- result.reset(temp.release());
- resultLen += bufCnt;
-
- bufPos = kMaxMacStaticPathChars;
- bufCnt = 0;
- }
-
- // Prepend our new name and a '/'
- bufPos -= nameLen;
- ConvertSlashToColon((char*)std::memcpy(&buf[bufPos], &spec.name[1], nameLen), nameLen);
- buf[--bufPos] = '/';
- bufCnt += (nameLen + 1);
-
- // From here on out, ignore the input file name
- index = -1;
-
- // Move up to the parent
- spec.parID = catInfo.dirInfo.ioDrParID;
- }
- }
- while (err == noErr && spec.parID != fsRtParID);
-
- // Composite existing buffer with any previous result buffer
- ArrayJanitor<char> final
- (
- (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen]
- , manager
- );
-
- // Copy in the static buffer
- std::memcpy(final.get(), &buf[bufPos], bufCnt);
-
- // Copy in the old buffer
- if (resultLen > 0)
- std::memcpy(final.get() + bufCnt, result.get(), resultLen);
- // Cleanup and transcode to unicode
- return XMLString::transcode(final.get(), manager);
- }
- std::size_t
- TranscodeUniCharsToUTF8(const UniChar* src, char* dst, std::size_t srcCnt, std::size_t maxChars)
- {
- std::size_t result = 0;
-
- // Use the text encoding converter to perform the format conversion.
- // Note that this is slightly heavyweight, but we're not in a performance
- // sensitive code-path.
- OSStatus err = noErr;
- TECObjectRef tec = 0;
- ByteCount bytesConsumed = 0;
- ByteCount bytesProduced = 0;
- TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
- kTextEncodingDefaultVariant,
- kUnicode16BitFormat);
- TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
- kTextEncodingDefaultVariant,
- kUnicodeUTF8Format);
- if (err == noErr)
- err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
- if (err == noErr)
- err = TECConvertText(tec,
- (ConstTextPtr) src,
- srcCnt * sizeof(UniChar), // inputBufferLength
- &bytesConsumed, // actualInputLength
- (TextPtr) dst, // outputBuffer
- maxChars * sizeof(char), // outputBufferLength
- &bytesProduced); // actualOutputLength
- TECDisposeConverter(tec);
- result = bytesProduced;
-
- // Return number of chars in dst
- return result;
- }
- std::size_t
- TranscodeUTF8ToUniChars(const char* src, UniChar* dst, std::size_t maxChars)
- {
- std::size_t result = 0;
-
- // Use the text encoding converter to perform the format conversion.
- // Note that this is slightly heavyweight, but we're not in a performance
- // sensitive code-path.
- OSStatus err = noErr;
- TECObjectRef tec = 0;
- ByteCount bytesConsumed = 0;
- ByteCount bytesProduced = 0;
- TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
- kTextEncodingDefaultVariant,
- kUnicodeUTF8Format);
- TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
- kTextEncodingDefaultVariant,
- kUnicode16BitFormat);
- if (err == noErr)
- err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
- if (err == noErr)
- err = TECConvertText(tec,
- (ConstTextPtr) src,
- std::strlen(src), // inputBufferLength
- &bytesConsumed, // actualInputLength
- (TextPtr) dst, // outputBuffer
- maxChars * sizeof(UniChar), // outputBufferLength
- &bytesProduced); // actualOutputLength
- TECDisposeConverter(tec);
- result = bytesProduced / sizeof(UniChar);
-
- // Return number of unicode characters in dst
- return result;
- }
- #include <xercesc/util/LogicalPath.c>
- XERCES_CPP_NAMESPACE_END