MacOSPlatformUtils.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:50k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: MacOSPlatformUtils.cpp,v 1.23 2001/10/23 04:50:06 jberry Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. // Note:
  61. //   Xerces is not officially supported on Macintosh. This file was sent
  62. //   in by one of the Macintosh users and is included in the distribution
  63. //   just for convenience. Please send any defects / modification
  64. //   reports to xml4c@us.ibm.com
  65. // ---------------------------------------------------------------------------
  66. // ---------------------------------------------------------------------------
  67. //  Includes
  68. // ---------------------------------------------------------------------------
  69. #include <util/Janitor.hpp>
  70. #include <util/PlatformUtils.hpp>
  71. #include <util/RuntimeException.hpp>
  72. #include <util/XMLUniDefs.hpp>
  73. #include <util/XMLUni.hpp>
  74. #include <util/XMLString.hpp>
  75. #include <util/Platforms/MacOS/MacOSDefs.hpp>
  76. #include <util/Platforms/MacOS/MacOSPlatformUtils.hpp>
  77. #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
  78.    #include <util/MsgLoaders/InMemory/InMemMsgLoader.hpp>
  79. #endif
  80. #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
  81.    #include <util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.hpp>
  82. #endif
  83. #if (defined(XML_USE_NETACCESSOR_URLACCESS) || defined(XML_USE_NETACCESSOR_NATIVE))
  84.    #include <util/NetAccessors/MacOSURLAccess/MacOSURLAccess.hpp>
  85. #endif
  86. #include <cstring>
  87. #include <cstdlib>
  88. #include <cctype>
  89. #include <cstdio>
  90. #include <memory>
  91. #include <algorithm>
  92. #if defined(XML_MACOSX)
  93.     // Include from Frameworks Headers under ProjectBuilder
  94.     #include <Carbon/Carbon.h>
  95. #else
  96.     // Classic include styles
  97.     #include <Files.h>
  98.     #include <Gestalt.h>
  99.     #include <TextUtils.h>
  100.     #include <TextEncodingConverter.h>
  101.     #include <Multiprocessing.h>
  102.     #include <DriverSynchronization.h>
  103.     #include <DriverServices.h>
  104.     #include <CFString.h>
  105.     #include <URLAccess.h>
  106. #endif
  107. //----------------------------------------------------------------------------
  108. // Local Constants
  109. //----------------------------------------------------------------------------
  110. const std::size_t kMaxStaticPathChars = 512; // Size of our statically allocated path buffers
  111. //----------------------------------------------------------------------------
  112. // Function Prototypes
  113. //----------------------------------------------------------------------------
  114. XMLCh* ConvertColonToSlash(XMLCh* p, std::size_t charCount);
  115. XMLCh* ConvertSlashToColon(XMLCh* p, std::size_t charCount);
  116. char* ConvertSlashToColon(char* p, std::size_t charCount);
  117. XMLCh* XMLCreateFullPathFromFSRef_X(const FSRef& startingRef);
  118. XMLCh* XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef);
  119. XMLCh* XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec);
  120. bool XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref);
  121. bool XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref);
  122. bool XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec);
  123. std::size_t TranscodeUniCharsToUTF8(UniChar* src, char* dst, std::size_t srcCnt, std::size_t maxChars);
  124. std::size_t TranscodeUTF8ToUniChars(char* src, UniChar* dst, std::size_t maxChars);
  125. //----------------------------------------------------------------------------
  126. //  Local Data
  127. //
  128. // gIsClassic
  129. //  True if we're in the "classic" environment, either under the blue blox
  130. //  or on a real classic OS.
  131. //
  132. //  gFileSystemCompatible
  133. //   This flag indicates whether the file system APIs meet our minimum
  134. //   requirements.
  135. //
  136. // gHasFSSpecAPIs
  137. //   True if the FSSpecAPIs are available. These are required.
  138. //
  139. // gHasF2TBAPIs
  140. //   True if the FS supports 2 terrabyte calls. These are required for
  141. //   use under Carbon.
  142. //
  143. // gHasHFSPlusAPIs
  144. //   True if the FS supports HFSPlus APIs. If this is true, then the
  145. //   new Fork calls are used, and all file name and path handling
  146. //   uses long unicode names. Note that once a file is opened with
  147. //   the fork calls, only fork calls may be used to access it.
  148. //
  149. // gHasFSPathAPIs
  150. //   True if the FS supports posix path creation APIs FSPathMakeRef and
  151. //  FSRefMakePath. If so, these routines are used to support path creation
  152. //  and  interpretation.
  153. //
  154. // gHasMPAPIs
  155. //  True if the Multiprocessing APIs are available.
  156. //----------------------------------------------------------------------------
  157. static bool gIsClassic = false;
  158. static bool gFileSystemCompatible = false;
  159. static bool gHasFSSpecAPIs = false;
  160. static bool gHasFS2TBAPIs = false;
  161. static bool gHasHFSPlusAPIs = false;
  162. static bool gHasFSPathAPIs = false;
  163. static bool gHasMPAPIs = false;
  164. //----------------------------------------------------------------------------
  165. // XMLMacFile methods
  166. //----------------------------------------------------------------------------
  167. unsigned int
  168. XMLMacFile::currPos()
  169. {
  170.     OSErr err = noErr;
  171.     unsigned int pos = 0;
  172.     
  173.     if (!mFileValid)
  174.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos);
  175.     
  176.     if (gHasHFSPlusAPIs)
  177.     {
  178.         SInt64 bigPos = 0;
  179.         err = FSGetForkPosition(mFileRefNum, &bigPos);
  180.         if (err == noErr)
  181.             pos = bigPos;
  182.     }
  183.     else
  184.     {
  185.         long longPos;
  186.         err = GetFPos(mFileRefNum, &longPos);
  187.         if (err == noErr)
  188.             pos = longPos;
  189.     }
  190.     
  191.     if (err != noErr)
  192.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos);
  193.     
  194.     return pos;
  195. }
  196. void
  197. XMLMacFile::close()
  198. {
  199.     OSErr err = noErr;
  200.     if (!mFileValid)
  201.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile);
  202.     
  203.     if (gHasHFSPlusAPIs)
  204.         err = FSCloseFork(mFileRefNum);
  205.     else
  206.         err = FSClose(mFileRefNum);
  207.     
  208.     mFileValid = false;
  209.     
  210.     if (err != noErr)
  211.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile);
  212. }
  213. unsigned int
  214. XMLMacFile::size()
  215. {
  216.     OSErr err = noErr;
  217.     unsigned int len = 0;
  218.     
  219.     if (!mFileValid)
  220.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize);
  221.     
  222.     if (gHasHFSPlusAPIs)
  223.     {
  224.         SInt64 bigLen = 0;
  225.         err = FSGetForkSize(mFileRefNum, &bigLen);
  226.         if (err == noErr)
  227.             len = bigLen;
  228.     }
  229.     else
  230.     {
  231.         long longLen;
  232.         err = GetEOF(mFileRefNum, &longLen);
  233.         if (err == noErr)
  234.             len = longLen;
  235.     }
  236.     
  237.     if (err != noErr)
  238.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize);
  239.     
  240.     return len;
  241. }
  242. void
  243. XMLMacFile::open(const XMLCh* const fileName)
  244. {
  245.     OSErr err = noErr;
  246.     
  247.     if (mFileValid)
  248.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile);
  249.     
  250.     if (gHasHFSPlusAPIs)
  251.     {
  252.         FSRef ref;
  253.         if (!XMLParsePathToFSRef(fileName, ref))
  254.             err = fnfErr;
  255.         
  256.         HFSUniStr255 forkName;
  257.         if (err == noErr)
  258.             err = FSGetDataForkName(&forkName);
  259.         
  260.         if (err == noErr)
  261.             err = FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &mFileRefNum);
  262.     }
  263.     else
  264.     {
  265.         FSSpec spec;
  266.         if (!XMLParsePathToFSSpec(fileName, spec))
  267.             err = fnfErr;
  268.         
  269.         if (err == noErr)
  270.             err = FSpOpenDF(&spec, fsRdPerm, &mFileRefNum);
  271.     }
  272.     
  273.     if (err != noErr)
  274.         ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
  275.     
  276.     mFileValid = true;
  277. }
  278. unsigned int
  279. XMLMacFile::read(const unsigned int toRead, XMLByte* const toFill)
  280. {
  281.     unsigned int bytesRead = 0;
  282.     OSErr err = noErr;
  283.     
  284.     if (!mFileValid)
  285.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile);
  286.     
  287.     if (gHasHFSPlusAPIs)
  288.     {
  289.         ByteCount actualCount;
  290.         err = FSReadFork(mFileRefNum, fsFromMark, 0, toRead, toFill, &actualCount);
  291.         bytesRead = actualCount;
  292.     }
  293.     else
  294.     {
  295.         long byteCount = toRead;
  296.         err = FSRead(mFileRefNum, &byteCount, toFill);
  297.         bytesRead = byteCount;
  298.     }
  299.     
  300.     if (err != noErr && err != eofErr)
  301.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile);
  302.     
  303.     return bytesRead;
  304. }
  305. void
  306. XMLMacFile::reset()
  307. {
  308.     OSErr err = noErr;
  309.     
  310.     if (!mFileValid)
  311.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile);
  312.     
  313.     if (gHasHFSPlusAPIs)
  314.         err = FSSetForkPosition(mFileRefNum, fsFromStart, 0);
  315.     else
  316.         err = SetFPos(mFileRefNum, fsFromStart, 0);
  317.     
  318.     if (err != noErr)
  319.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile);
  320. }
  321. XMLMacFile::~XMLMacFile()
  322. {
  323.     if (mFileValid)
  324.         close();
  325. }
  326. // ---------------------------------------------------------------------------
  327. //  XMLPlatformUtils: The panic method
  328. // ---------------------------------------------------------------------------
  329. void
  330. XMLPlatformUtils::panic(const PanicReasons reason)
  331. {
  332.     const char* reasonStr = "Unknown reason";
  333.     if (reason == Panic_NoTransService)
  334.         reasonStr = "Could not load a transcoding service";
  335.     else if (reason == Panic_NoDefTranscoder)
  336.         reasonStr = "Could not load a local code page transcoder";
  337.     else if (reason == Panic_CantFindLib)
  338.         reasonStr = "Could not find the xerces-c DLL";
  339.     else if (reason == Panic_UnknownMsgDomain)
  340.         reasonStr = "Unknown message domain";
  341.     else if (reason == Panic_CantLoadMsgDomain)
  342.         reasonStr = "Cannot load message domain";
  343.     else if (reason == Panic_SynchronizationErr)
  344.         reasonStr = "A system synchronization error occurred";
  345.     else if (reason == Panic_SystemInit)
  346.         reasonStr = "Failed to complete platform dependent initialization";
  347.     else
  348.         reasonStr = "Unknown error source";
  349.     
  350.     char text[256];
  351.     std::snprintf(text, sizeof(text), "Xerces Panic Error: %s", reasonStr);
  352.     
  353.     //
  354.     //  The default handling of panics is not very friendly.
  355.     // To replace it with something more friendly, you'll need to:
  356.     // - #define XML_USE_CUSTOM_PANIC_PROC
  357.     // - Write, and link with, XMLCustomPanicProc
  358.     // - Implement your panic handling within XMLCustomPanicProc.
  359.     //
  360. #if defined(XML_USE_CUSTOM_PANIC_PROC)
  361.     XMLCustomPanicProc(reason, reasonStr);
  362. #else
  363.     Str255 pasText;
  364.     CopyCStringToPascal(text, pasText);
  365.     DebugStr(pasText);
  366. #endif
  367.     
  368.     // Life's got us down. Good-bye world.
  369.     std::exit(-1);
  370. }
  371. // ---------------------------------------------------------------------------
  372. //  XMLPlatformUtils: File Methods
  373. // ---------------------------------------------------------------------------
  374. unsigned int
  375. XMLPlatformUtils::curFilePos(const FileHandle theFile)
  376. {
  377.     return theFile->currPos();
  378. }
  379. void
  380. XMLPlatformUtils::closeFile(const FileHandle theFile)
  381. {
  382.     theFile->close();
  383. }
  384. unsigned int
  385. XMLPlatformUtils::fileSize(const FileHandle theFile)
  386. {
  387.     return theFile->size();
  388. }
  389. FileHandle
  390. XMLPlatformUtils::openFile(const char* const fileName)
  391. {
  392.     const XMLCh* xmlPath = XMLString::transcode(fileName);
  393.     ArrayJanitor<const XMLCh> jan(xmlPath);
  394.     return openFile(xmlPath);
  395. }
  396. FileHandle
  397. XMLPlatformUtils::openFile(const XMLCh* const fileName)
  398. {
  399.     // Check to make sure the file system is in a state where we can use it
  400.     if (!gFileSystemCompatible)
  401.         ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile);
  402.     
  403.     XMLMacFile* file = new XMLMacFile();
  404.     Janitor<XMLMacAbstractFile> janFile(file);
  405.     file->open(fileName);
  406.     janFile.orphan();
  407.     
  408.     return file;
  409. }
  410. FileHandle
  411. XMLPlatformUtils::openStdInHandle()
  412. {
  413.     ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile);
  414.     return NULL;
  415. }
  416. unsigned int
  417. XMLPlatformUtils::readFileBuffer(   const   FileHandle      theFile
  418.                                  , const unsigned int    toRead
  419.                                  ,       XMLByte* const  toFill)
  420. {
  421.     return theFile->read(toRead, toFill);
  422. }
  423. void
  424. XMLPlatformUtils::resetFile(FileHandle theFile)
  425. {
  426.     theFile->reset();
  427. }
  428. // ---------------------------------------------------------------------------
  429. //  XMLPlatformUtils: File system methods
  430. // ---------------------------------------------------------------------------
  431. XMLCh*
  432. XMLPlatformUtils::getFullPath(const XMLCh* const srcPath)
  433. {
  434.     XMLCh* path = NULL;
  435.     
  436.     if (gHasHFSPlusAPIs)
  437.     {
  438.         FSRef ref;
  439.         if (!XMLParsePathToFSRef(srcPath, ref) || (path = XMLCreateFullPathFromFSRef(ref)) == NULL)
  440.             path = XMLString::replicate(srcPath);
  441.     }
  442.     else
  443.     {
  444.         FSSpec spec;
  445.         if (!XMLParsePathToFSSpec(srcPath, spec) || (path = XMLCreateFullPathFromFSSpec(spec)) == NULL)
  446.             path = XMLString::replicate(srcPath);
  447.     }
  448.     
  449.     return path;
  450. }
  451. bool
  452. XMLPlatformUtils::isRelative(const XMLCh* const toCheck)
  453. {
  454.     return (toCheck[0] != L'/');
  455. }
  456. XMLCh*
  457. XMLPlatformUtils::weavePaths(const   XMLCh* const    basePath
  458.                                     , const XMLCh* const    relativePath)
  459.                                     
  460. {
  461.     // Code from Windows largely unmodified for the Macintosh,
  462.     // with the exception of removing support for '' path
  463.     // separator.
  464.     //
  465.     // Note that there is no support currently for Macintosh
  466.     // path separators ':'.
  467.     
  468.     // Create a buffer as large as both parts and empty it
  469.     ArrayJanitor<XMLCh> tmpBuf(new XMLCh[XMLString::stringLen(basePath)
  470.         + XMLString::stringLen(relativePath)
  471.         + 2]);
  472.     tmpBuf[0] = 0;
  473.     
  474.     //
  475.     //  If we have no base path, then just take the relative path as
  476.     //  is.
  477.     //
  478.     if (!basePath)
  479.     {
  480.         XMLString::copyString(tmpBuf.get(), relativePath);
  481.         return tmpBuf.release();
  482.     }
  483.     
  484.     if (!*basePath)
  485.     {
  486.         XMLString::copyString(tmpBuf.get(), relativePath);
  487.         return tmpBuf.release();
  488.     }
  489.     
  490.     const XMLCh* basePtr = basePath + (XMLString::stringLen(basePath) - 1);
  491.     if (*basePtr != chForwardSlash)
  492.     {
  493.         while ((basePtr >= basePath) && (*basePtr != chForwardSlash))
  494.             basePtr--;
  495.     }
  496.     
  497.     // There is no relevant base path, so just take the relative part
  498.     if (basePtr < basePath)
  499.     {
  500.         XMLString::copyString(tmpBuf.get(), relativePath);
  501.         return tmpBuf.release();
  502.     }
  503.     
  504.     //  We have some path part, so we need to check to see if we have to
  505.     //  weave any of the parts together.
  506.     const XMLCh* pathPtr = relativePath;
  507.     
  508.     while (true)
  509.     {
  510.         // If it does not start with some period, then we are done
  511.         if (*pathPtr != chPeriod)
  512.             break;
  513.         
  514.         unsigned int periodCount = 1;
  515.         pathPtr++;
  516.         if (*pathPtr == chPeriod)
  517.         {
  518.             pathPtr++;
  519.             periodCount++;
  520.         }
  521.         
  522.         // Has to be followed by a / or the null to mean anything
  523.         if ((*pathPtr != chForwardSlash) &&  *pathPtr)
  524.             break;
  525.         
  526.         if (*pathPtr)
  527.             pathPtr++;
  528.         
  529.         // If it's one period, just eat it, else move backwards in the base
  530.         if (periodCount == 2)
  531.         {
  532.             basePtr--;
  533.             while ((basePtr >= basePath) && (*basePtr != chForwardSlash))
  534.                 basePtr--;
  535.             
  536.             // The base cannot provide enough levels, so it's in error/
  537.             if (basePtr < basePath)
  538.                 ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_BasePathUnderflow);
  539.         }
  540.     }
  541.     
  542.     // Copy the base part up to the base pointer
  543.     XMLCh* bufPtr = tmpBuf.get();
  544.     const XMLCh* tmpPtr = basePath;
  545.     while (tmpPtr <= basePtr)
  546.         *bufPtr++ = *tmpPtr++;
  547.     
  548.     // And then copy on the rest of our path
  549.     XMLString::copyString(bufPtr, pathPtr);
  550.     
  551.     // Orphan the buffer and return it
  552.     return tmpBuf.release();
  553. }
  554. // ---------------------------------------------------------------------------
  555. //  XMLPlatformUtils: Timing Methods
  556. // ---------------------------------------------------------------------------
  557. unsigned long
  558. XMLPlatformUtils::getCurrentMillis()
  559. {
  560. if ((void*)kUnresolvedCFragSymbolAddress != UpTime)
  561. {
  562. // Use Driver services routines, now in Carbon,
  563. // to get the elapsed milliseconds.
  564. AbsoluteTime time = UpTime();
  565. return AbsoluteToDuration(time);
  566. }
  567. else
  568. return TickCount() * 100 / 6;
  569. }
  570. // ---------------------------------------------------------------------------
  571. //  Mutex methods
  572. //
  573. // There are a number of choices for multi-threading on Mac OS. Traditionally
  574. // there was the Thread Manager, which provided cooperative multitasking on
  575. // 68K and PPC platforms, and preemptive multitasking on 68K platforms only.
  576. // The primary threading model supported under Carbon is the Multiprocessing
  577. // library, which as of version 2.0 provides a nice set of primitives. Under
  578. // Mac OS X, the Multiprocessing library is a thin veneer over pthreads.
  579. //
  580. // For lack of any really good solutions, I've implemented these mutexes
  581. // atop the Multiprocessing library. The critical regions employed here
  582. // support recursive behavior, which is required by Xerces.
  583. //
  584. // Please note that, despite this implementation, there are probably other
  585. // MacOS barriers to actually using Xerces in a multi-threaded environment.
  586. // Many other parts of your system and/or development environment may not
  587. // support pre-emption, even under Mac OS X. Examples may include the memory
  588. // allocator, the Unicode Converter or Utilities, and perhaps the file
  589. // system (though the FS is better with Multiprocessing as of System 9.0).
  590. //
  591. // These routines are provided somewhat speculatively, and with the philosphy
  592. // that this code, at least, shouldn't be the reason why multithreading
  593. // doesn't work. Compatibility of this library wrt the other areas described
  594. // above will be resolved in time.
  595. // ---------------------------------------------------------------------------
  596. void*
  597. XMLPlatformUtils::makeMutex()
  598. {
  599. if (gHasMPAPIs)
  600. {
  601. MPCriticalRegionID criticalRegion = NULL;
  602. OSStatus status = MPCreateCriticalRegion(&criticalRegion);
  603. return (status == noErr) ? (void*)(criticalRegion) : NULL;
  604. }
  605. else
  606. return (void*)1;
  607. }
  608. void
  609. XMLPlatformUtils::closeMutex(void* const mtxHandle)
  610. {
  611. if (gHasMPAPIs)
  612. {
  613. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  614. OSStatus status = MPDeleteCriticalRegion(criticalRegion);
  615. status = noErr; // ignore any error and zap compiler warning
  616. }
  617. else
  618. ;
  619. }
  620. void
  621. XMLPlatformUtils::lockMutex(void* const mtxHandle)
  622. {
  623. if (gHasMPAPIs)
  624. {
  625. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  626. OSStatus status = MPEnterCriticalRegion(criticalRegion, kDurationForever);
  627. status = noErr; // ignore any error and zap compiler warning
  628. }
  629. else
  630. ;
  631. }
  632. void
  633. XMLPlatformUtils::unlockMutex(void* const mtxHandle)
  634. {
  635. if (gHasMPAPIs)
  636. {
  637. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  638. OSStatus status = MPExitCriticalRegion(criticalRegion);
  639. status = noErr; // ignore any error and zap compiler warning
  640. }
  641. else
  642. ;
  643. }
  644. // ---------------------------------------------------------------------------
  645. //  Miscellaneous synchronization methods
  646. //
  647. // Atomic manipulation is implemented atop routines that were traditionally
  648. // part of DriverServices, but are now apparently a part of Carbon. If this
  649. // selection proves to be invalid, similar routines in OpenTransport could
  650. // be used instead.
  651. // ---------------------------------------------------------------------------
  652. void*
  653. XMLPlatformUtils::compareAndSwap(       void**      toFill
  654.                                  , const void* const newValue
  655.                                  , const void* const toCompare)
  656. {
  657.     // Replace *toFill with newValue iff *toFill == toCompare,
  658.     // returning previous value of *toFill
  659.     
  660.     Boolean success = CompareAndSwap(
  661.         reinterpret_cast<UInt32>(toCompare),
  662.         reinterpret_cast<UInt32>(newValue),
  663.         reinterpret_cast<UInt32*>(toFill));
  664.     
  665.     return (success) ? const_cast<void*>(toCompare) : *toFill;
  666. }
  667. //
  668. // Atomic Increment and Decrement
  669. //
  670. // Apple's routines return the value as it was before the
  671. // operation, while these routines want to return it as it
  672. // is after. So we perform the translation before returning
  673. // the value.
  674. //
  675. int
  676. XMLPlatformUtils::atomicIncrement(int &location)
  677. {
  678.     return IncrementAtomic(reinterpret_cast<long*>(&location)) + 1;
  679. }
  680. int
  681. XMLPlatformUtils::atomicDecrement(int &location)
  682. {
  683.     return DecrementAtomic(reinterpret_cast<long*>(&location)) - 1;
  684. }
  685. // ---------------------------------------------------------------------------
  686. //  XMLPlatformUtils: Private Static Methods
  687. // ---------------------------------------------------------------------------
  688. //
  689. //  This method handles the MacOS basic init functions.
  690. //
  691. void
  692. XMLPlatformUtils::platformInit()
  693. {
  694. // Detect available functions by seeing if the symbols resolve
  695. long value = 0;
  696. gIsClassic = ((void*)kUnresolvedCFragSymbolAddress != Gestalt)
  697. && (noErr == Gestalt(gestaltSystemVersion, &value))
  698. && (value < 0x01000)
  699. ;
  700. gHasFSSpecAPIs = ((void*)kUnresolvedCFragSymbolAddress != FSMakeFSSpec);
  701. gHasFS2TBAPIs = ((void*)kUnresolvedCFragSymbolAddress != PBXGetVolInfoSync);
  702. gHasHFSPlusAPIs = ((void*)kUnresolvedCFragSymbolAddress != FSOpenFork);
  703. #if TARGET_API_MAC_CARBON
  704. gHasFSPathAPIs = ((void*)kUnresolvedCFragSymbolAddress != FSPathMakeRef);
  705. #else
  706. gHasFSPathAPIs = false;
  707. #endif
  708. gHasMPAPIs = MPLibraryIsLoaded();
  709.     
  710. // We require FSSpecs at a minimum
  711.     gFileSystemCompatible = gHasFSSpecAPIs;
  712. }
  713. //
  714. //  This method handles the MacOS basic termination functions.
  715. //
  716. void
  717. XMLPlatformUtils::platformTerm()
  718. {
  719. }
  720. // ---------------------------------------------------------------------------
  721. //  XMLPlatformUtils: Private Static Methods
  722. // ---------------------------------------------------------------------------
  723. //
  724. //  This method is called by the platform independent part of this class
  725. //  during initialization. We have to create the type of net accessor that
  726. //  we want to use. If none, then just return zero.
  727. //
  728. XMLNetAccessor*
  729. XMLPlatformUtils::makeNetAccessor()
  730. {
  731. #if (defined(XML_USE_NETACCESSOR_URLACCESS) || defined(XML_USE_NETACCESSOR_NATIVE))
  732. // Only try to use URLAccess if it's actually available
  733. if (URLAccessAvailable())
  734. return new MacOSURLAccess;
  735. #endif
  736. // No netaccessor available--we can live with it, but you won't
  737. // get net access.
  738. return 0;
  739. }
  740. //
  741. //  This method is called by the platform independent part of this class
  742. //  when client code asks to have one of the supported message sets loaded.
  743. //
  744. XMLMsgLoader*
  745. XMLPlatformUtils::loadAMsgSet(const XMLCh* const msgDomain)
  746. {
  747. #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
  748.     return new InMemMsgLoader(msgDomain);
  749. #else
  750.     #error You must provide a message loader
  751.     return 0;
  752. #endif
  753. }
  754. //
  755. //  This method is called very early in the bootstrapping process. This guy
  756. //  must create a transcoding service and return it. It cannot use any string
  757. //  methods, any transcoding services, throw any exceptions, etc... It just
  758. //  makes a transcoding service and returns it, or returns zero on failure.
  759. //
  760. XMLTransService*
  761. XMLPlatformUtils::makeTransService()
  762. {
  763. #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
  764.     if (MacOSUnicodeConverter::IsMacOSUnicodeConverterSupported())
  765.         return new MacOSUnicodeConverter;
  766. #else
  767.     #error You must provide a transcoding service implementation
  768. #endif
  769.     // If we got here it's because we didn't detect the Mac OS
  770.     // Unicode Converter or Text Encoding Converter routines
  771.     // that we require to function properly. Xerces will not
  772.     // survive this condition.
  773.     return NULL;
  774. }
  775. // ---------------------------------------------------------------------------
  776. // Utility Functions
  777. // ---------------------------------------------------------------------------
  778. XMLCh*
  779. CopyUniCharsToXMLChs(const UniChar* src, XMLCh* dst, std::size_t charCount, std::size_t maxChars)
  780. {
  781. // Ensure we don't step on anybody's toes
  782. std::size_t cnt = std::min(charCount, maxChars);
  783. // Copy the characters. UniChar is unsigned, so we shouldn't have
  784. // any sign extension problems.
  785. // To allow copy within a identical range, we copy backwards,
  786. // since XMLCh (may be) larger than UniChar.
  787. dst += cnt;
  788. src += cnt;
  789. for (; cnt > 0; --cnt)
  790. *--dst = *--src;
  791. return dst;
  792. }
  793. UniChar*
  794. CopyXMLChsToUniChars(const XMLCh* src, UniChar* dst, std::size_t charCount, std::size_t maxChars)
  795. {
  796. UniChar* dstBegin = dst;
  797. // Ensure we don't step on anybody's toes
  798. std::size_t cnt = std::min(charCount, maxChars);
  799. // Copy the characters. XMLCh's will be truncated on copy to UniChar's.
  800. // To allow copy within a identical range, we copy forwards,
  801. // since XMLCh (may be) larger than UniChar.
  802. for (; cnt > 0; --cnt)
  803. *dst++ = *src++;
  804. return dstBegin;
  805. }
  806. XMLCh*
  807. ConvertColonToSlash(XMLCh* p, std::size_t charCount)
  808. {
  809. XMLCh* start = p;
  810. for (; charCount > 0; --charCount)
  811. {
  812. XMLCh c = *p;
  813. if (c == ':')
  814. *p++ = '/';
  815. else
  816. p++;
  817. }
  818. return start;
  819. }
  820. XMLCh*
  821. ConvertSlashToColon(XMLCh* p, std::size_t charCount)
  822. {
  823. XMLCh* start = p;
  824. for (; charCount > 0; --charCount)
  825. {
  826. XMLCh c = *p;
  827. if (c == '/')
  828. *p++ = ':';
  829. else
  830. p++;
  831. }
  832. return start;
  833. }
  834. char*
  835. ConvertSlashToColon(char* p, std::size_t charCount)
  836. {
  837. char* start = p;
  838. for (; charCount > 0; --charCount)
  839. {
  840. char c = *p;
  841. if (c == '/')
  842. *p++ = ':';
  843. else
  844. p++;
  845. }
  846. return start;
  847. }
  848. bool
  849. XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref)
  850. {
  851. bool result;
  852. // If FSPathMakeRef is available, we use it to parse the
  853. // path: this gives us "standard" path support under MacOS X.
  854. // Without this, our paths in that environment would always
  855. // have a volume name at their root...which would look
  856. // "normal" to Mac users, but not normal to unix users. Since
  857. // we're making "unix" paths, we'll stick with the unix
  858. // style paths. This also allows us to easilly take paths
  859. // off the command line.
  860. //
  861. // FSPathMakeRef is available on Mac OS X and in CarbonLib 1.1
  862. // and greater. But on classic under CarbonLib, it expects paths
  863. // to contain ':' separators, for which we're not prepared. Since
  864. // this isn't a case where we need to use it, we drop back to the
  865. // classic case for this.
  866. if (TARGET_API_MAC_CARBON && !gIsClassic && gHasFSPathAPIs)
  867. result = XMLParsePathToFSRef_X(pathName, ref);
  868. else
  869. result = XMLParsePathToFSRef_Classic(pathName, ref);
  870. return result;
  871. }
  872. bool
  873. XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref)
  874. {
  875. // Parse Path to FSRef using FSPathMakeRef as available under
  876. // Mac OS X and CarbonLib 1.1 and greater.
  877. OSStatus err = noErr;
  878. std::size_t pathLen = XMLString::stringLen(pathName);
  879.     // Transcode XMLCh into UniChar
  880. UniChar uniBuf[kMaxStaticPathChars];
  881. CopyXMLChsToUniChars(pathName, uniBuf, pathLen, kMaxStaticPathChars);
  882. // Transcode Unicode to UTF-8
  883. char utf8Buf[kMaxStaticPathChars];
  884. pathLen = TranscodeUniCharsToUTF8(uniBuf, utf8Buf, pathLen, kMaxStaticPathChars-1);
  885. // Terminate the path
  886. char* p = utf8Buf;
  887. p[pathLen++] = '';
  888. // If it's a relative path, pre-pend the current directory to the path.
  889. // FSPathMakeRef doesn't deal with relativity on the front of the path
  890. if (*p == '.')
  891. {
  892. // Right justify the user path to make room for the pre-pended path
  893. std::memmove(p + kMaxStaticPathChars - pathLen, p, pathLen);
  894. // Get the current directory
  895.         FSSpec spec;
  896. if (err == noErr)
  897. err = FSMakeFSSpec(0, 0, NULL, &spec);
  898.         if (err == noErr)
  899.             err = FSpMakeFSRef(&spec, &ref);
  900. // Get pathname to the current directory
  901. if (err == noErr)
  902. err = FSRefMakePath(&ref, reinterpret_cast<UInt8*>(p), kMaxStaticPathChars - pathLen - 1); // leave room for one '/'
  903. std::size_t prefixLen = std::strlen(p);
  904. // Now munge the two paths back together
  905. if (err == noErr)
  906. {
  907. p[prefixLen++] = '/';
  908. std::memmove(p + prefixLen, p + kMaxStaticPathChars - pathLen, pathLen);
  909. }
  910. // We now have a path from an absolute starting point
  911. }
  912. // Let the OS discover the location
  913. Boolean isDirectory = false;
  914. if (err == noErr)
  915. err = FSPathMakeRef(reinterpret_cast<UInt8*>(p), &ref, &isDirectory);
  916. // Return true on success
  917. return (err == noErr);
  918. }
  919. bool
  920. XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref)
  921. {
  922. // Parse Path to FSRef by stepping manually through path components.
  923. // Path's parsed in this way must always begin with a volume name.
  924. // This assumption would fail for standard unix paths under Mac OS X,
  925. // so for those cases we use the routine XMLParsePathToFSRef_Carbon
  926. // above.
  927.     const XMLCh* p = pathName;
  928.     const XMLCh* pEnd;
  929.     std::size_t segLen;
  930. const std::size_t kXMLBufCount = 256;
  931. XMLCh xmlBuf[kXMLBufCount];
  932.     
  933.     OSErr err = noErr;
  934.     
  935.     if (*p == L'/')
  936.     {
  937.         // Absolute name: grab the first component as volume name
  938.         
  939.         // Find the end of the path segment
  940.         for (pEnd = ++p; *pEnd && *pEnd != L'/'; ++pEnd) ;
  941.         segLen = pEnd - p;
  942.         
  943.         // Try to find a volume that matches this name
  944.         for (ItemCount volIndex = 1; err == noErr; ++volIndex)
  945.         {
  946.             HFSUniStr255 hfsStr;
  947.             hfsStr.length = 0;
  948.             
  949.             // Get the volume name
  950.             err = FSGetVolumeInfo(
  951.                 0,
  952.                 volIndex,
  953.                 static_cast<FSVolumeRefNum*>(NULL),
  954.                 0,
  955.                 static_cast<FSVolumeInfo*>(NULL),
  956.                 &hfsStr,
  957.                 &ref
  958.                 );
  959.             
  960.             // Compare against our path segment
  961.             if (err == noErr && segLen == hfsStr.length)
  962.             {
  963.              // Case-insensitive compare
  964.              if (XMLString::compareNIString(
  965. ConvertSlashToColon(
  966. CopyUniCharsToXMLChs(hfsStr.unicode, xmlBuf, segLen, kXMLBufCount),
  967. segLen),
  968. p, segLen) == 0)
  969.                     break;  // we found our volume
  970.             }
  971.         }
  972.         
  973.         p = pEnd;
  974.     }
  975.     else
  976.     {
  977.         // Relative name, so get the default directory as parent ref
  978.         FSSpec spec;
  979.         err = FSMakeFSSpec(0, 0, NULL, &spec);
  980.         if (err == noErr)
  981.             err = FSpMakeFSRef(&spec, &ref);
  982.     }
  983.     
  984.     // ref now refers to the a parent directory: parse the rest of the path
  985.     while (err == noErr && *p)
  986.     {
  987.         switch (*p)
  988.         {
  989.         case L'/':   // Just skip any number of path separators
  990.             ++p;
  991.             break;
  992.             
  993.         case L'.':   // Potentially "current directory" or "parent directory"
  994.             if (p[1] == L'/' || p[1] == 0)       // "current directory"
  995.             {
  996.                 ++p;
  997.                 break;
  998.             }
  999.             else if (p[1] == L'.' && (p[2] == L'/' || p[2] == 0)) // "parent directory"
  1000.             {
  1001.                 p += 2;  // Get the parent of our parent
  1002.                 
  1003.                 FSCatalogInfo catalogInfo;
  1004.                 err = FSGetCatalogInfo(
  1005.                     &ref,
  1006.                     kFSCatInfoParentDirID,
  1007.                     &catalogInfo,
  1008.                     static_cast<HFSUniStr255*>(NULL),
  1009.                     static_cast<FSSpec*>(NULL),
  1010.                     &ref
  1011.                     );
  1012.                 
  1013.                 // Check that we didn't go too far
  1014.                 if (err != noErr || catalogInfo.parentDirID == fsRtParID)
  1015.                     return false;
  1016.                 
  1017.                 break;
  1018.             }
  1019.             else // some other sequence of periods...fall through and treat as segment
  1020.                 ;
  1021.             
  1022.         default:
  1023.             // Find the end of the path segment
  1024.             for (pEnd = p; *pEnd && *pEnd != L'/'; ++pEnd) ;
  1025.             segLen = pEnd - p;
  1026.             // pEnd now points either to '/' or NUL
  1027.             // Create a new ref using this path segment
  1028.             err = FSMakeFSRefUnicode(
  1029.                 &ref,
  1030.                 segLen,
  1031.                 ConvertColonToSlash(
  1032.                  CopyXMLChsToUniChars(p, reinterpret_cast<UniChar*>(xmlBuf), segLen, kXMLBufCount),
  1033.                  segLen),
  1034.                 kTextEncodingUnknown,
  1035.                 &ref
  1036.                 );
  1037.             
  1038.             p = pEnd;
  1039.             break;
  1040.         }
  1041.     }
  1042.     
  1043.     return err == noErr;
  1044. }
  1045. bool
  1046. XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec)
  1047. {
  1048. // Parse Path to an FSSpec
  1049. // If we've got HFS+ APIs, do this in terms of refs so that
  1050. // we can grandfather in the use of FSPathMakeRef under Mac OS X 
  1051. // and CarbonLib 1.1. Otherwise, do it the hard way.
  1052. bool result = false;
  1053. if (gHasHFSPlusAPIs)
  1054. {
  1055. // Parse to a ref
  1056. FSRef ref;
  1057. result = XMLParsePathToFSRef(pathName, ref);
  1058. // Down convert to a spec
  1059. if (result)
  1060. result = (noErr == FSGetCatalogInfo(&ref,
  1061. kFSCatInfoNone,
  1062. static_cast<FSCatalogInfo*>(NULL), // catalogInfo
  1063. static_cast<HFSUniStr255*>(NULL), // outName
  1064. &spec,
  1065. static_cast<FSRef*>(NULL) // parentRef
  1066. ));
  1067. }
  1068. else
  1069. result = XMLParsePathToFSSpec_Classic(pathName, spec);
  1070. // Return true on success
  1071. return result;
  1072. }
  1073. bool
  1074. XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec)
  1075. {
  1076. // Manually parse the path using FSSpec APIs.
  1077.     // Transcode the path into ascii
  1078.     const char* p = XMLString::transcode(pathName);
  1079.     ArrayJanitor<const char> janPath(p);
  1080.     const char* pEnd;
  1081.     std::size_t segLen;
  1082.     
  1083.     OSStatus err = noErr;
  1084.     Str255 name;  // Must be long enough for a partial pathname consisting of two segments (64 bytes)
  1085.     
  1086.     if (*p == '/')
  1087.     {
  1088.         // Absolute name: grab the first component as volume name
  1089.         
  1090.         // Find the end of the path segment
  1091.         for (pEnd = ++p; *pEnd && *pEnd != '/'; ++pEnd) ;
  1092.         segLen = pEnd - p;
  1093.         
  1094.         // Try to find a volume that matches this name
  1095.         for (ItemCount volIndex = 1; err == noErr; ++volIndex)
  1096.         {
  1097.             FSVolumeRefNum volRefNum;
  1098.             
  1099.             if (gHasFS2TBAPIs)
  1100.             {
  1101.                 XVolumeParam xVolParam;
  1102.                 name[0] = 0;
  1103.                 xVolParam.ioNamePtr  = name;
  1104.                 xVolParam.ioVRefNum  = 0;
  1105.                 xVolParam.ioXVersion = 0;
  1106.                 xVolParam.ioVolIndex = volIndex;
  1107.                 err = PBXGetVolInfoSync(&xVolParam);
  1108.                 volRefNum = xVolParam.ioVRefNum;
  1109.             }
  1110.             else
  1111.             {
  1112. #if !TARGET_API_MAC_CARBON
  1113.                 HParamBlockRec hfsParams;
  1114.                 name[0] = 0;
  1115.                 hfsParams.volumeParam.ioNamePtr  = name;
  1116.                 hfsParams.volumeParam.ioVRefNum  = 0;
  1117.                 hfsParams.volumeParam.ioVolIndex = volIndex;
  1118.                 err = PBHGetVInfoSync(&hfsParams);
  1119.                 volRefNum = hfsParams.volumeParam.ioVRefNum;
  1120. #else
  1121.                 err = nsvErr;
  1122. #endif
  1123.             }
  1124.             
  1125.             // Compare against our path segment
  1126.             if (err == noErr && segLen == StrLength(name))
  1127.             {
  1128.              // Case-insensitive compare
  1129.              if (XMLString::compareNIString(
  1130.              ConvertSlashToColon(reinterpret_cast<char*>(&name[1]), segLen),
  1131.              p, segLen) == 0)
  1132.                 {
  1133.                     // we found our volume: fill in the spec
  1134.                     err = FSMakeFSSpec(volRefNum, fsRtDirID, NULL, &spec);
  1135.                     break;
  1136.                 }
  1137.             }
  1138.         }
  1139.         
  1140.         p = pEnd;
  1141.     }
  1142.     else
  1143.     {
  1144.         // Relative name, so get the default directory as parent spec
  1145.         err = FSMakeFSSpec(0, 0, NULL, &spec);
  1146.     }
  1147.     
  1148.     // We now have a parent directory in the spec.
  1149.     while (err == noErr && *p)
  1150.     {
  1151.         switch (*p)
  1152.         {
  1153.         case '/':  // Just skip any number of path separators
  1154.             ++p;
  1155.             break;
  1156.             
  1157.         case L'.':  // Potentially "current directory" or "parent directory"
  1158.             if (p[1] == '/' || p[1] == 0)      // "current directory"
  1159.             {
  1160.                 ++p;
  1161.                 break;
  1162.             }
  1163.             else if (p[1] == '.' && (p[2] == '/' || p[2] == 0)) // "parent directory"
  1164.             {
  1165.                 p += 2;  // Get the parent of our parent
  1166.                 
  1167.                 CInfoPBRec catInfo;
  1168.                 catInfo.dirInfo.ioNamePtr = NULL;
  1169.                 catInfo.dirInfo.ioVRefNum = spec.vRefNum;
  1170.                 catInfo.dirInfo.ioFDirIndex = -1;
  1171.                 catInfo.dirInfo.ioDrDirID = spec.parID;
  1172.                 err = PBGetCatInfoSync(&catInfo);
  1173.                 
  1174.                 // Check that we didn't go too far
  1175.                 if (err != noErr || catInfo.dirInfo.ioDrParID == fsRtParID)
  1176.                     return false;
  1177.                 
  1178.                 // Update our spec
  1179.                 if (err == noErr)
  1180.                     err = FSMakeFSSpec(spec.vRefNum, catInfo.dirInfo.ioDrDirID, NULL, &spec);
  1181.                 
  1182.                 break;
  1183.             }
  1184.             else // some other sequence of periods...fall through and treat as segment
  1185.                 ;
  1186.             
  1187.         default:
  1188.             {
  1189.                 // Find the end of the path segment
  1190.                 for (pEnd = p; *pEnd && *pEnd != '/'; ++pEnd) ;
  1191.                 segLen = pEnd - p;
  1192.                 
  1193.                 // Check for name length overflow
  1194.                 if (segLen > 31)
  1195.                     return false;
  1196.                 
  1197.                 // Make a partial pathname from our current spec to the new object
  1198.                 unsigned char* partial = &name[1];
  1199.                 
  1200.                 *partial++ = ':';       // Partial leads with :
  1201.                 const unsigned char* specName = spec.name; // Copy in spec name
  1202.                 for (int specCnt = *specName++; specCnt > 0; --specCnt)
  1203.                     *partial++ = *specName++;
  1204.                 
  1205.                 *partial++ = ':';       // Separator
  1206.                 while (p != pEnd)       // Copy in new element
  1207.                 {
  1208.                  if (*p == ':') // Convert : to /
  1209.                  {
  1210.                  *partial++ = '/';
  1211.                  p++;
  1212.                  }
  1213.                  else
  1214.                  *partial++ = *p++;
  1215. }
  1216.                 
  1217.                 name[0] = partial - &name[1];   // Set the name length
  1218.                 
  1219.                 // Update the spec
  1220.                 err = FSMakeFSSpec(spec.vRefNum, spec.parID, name, &spec);
  1221.             }
  1222.             break;
  1223.         }
  1224.     }
  1225.     
  1226.     return err == noErr;
  1227. }
  1228. XMLCh*
  1229. XMLCreateFullPathFromFSRef(const FSRef& startingRef)
  1230. {
  1231. XMLCh* result = NULL;
  1232. // If FSRefMakePath is available, we use it to create the
  1233. // path: this gives us "standard" path support under MacOS X.
  1234. // Without this, our paths in that environment would always
  1235. // have a volume name at their root...which would look
  1236. // "normal" to Mac users, but not normal to unix users. Since
  1237. // we're making "unix" paths, we'll stick with the unix
  1238. // style paths. This also allows us to easilly take paths
  1239. // off the command line.
  1240. //
  1241. // FSRefMakePath is available on Mac OS X and in CarbonLib 1.1
  1242. // and greater. But we use it only on X since on Classic it
  1243. // makes paths with ':' separators, which really confuses us!
  1244. if (TARGET_API_MAC_CARBON && !gIsClassic && gHasFSPathAPIs)
  1245. result = XMLCreateFullPathFromFSRef_X(startingRef);
  1246. else
  1247. result = XMLCreateFullPathFromFSRef_Classic(startingRef);
  1248. return result;
  1249. }
  1250. XMLCh*
  1251. XMLCreateFullPathFromFSRef_X(const FSRef& startingRef)
  1252. {
  1253. // Create the path using FSRefMakePath as available on Mac OS X
  1254. // and under CarbonLib 1.1 and greater.
  1255. OSStatus err = noErr;
  1256. // Make the path in utf8 form
  1257. char utf8Buf[kMaxStaticPathChars];
  1258. utf8Buf[0] = '';
  1259. if (err == noErr)
  1260. err = FSRefMakePath(&startingRef, reinterpret_cast<UInt8*>(utf8Buf), kMaxStaticPathChars);
  1261. // Bail if path conversion failed
  1262. if (err != noErr)
  1263. return NULL;
  1264. // Transcode into UniChars
  1265. UniChar uniBuf[kMaxStaticPathChars];
  1266. std::size_t pathLen = TranscodeUTF8ToUniChars(utf8Buf, uniBuf, kMaxStaticPathChars-1);
  1267. uniBuf[pathLen++] = 0;
  1268. // Transcode into a dynamically allocated buffer of XMLChs
  1269. ArrayJanitor<XMLCh> result(new XMLCh[pathLen]);
  1270. if (result.get() != NULL)
  1271. CopyUniCharsToXMLChs(uniBuf, result.get(), pathLen, pathLen);
  1272. return result.release();
  1273. }
  1274. XMLCh*
  1275. XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef)
  1276. {
  1277. // Manually create the path using FSRef APIs.
  1278.     OSStatus err = noErr;
  1279.     FSCatalogInfo catalogInfo;
  1280.     HFSUniStr255 name;
  1281.     FSRef ref = startingRef;
  1282.     
  1283.     XMLCh buf[kMaxStaticPathChars];
  1284.     std::size_t bufPos   = kMaxStaticPathChars;
  1285.     std::size_t bufCnt   = 0;
  1286.     
  1287.     ArrayJanitor<XMLCh> result(NULL);
  1288.     std::size_t resultLen = 0;
  1289.     
  1290.     buf[--bufPos] = L'';
  1291.     ++bufCnt;
  1292.     
  1293. do
  1294. {
  1295. err = FSGetCatalogInfo(
  1296. &ref,
  1297. kFSCatInfoParentDirID,
  1298. &catalogInfo,
  1299. &name,
  1300. static_cast<FSSpec*>(NULL),
  1301. &ref
  1302. );
  1303. if (err == noErr)
  1304. {
  1305. // If there's not room in our static buffer for the new
  1306. // name plus separator, dump it to the dynamic result buffer.
  1307. if (bufPos < (std::size_t)name.length + 1)
  1308. {
  1309. ArrayJanitor<XMLCh> temp(new XMLCh[bufCnt + resultLen]);
  1310. // Copy in the static buffer
  1311. std::memcpy(temp.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
  1312. // Copy in the old buffer
  1313. if (resultLen > 0)
  1314. std::memcpy(temp.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
  1315. result.reset(temp.release());
  1316. resultLen += bufCnt;
  1317. bufPos = kMaxStaticPathChars;
  1318. bufCnt = 0;
  1319. }
  1320. // Prepend our new name and a '/'
  1321. bufPos -= name.length;
  1322. ConvertSlashToColon(CopyUniCharsToXMLChs(name.unicode, &buf[bufPos], name.length, name.length), name.length);
  1323. buf[--bufPos] = L'/';
  1324. bufCnt += (name.length + 1);
  1325. }
  1326. }
  1327. while (err == noErr && catalogInfo.parentDirID != fsRtParID);
  1328. // Composite existing buffer with any previous result buffer
  1329. ArrayJanitor<XMLCh> final(new XMLCh[bufCnt + resultLen]);
  1330. // Copy in the static buffer
  1331. std::memcpy(final.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
  1332. // Copy in the old buffer
  1333. if (resultLen > 0)
  1334. std::memcpy(final.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
  1335.     return final.release();
  1336. }
  1337. XMLCh*
  1338. XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec)
  1339. {
  1340. XMLCh* result = NULL;
  1341. // If FSRefs are available, do this operation in terms of refs...this
  1342. // allows us to grandfather in the use of FSPathMakeRef and FSRefMakePath
  1343. // if possible.
  1344. if (gHasHFSPlusAPIs)
  1345. {
  1346. OSStatus err = noErr;
  1347. FSRef ref;
  1348. // Up convert to FSRef
  1349. if (err == noErr)
  1350. err = FSpMakeFSRef(&startingSpec, &ref);
  1351. // Create the path
  1352. if (err == noErr)
  1353. result = XMLCreateFullPathFromFSRef(ref);
  1354. }
  1355. else
  1356. {
  1357. // Create using FSSpecs only
  1358. result = XMLCreateFullPathFromFSSpec_Classic(startingSpec);
  1359. }
  1360. return result;
  1361. }
  1362. XMLCh*
  1363. XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec)
  1364. {
  1365. // Manually create the path using FSSpec APIs.
  1366.     OSStatus err = noErr;
  1367.     FSSpec spec = startingSpec;
  1368.     
  1369.     char buf[kMaxStaticPathChars];
  1370.     std::size_t bufPos   = kMaxStaticPathChars;
  1371.     std::size_t bufCnt   = 0;
  1372.     
  1373.     ArrayJanitor<char> result(NULL);
  1374.     std::size_t resultLen = 0;
  1375.     
  1376.     buf[--bufPos] = '';
  1377.     ++bufCnt;
  1378.     
  1379. short index = 0;
  1380. do
  1381. {
  1382. CInfoPBRec catInfo;
  1383. catInfo.dirInfo.ioNamePtr = spec.name;
  1384. catInfo.dirInfo.ioVRefNum = spec.vRefNum;
  1385. catInfo.dirInfo.ioFDirIndex = index;
  1386. catInfo.dirInfo.ioDrDirID = spec.parID;
  1387. err = PBGetCatInfoSync(&catInfo);
  1388. if (err == noErr)
  1389. {
  1390. std::size_t nameLen = StrLength(spec.name);
  1391. // If there's not room in our static buffer for the new
  1392. // name plus separator, dump it to the dynamic result buffer.
  1393. if (bufPos < nameLen + 1)
  1394. {
  1395. ArrayJanitor<char> temp(new char[bufCnt + resultLen]);
  1396. // Copy in the static buffer
  1397. std::memcpy(temp.get(), &buf[bufPos], bufCnt);
  1398. // Copy in the old buffer
  1399. if (resultLen > 0)
  1400. std::memcpy(temp.get() + bufCnt, result.get(), resultLen);
  1401. result.reset(temp.release());
  1402. resultLen += bufCnt;
  1403. bufPos = kMaxStaticPathChars;
  1404. bufCnt = 0;
  1405. }
  1406. // Prepend our new name and a '/'
  1407. bufPos -= nameLen;
  1408. ConvertSlashToColon((char*)std::memcpy(&buf[bufPos], &spec.name[1], nameLen), nameLen);
  1409. buf[--bufPos] = '/';
  1410. bufCnt += (nameLen + 1);
  1411. // From here on out, ignore the input file name
  1412. index = -1;
  1413. // Move up to the parent
  1414. spec.parID = catInfo.dirInfo.ioDrParID;
  1415. }
  1416. }
  1417. while (err == noErr && spec.parID != fsRtParID);
  1418. // Composite existing buffer with any previous result buffer
  1419. ArrayJanitor<char> final(new char[bufCnt + resultLen]);
  1420. // Copy in the static buffer
  1421. std::memcpy(final.get(), &buf[bufPos], bufCnt);
  1422. // Copy in the old buffer
  1423. if (resultLen > 0)
  1424. std::memcpy(final.get() + bufCnt, result.get(), resultLen);
  1425.     
  1426.     // Cleanup and transcode to unicode
  1427.     return XMLString::transcode(final.get());
  1428. }
  1429. std::size_t
  1430. TranscodeUniCharsToUTF8(UniChar* src, char* dst, std::size_t srcCnt, std::size_t maxChars)
  1431. {
  1432. std::size_t result = 0;
  1433.     // Use the text encoding converter to perform the format conversion.
  1434.     // Note that this is slightly heavyweight, but we're not in a performance
  1435.     // sensitive code-path.
  1436.     
  1437.     OSStatus err = noErr;
  1438.     TECObjectRef tec = 0;
  1439.     ByteCount bytesConsumed = 0;
  1440.     ByteCount bytesProduced = 0;
  1441.     
  1442.     TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1443.                                         kTextEncodingDefaultVariant,
  1444.                                         kUnicode16BitFormat);
  1445.                                         
  1446.     TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1447.                                         kTextEncodingDefaultVariant,
  1448.                                         kUnicodeUTF8Format);
  1449.     
  1450.     if (err == noErr)
  1451.         err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
  1452.         
  1453.     if (err == noErr)
  1454.         err = TECConvertText(tec,
  1455.                     (ConstTextPtr) src,
  1456.                     srcCnt * sizeof(UniChar), // inputBufferLength
  1457.                     &bytesConsumed, // actualInputLength
  1458.                     (TextPtr) dst, // outputBuffer
  1459.                     maxChars * sizeof(char), // outputBufferLength
  1460.                     &bytesProduced); // actualOutputLength
  1461.                     
  1462.     TECDisposeConverter(tec);
  1463.     
  1464.     result = bytesProduced;
  1465.     // Return number of chars in dst
  1466. return result;
  1467. }
  1468. std::size_t
  1469. TranscodeUTF8ToUniChars(char* src, UniChar* dst, std::size_t maxChars)
  1470. {
  1471. std::size_t result = 0;
  1472.     // Use the text encoding converter to perform the format conversion.
  1473.     // Note that this is slightly heavyweight, but we're not in a performance
  1474.     // sensitive code-path.
  1475.     
  1476.     OSStatus err = noErr;
  1477.     TECObjectRef tec = 0;
  1478.     ByteCount bytesConsumed = 0;
  1479.     ByteCount bytesProduced = 0;
  1480.     
  1481.     
  1482.     TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1483.                                         kTextEncodingDefaultVariant,
  1484.                                         kUnicodeUTF8Format);
  1485.                                         
  1486.     TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1487.                                         kTextEncodingDefaultVariant,
  1488.                                         kUnicode16BitFormat);
  1489.     
  1490.     if (err == noErr)
  1491.         err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
  1492.         
  1493.     if (err == noErr)
  1494.         err = TECConvertText(tec,
  1495.                     (ConstTextPtr) src,
  1496.                     std::strlen(src), // inputBufferLength
  1497.                     &bytesConsumed, // actualInputLength
  1498.                     (TextPtr) dst, // outputBuffer
  1499.                     maxChars * sizeof(UniChar), // outputBufferLength
  1500.                     &bytesProduced); // actualOutputLength
  1501.                     
  1502.     TECDisposeConverter(tec);
  1503.     
  1504.     result = bytesProduced / sizeof(UniChar);
  1505.     // Return number of unicode characters in dst
  1506. return result;
  1507. }