MacOSPlatformUtils.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:47k
源码类别:

词法分析

开发平台:

Visual 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.18 2003/05/21 02:43:07 jberry Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <cstring>
  63. #include <cstdlib>
  64. #include <cctype>
  65. #include <cstdio>
  66. #include <memory>
  67. #include <algorithm>
  68. #if defined(__APPLE__)
  69.     // Include from Frameworks Headers under ProjectBuilder
  70.     #include <Carbon/Carbon.h>
  71. #else
  72.     // Classic include styles
  73.     #include <Files.h>
  74.     #include <Gestalt.h>
  75.     #include <TextUtils.h>
  76.     #include <TextEncodingConverter.h>
  77.     #include <Multiprocessing.h>
  78.     #include <DriverSynchronization.h>
  79.     #include <DriverServices.h>
  80.     #include <CFString.h>
  81.     #include <URLAccess.h>
  82. #endif
  83. #include <xercesc/util/XercesDefs.hpp>
  84. #include <xercesc/util/Janitor.hpp>
  85. #include <xercesc/util/PlatformUtils.hpp>
  86. #include <xercesc/util/RuntimeException.hpp>
  87. #include <xercesc/util/XMLUniDefs.hpp>
  88. #include <xercesc/util/XMLUni.hpp>
  89. #include <xercesc/util/XMLString.hpp>
  90. #include <xercesc/util/Platforms/MacOS/MacOSPlatformUtils.hpp>
  91. #include <xercesc/util/Platforms/MacOS/MacCarbonFile.hpp>
  92. #include <xercesc/util/Platforms/MacOS/MacPosixFile.hpp>
  93. #include <xercesc/util/PanicHandler.hpp>
  94. #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
  95.    #include <xercesc/util/MsgLoaders/InMemory/InMemMsgLoader.hpp>
  96. #endif
  97. #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
  98.    #include <xercesc/util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.hpp>
  99. #endif
  100. // Make up our minds about which netaccessor we'll use
  101. #if (defined(XML_USE_NETACCESSOR_URLACCESSCF) || (defined(XML_USE_NETACCESSOR_NATIVE) && TARGET_API_MAC_CARBON))
  102.     #define USE_URLACCESSCF
  103. #elif (defined(XML_USE_NETACCESSOR_URLACCESS) || (defined(XML_USE_NETACCESSOR_NATIVE) && !TARGET_API_MAC_CARBON))
  104.     #define USE_URLACCESS
  105. #endif
  106. #if defined(USE_URLACCESSCF)
  107.    #include <xercesc/util/NetAccessors/MacOSURLAccessCF/MacOSURLAccessCF.hpp>
  108. #elif defined(USE_URLACCESS)
  109.    #include <xercesc/util/NetAccessors/MacOSURLAccess/MacOSURLAccess.hpp>
  110. #endif
  111. XERCES_CPP_NAMESPACE_BEGIN
  112. //----------------------------------------------------------------------------
  113. // Function Prototypes
  114. //----------------------------------------------------------------------------
  115. XMLCh* ConvertColonToSlash(XMLCh* p, std::size_t charCount);
  116. XMLCh* ConvertSlashToColon(XMLCh* p, std::size_t charCount);
  117. char* ConvertSlashToColon(char* p, std::size_t charCount);
  118. XMLCh* XMLCreateFullPathFromFSRef_X(const FSRef& startingRef, MemoryManager* const manager);
  119. XMLCh* XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef, MemoryManager* const manager);
  120. XMLCh* XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec,
  121.                                             MemoryManager* const manager);
  122. bool XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager);
  123. bool XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager);
  124. bool XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec, MemoryManager* const manager);
  125. //----------------------------------------------------------------------------
  126. //  Local Data
  127. //
  128. //  gFileSystemCompatible
  129. //   This flag indicates whether the file system APIs meet our minimum
  130. //   requirements.
  131. //
  132. // gHasFSSpecAPIs
  133. //   True if the FSSpecAPIs are available. These are required.
  134. //
  135. // gHasF2TBAPIs
  136. //   True if the FS supports 2 terrabyte calls. These are required for
  137. //   use under Carbon.
  138. //
  139. // gHasHFSPlusAPIs
  140. //   True if the FS supports HFSPlus APIs. If this is true, then the
  141. //   new Fork calls are used, and all file name and path handling
  142. //   uses long unicode names. Note that once a file is opened with
  143. //   the fork calls, only fork calls may be used to access it.
  144. //
  145. // gHasFSPathAPIs
  146. //   True if the FS supports path creation APIs FSPathMakeRef and
  147. //  FSRefMakePath.
  148. //
  149. // gPathAPIsUsePosixPaths
  150. //   True if the path creation APIs FSPathMakeRef and FSRefMakePath
  151. //  use posix, rather than HFS, style paths. If so, these routines
  152. //  are used to support path creation and  interpretation.
  153. //
  154. // gHasMPAPIs
  155. //  True if the Multiprocessing APIs are available.
  156. //
  157. // gUsePosixFiles
  158. //   True if we're using XMLMacPosixFile rather than XMLMacCarbonFile.
  159. //----------------------------------------------------------------------------
  160. bool gFileSystemCompatible = false;
  161. bool gHasFSSpecAPIs = false;
  162. bool gHasFS2TBAPIs = false;
  163. bool gHasHFSPlusAPIs = false;
  164. bool gHasFSPathAPIs = false;
  165. bool gPathAPIsUsePosixPaths = false;
  166. bool gHasMPAPIs = false;
  167. bool gUsePosixFiles = false;
  168. // ---------------------------------------------------------------------------
  169. //  XMLPlatformUtils: The panic method
  170. // ---------------------------------------------------------------------------
  171. void 
  172. XMLPlatformUtils::panic(const PanicHandler::PanicReasons reason)
  173. {
  174.     if (fgUserPanicHandler)
  175. fgUserPanicHandler->panic(reason);
  176. else
  177. fgDefaultPanicHandler->panic(reason);
  178. }
  179. // ---------------------------------------------------------------------------
  180. //  XMLPlatformUtils: File Methods
  181. // ---------------------------------------------------------------------------
  182. unsigned int
  183. XMLPlatformUtils::curFilePos(const FileHandle theFile)
  184. {
  185. return reinterpret_cast<XMLMacAbstractFile*>(theFile)->currPos();
  186. }
  187. void
  188. XMLPlatformUtils::closeFile(const FileHandle theFile)
  189. {
  190.     reinterpret_cast<XMLMacAbstractFile*>(theFile)->close();
  191. }
  192. unsigned int
  193. XMLPlatformUtils::fileSize(const FileHandle theFile)
  194. {
  195.     return reinterpret_cast<XMLMacAbstractFile*>(theFile)->size();
  196. }
  197. FileHandle
  198. XMLPlatformUtils::openFile(const char* const fileName)
  199. {
  200.     // Check to make sure the file system is in a state where we can use it
  201.     if (!gFileSystemCompatible)
  202.         ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
  203.     Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
  204.     
  205.     return (file->open(fileName, false)) ? file.release() : NULL;
  206. }
  207. FileHandle
  208. XMLPlatformUtils::openFile(const XMLCh* const fileName)
  209. {
  210.     // Check to make sure the file system is in a state where we can use it
  211.     if (!gFileSystemCompatible)
  212.         ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
  213.     Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
  214.     return (file->open(fileName, false)) ? file.release() : NULL;
  215. }
  216. FileHandle
  217. XMLPlatformUtils::openFileToWrite(const char* const fileName)
  218. {
  219.     // Check to make sure the file system is in a state where we can use it
  220.     if (!gFileSystemCompatible)
  221.         ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
  222.     Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
  223.     return (file->open(fileName, true)) ? file.release() : NULL;
  224. }
  225. FileHandle
  226. XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName)
  227. {
  228.     // Check to make sure the file system is in a state where we can use it
  229.     if (!gFileSystemCompatible)
  230.         ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName);
  231.     Janitor<XMLMacAbstractFile> file(XMLMakeMacFile());
  232.     return (file->open(fileName, true)) ? file.release() : NULL;
  233. }
  234. FileHandle
  235. XMLPlatformUtils::openStdInHandle()
  236. {
  237.     XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull};
  238.     ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr);
  239.     return NULL;
  240. }
  241. unsigned int
  242. XMLPlatformUtils::readFileBuffer(   const FileHandle      theFile
  243.                                  ,  const unsigned int    toRead
  244.                                  ,        XMLByte* const  toFill)
  245. {
  246.     return reinterpret_cast<XMLMacAbstractFile*>(theFile)->read(toRead, toFill);
  247. }
  248. void
  249. XMLPlatformUtils::writeBufferToFile(   const   FileHandle   theFile
  250.                                     ,  const long     toWrite
  251.                                     ,  const XMLByte* const toFlush)
  252. {
  253.     return reinterpret_cast<XMLMacAbstractFile*>(theFile)->write(toWrite, toFlush);
  254. }
  255. void
  256. XMLPlatformUtils::resetFile(FileHandle theFile)
  257. {
  258.     reinterpret_cast<XMLMacAbstractFile*>(theFile)->reset();
  259. }
  260. // ---------------------------------------------------------------------------
  261. //  XMLPlatformUtils: File system methods
  262. // ---------------------------------------------------------------------------
  263. XMLCh*
  264. XMLPlatformUtils::getFullPath(const XMLCh* const srcPath,
  265.                               MemoryManager* const manager)
  266. {
  267.     XMLCh* path = NULL;
  268.     if (gHasHFSPlusAPIs)
  269.     {
  270.         FSRef ref;
  271.         if (   !XMLParsePathToFSRef(srcPath, ref, manager)
  272. || (path = XMLCreateFullPathFromFSRef(ref, manager)) == NULL
  273.    )
  274.             path = XMLString::replicate(srcPath, manager);
  275.     }
  276.     else
  277.     {
  278.         FSSpec spec;
  279.         if (   !XMLParsePathToFSSpec(srcPath, spec, manager)
  280.     || (path = XMLCreateFullPathFromFSSpec(spec, manager)) == NULL
  281.    )
  282.             path = XMLString::replicate(srcPath, manager);
  283.     }
  284.     return path;
  285. }
  286. bool
  287. XMLPlatformUtils::isRelative(const XMLCh* const toCheck)
  288. {
  289.     return (toCheck[0] != L'/');
  290. }
  291. XMLCh* XMLPlatformUtils::getCurrentDirectory(MemoryManager* const manager)
  292. {
  293. // Get a newly allocated path to the current directory
  294. FSSpec spec;
  295. XMLCh* path =
  296. (noErr == FSMakeFSSpec(0, 0, NULL, &spec))
  297. ? XMLCreateFullPathFromFSSpec(spec, manager)
  298. : NULL;
  299.     if (!path)
  300.  ThrowXML(XMLPlatformUtilsException,
  301.            XMLExcepts::File_CouldNotGetBasePathName);
  302.            
  303. return path;
  304. }
  305. inline bool XMLPlatformUtils::isAnySlash(XMLCh c) 
  306. {
  307. // We support only forward slash as a path delimiter
  308.     return (chForwardSlash == c);
  309. }
  310. // ---------------------------------------------------------------------------
  311. //  XMLPlatformUtils: Timing Methods
  312. // ---------------------------------------------------------------------------
  313. unsigned long
  314. XMLPlatformUtils::getCurrentMillis()
  315. {
  316. if ((void*)kUnresolvedCFragSymbolAddress != UpTime)
  317. {
  318. // Use Driver services routines, now in Carbon,
  319. // to get the elapsed milliseconds.
  320. AbsoluteTime time = UpTime();
  321. return AbsoluteToDuration(time);
  322. }
  323. else
  324. return TickCount() * 100 / 6;
  325. }
  326. // ---------------------------------------------------------------------------
  327. //  Mutex methods
  328. //
  329. // There are a number of choices for multi-threading on Mac OS. Traditionally
  330. // there was the Thread Manager, which provided cooperative multitasking on
  331. // 68K and PPC platforms, and preemptive multitasking on 68K platforms only.
  332. // The primary threading model supported under Carbon is the Multiprocessing
  333. // library, which as of version 2.0 provides a nice set of primitives. Under
  334. // Mac OS X, the Multiprocessing library is a thin veneer over pthreads.
  335. //
  336. // For lack of any really universal solutions, I've implemented these mutexes
  337. // atop the Multiprocessing library. The critical regions employed here
  338. // support recursive behavior, which is required by Xerces.
  339. //
  340. // Please note that, despite this implementation, there may be other barriers
  341. // to using Xerces in a multithreaded environment. The memory allocator
  342. // under Mac OS 9, for instance, is not thread safe.
  343. // ---------------------------------------------------------------------------
  344. void*
  345. XMLPlatformUtils::makeMutex()
  346. {
  347. if (gHasMPAPIs)
  348. {
  349. MPCriticalRegionID criticalRegion = NULL;
  350. OSStatus status = MPCreateCriticalRegion(&criticalRegion);
  351. return (status == noErr) ? (void*)(criticalRegion) : NULL;
  352. }
  353. else
  354. return (void*)1;
  355. }
  356. void
  357. XMLPlatformUtils::closeMutex(void* const mtxHandle)
  358. {
  359. if (gHasMPAPIs)
  360. {
  361. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  362. OSStatus status = MPDeleteCriticalRegion(criticalRegion);
  363. status = noErr; // ignore any error and zap compiler warning
  364. }
  365. else
  366. ;
  367. }
  368. void
  369. XMLPlatformUtils::lockMutex(void* const mtxHandle)
  370. {
  371. if (gHasMPAPIs)
  372. {
  373. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  374. OSStatus status = MPEnterCriticalRegion(criticalRegion, kDurationForever);
  375. status = noErr; // ignore any error and zap compiler warning
  376. }
  377. else
  378. ;
  379. }
  380. void
  381. XMLPlatformUtils::unlockMutex(void* const mtxHandle)
  382. {
  383. if (gHasMPAPIs)
  384. {
  385. MPCriticalRegionID criticalRegion = reinterpret_cast<MPCriticalRegionID>(mtxHandle);
  386. OSStatus status = MPExitCriticalRegion(criticalRegion);
  387. status = noErr; // ignore any error and zap compiler warning
  388. }
  389. else
  390. ;
  391. }
  392. // ---------------------------------------------------------------------------
  393. //  Miscellaneous synchronization methods
  394. //
  395. // Atomic manipulation is implemented atop routines that were traditionally
  396. // part of DriverServices, but are now a part of Carbon.
  397. // ---------------------------------------------------------------------------
  398. void*
  399. XMLPlatformUtils::compareAndSwap(       void**      toFill
  400.                                  , const void* const newValue
  401.                                  , const void* const toCompare)
  402. {
  403.     // Replace *toFill with newValue iff *toFill == toCompare,
  404.     // returning previous value of *toFill
  405.     Boolean success = CompareAndSwap(
  406.         reinterpret_cast<UInt32>(toCompare),
  407.         reinterpret_cast<UInt32>(newValue),
  408.         reinterpret_cast<UInt32*>(toFill));
  409.     return (success) ? const_cast<void*>(toCompare) : *toFill;
  410. }
  411. //
  412. // Atomic Increment and Decrement
  413. //
  414. // Apple's routines return the value as it was before the
  415. // operation, while these routines want to return it as it
  416. // is after. So we perform the translation before returning
  417. // the value.
  418. //
  419. int
  420. XMLPlatformUtils::atomicIncrement(int &location)
  421. {
  422.     return IncrementAtomic(reinterpret_cast<long*>(&location)) + 1;
  423. }
  424. int
  425. XMLPlatformUtils::atomicDecrement(int &location)
  426. {
  427.     return DecrementAtomic(reinterpret_cast<long*>(&location)) - 1;
  428. }
  429. // ---------------------------------------------------------------------------
  430. //  XMLPlatformUtils: Private Static Methods
  431. // ---------------------------------------------------------------------------
  432. //
  433. //  This method handles the MacOS basic init functions.
  434. //
  435. void
  436. XMLPlatformUtils::platformInit()
  437. {
  438. long value = 0;
  439. // Detect available functions
  440.     // Look for file system services
  441.     if (noErr == Gestalt(gestaltFSAttr, &value))
  442.     {
  443.         gHasFSSpecAPIs = (value & (1 << gestaltHasFSSpecCalls)) != 0;
  444.         gHasFS2TBAPIs = (value & (1 << gestaltFSSupports2TBVols)) != 0;
  445.         gHasHFSPlusAPIs = (value & (1 << gestaltHasHFSPlusAPIs)) != 0;
  446.         #if TARGET_API_MAC_CARBON
  447.         gHasFSPathAPIs = ((void*)kUnresolvedCFragSymbolAddress != FSPathMakeRef);
  448.         #else
  449.         gHasFSPathAPIs = false;
  450.         #endif
  451.         gPathAPIsUsePosixPaths = gHasFSPathAPIs
  452.  && (value & (1 << gestaltFSUsesPOSIXPathsForConversion));
  453.     }
  454. // We require FSSpecs at a minimum
  455.     gFileSystemCompatible = gHasFSSpecAPIs;
  456. // Determine which file system to use (posix or carbon file access)
  457. // If we're using Metrowerks MSL, we surely don't want posix paths,
  458. // as MSL doesn't use them.
  459. #if __MSL__ && (__MSL__ < 0x08000 || _MSL_CARBON_FILE_APIS)
  460. gUsePosixFiles = false;
  461. #else
  462. gUsePosixFiles = noErr == Gestalt(gestaltSystemVersion, &value)
  463.   && value >= 0x00001000
  464.   ;
  465. #endif
  466.     // Look for MP
  467. gHasMPAPIs = MPLibraryIsLoaded();
  468. }
  469. //
  470. //  This method handles the MacOS basic termination functions.
  471. //
  472. void
  473. XMLPlatformUtils::platformTerm()
  474. {
  475. }
  476. // ---------------------------------------------------------------------------
  477. //  XMLPlatformUtils: Private Static Methods
  478. // ---------------------------------------------------------------------------
  479. //
  480. //  This method is called by the platform independent part of this class
  481. //  during initialization. We have to create the type of net accessor that
  482. //  we want to use. If none, then just return zero.
  483. //
  484. XMLNetAccessor*
  485. XMLPlatformUtils::makeNetAccessor()
  486. {
  487.     // The selection of NetAcessor is made through
  488.     // the following preprocessor defines:
  489.     //
  490.     // XML_USE_NETACCESSOR_URLACCESS -- Use netaccessor based on URLAccess
  491.     // XML_USE_NETACCESSOR_URLACCESSCF -- Use netaccessor based on CFURLAccess (CoreFoundation based)
  492.     // XML_USE_NETACCESSOR_NATIVE -- In absence of above selections, chooses URLACCESSCF
  493.     //    if targetting Carbon, and URLAccess otherwise
  494.     //
  495.     // These choices are resolved at the ^^^top^^^ of this file.
  496. #if (defined(USE_URLACCESSCF))
  497.     // Use the URLAccess code that relies only on CoreFoundation
  498. return new MacOSURLAccessCF;
  499. #elif (defined(USE_URLACCESS))
  500. // Only try to use URLAccess if it's actually available
  501. if (URLAccessAvailable())
  502. return new MacOSURLAccess;
  503. #endif
  504. // No netaccessor available--we can live with it, but you won't
  505. // get net access.
  506. return 0;
  507. }
  508. //
  509. //  This method is called by the platform independent part of this class
  510. //  when client code asks to have one of the supported message sets loaded.
  511. //
  512. XMLMsgLoader*
  513. XMLPlatformUtils::loadAMsgSet(const XMLCh* const msgDomain)
  514. {
  515. #if (defined(XML_USE_INMEMORY_MSGLOADER) || defined(XML_USE_INMEM_MESSAGELOADER))
  516.     return new InMemMsgLoader(msgDomain);
  517. #else
  518.     #error You must provide a message loader
  519.     return 0;
  520. #endif
  521. }
  522. //
  523. //  This method is called very early in the bootstrapping process. This guy
  524. //  must create a transcoding service and return it. It cannot use any string
  525. //  methods, any transcoding services, throw any exceptions, etc... It just
  526. //  makes a transcoding service and returns it, or returns zero on failure.
  527. //
  528. XMLTransService*
  529. XMLPlatformUtils::makeTransService()
  530. {
  531. #if (defined(XML_USE_MACOS_UNICODECONVERTER) || defined(XML_USE_NATIVE_TRANSCODER))
  532.     if (MacOSUnicodeConverter::IsMacOSUnicodeConverterSupported())
  533.         return new MacOSUnicodeConverter;
  534. #else
  535.     #error You must provide a transcoding service implementation
  536. #endif
  537.     // If we got here it's because we didn't detect the Mac OS
  538.     // Unicode Converter or Text Encoding Converter routines
  539.     // that we require to function properly. Xerces will not
  540.     // survive this condition.
  541.     return NULL;
  542. }
  543. // ---------------------------------------------------------------------------
  544. // Utility Functions
  545. // ---------------------------------------------------------------------------
  546. XMLCh*
  547. CopyUniCharsToXMLChs(const UniChar* src, XMLCh* dst, std::size_t charCount, std::size_t maxChars)
  548. {
  549. // Ensure we don't step on anybody's toes
  550. std::size_t cnt = std::min(charCount, maxChars);
  551. // Copy the characters. UniChar is unsigned, so we shouldn't have
  552. // any sign extension problems.
  553. // To allow copy within a identical range, we copy backwards,
  554. // since XMLCh (may be) larger than UniChar.
  555. dst += cnt;
  556. src += cnt;
  557. for (; cnt > 0; --cnt)
  558. *--dst = *--src;
  559. return dst;
  560. }
  561. UniChar*
  562. CopyXMLChsToUniChars(const XMLCh* src, UniChar* dst, std::size_t charCount, std::size_t maxChars)
  563. {
  564. UniChar* dstBegin = dst;
  565. // Ensure we don't step on anybody's toes
  566. std::size_t cnt = std::min(charCount, maxChars);
  567. // Copy the characters. XMLCh's will be truncated on copy to UniChar's.
  568. // To allow copy within a identical range, we copy forwards,
  569. // since XMLCh (may be) larger than UniChar.
  570. for (; cnt > 0; --cnt)
  571. *dst++ = *src++;
  572. return dstBegin;
  573. }
  574. XMLCh*
  575. ConvertColonToSlash(XMLCh* p, std::size_t charCount)
  576. {
  577. XMLCh* start = p;
  578. for (; charCount > 0; --charCount)
  579. {
  580. XMLCh c = *p;
  581. if (c == ':')
  582. *p++ = '/';
  583. else
  584. p++;
  585. }
  586. return start;
  587. }
  588. XMLCh*
  589. ConvertSlashToColon(XMLCh* p, std::size_t charCount)
  590. {
  591. XMLCh* start = p;
  592. for (; charCount > 0; --charCount)
  593. {
  594. XMLCh c = *p;
  595. if (c == '/')
  596. *p++ = ':';
  597. else
  598. p++;
  599. }
  600. return start;
  601. }
  602. char*
  603. ConvertSlashToColon(char* p, std::size_t charCount)
  604. {
  605. char* start = p;
  606. for (; charCount > 0; --charCount)
  607. {
  608. char c = *p;
  609. if (c == '/')
  610. *p++ = ':';
  611. else
  612. p++;
  613. }
  614. return start;
  615. }
  616. // Factory method to make an appropriate subclass of XMLMacAbstractFile
  617. // for our use
  618. XMLMacAbstractFile*
  619. XMLMakeMacFile(void)
  620. {
  621. XMLMacAbstractFile* result = NULL;
  622. if (gUsePosixFiles)
  623. result = new XMLMacPosixFile;
  624. else
  625. result = new XMLMacCarbonFile;
  626. return result;
  627. }
  628. bool
  629. XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
  630. {
  631. bool result;
  632. // If FSPathMakeRef is available, we use it to parse the
  633. // path: this gives us "standard" path support under MacOS X.
  634. // Without this, our paths in that environment would always
  635. // have a volume name at their root...which would look
  636. // "normal" to Mac users, but not normal to unix users. Since
  637. // we're making "unix" paths, we'll stick with the unix
  638. // style paths. This also allows us to easilly take paths
  639. // off the command line.
  640. //
  641. // FSPathMakeRef is available on Mac OS X and in CarbonLib 1.1
  642. // and greater. But on classic under CarbonLib, it expects paths
  643. // to contain ':' separators, for which we're not prepared. Since
  644. // this isn't a case where we need to use it, we drop back to the
  645. // classic case for this.
  646. if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths)
  647. result = XMLParsePathToFSRef_X(pathName, ref, manager);
  648. else
  649. result = XMLParsePathToFSRef_Classic(pathName, ref, manager);
  650. return result;
  651. }
  652. bool
  653. XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
  654. {
  655. // Parse Path to FSRef using FSPathMakeRef as available under
  656. // Mac OS X and CarbonLib 1.1 and greater.
  657. OSStatus err = noErr;
  658. std::size_t pathLen = XMLString::stringLen(pathName);
  659.     // Transcode XMLCh into UniChar
  660. UniChar uniBuf[kMaxMacStaticPathChars];
  661. CopyXMLChsToUniChars(pathName, uniBuf, pathLen, kMaxMacStaticPathChars);
  662. // Transcode Unicode to UTF-8
  663. char utf8Buf[kMaxMacStaticPathChars];
  664. pathLen = TranscodeUniCharsToUTF8(uniBuf, utf8Buf, pathLen, kMaxMacStaticPathChars-1);
  665. // Terminate the path
  666. char* p = utf8Buf;
  667. p[pathLen++] = '';
  668. // If it's a relative path, pre-pend the current directory to the path.
  669. // FSPathMakeRef doesn't deal with relativity on the front of the path
  670. if (*p != '/')
  671. {
  672. // Right justify the user path to make room for the pre-pended path
  673. std::memmove(p + kMaxMacStaticPathChars - pathLen, p, pathLen);
  674. // Get the current directory
  675.         FSSpec spec;
  676. if (err == noErr)
  677. err = FSMakeFSSpec(0, 0, NULL, &spec);
  678.         if (err == noErr)
  679.             err = FSpMakeFSRef(&spec, &ref);
  680. // Get pathname to the current directory
  681. if (err == noErr)
  682. err = FSRefMakePath(&ref, reinterpret_cast<UInt8*>(p), kMaxMacStaticPathChars - pathLen - 1); // leave room for one '/'
  683. std::size_t prefixLen = std::strlen(p);
  684. // Now munge the two paths back together
  685. if (err == noErr)
  686. {
  687. p[prefixLen++] = '/';
  688. std::memmove(p + prefixLen, p + kMaxMacStaticPathChars - pathLen, pathLen);
  689. }
  690. // We now have a path from an absolute starting point
  691. }
  692. // Let the OS discover the location
  693. Boolean isDirectory = false;
  694. if (err == noErr)
  695. err = FSPathMakeRef(reinterpret_cast<UInt8*>(p), &ref, &isDirectory);
  696. // Return true on success
  697. return (err == noErr);
  698. }
  699. bool
  700. XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager)
  701. {
  702. // Parse Path to FSRef by stepping manually through path components.
  703. // Path's parsed in this way must always begin with a volume name.
  704. // This assumption would fail for standard unix paths under Mac OS X,
  705. // so for those cases we use the routine XMLParsePathToFSRef_Carbon
  706. // above.
  707.     const XMLCh* p = pathName;
  708.     const XMLCh* pEnd;
  709.     std::size_t segLen;
  710. const std::size_t kXMLBufCount = 256;
  711. XMLCh xmlBuf[kXMLBufCount];
  712.     OSErr err = noErr;
  713.     if (*p == L'/')
  714.     {
  715.         // Absolute name: grab the first component as volume name
  716.         // Find the end of the path segment
  717.         for (pEnd = ++p; *pEnd && *pEnd != L'/'; ++pEnd) ;
  718.         segLen = pEnd - p;
  719.         // Try to find a volume that matches this name
  720.         for (ItemCount volIndex = 1; err == noErr; ++volIndex)
  721.         {
  722.             HFSUniStr255 hfsStr;
  723.             hfsStr.length = 0;
  724.             // Get the volume name
  725.             err = FSGetVolumeInfo(
  726.                 0,
  727.                 volIndex,
  728.                 static_cast<FSVolumeRefNum*>(NULL),
  729.                 0,
  730.                 static_cast<FSVolumeInfo*>(NULL),
  731.                 &hfsStr,
  732.                 &ref
  733.                 );
  734.             // Compare against our path segment
  735.             if (err == noErr && segLen == hfsStr.length)
  736.             {
  737.              // Case-insensitive compare
  738.              if (XMLString::compareNIString(
  739. ConvertSlashToColon(
  740. CopyUniCharsToXMLChs(hfsStr.unicode, xmlBuf, segLen, kXMLBufCount),
  741. segLen),
  742. p, segLen) == 0)
  743.                     break;  // we found our volume
  744.             }
  745.         }
  746.         p = pEnd;
  747.     }
  748.     else
  749.     {
  750.         // Relative name, so get the default directory as parent ref
  751.         FSSpec spec;
  752.         err = FSMakeFSSpec(0, 0, NULL, &spec);
  753.         if (err == noErr)
  754.             err = FSpMakeFSRef(&spec, &ref);
  755.     }
  756.     // ref now refers to the a parent directory: parse the rest of the path
  757.     while (err == noErr && *p)
  758.     {
  759.         switch (*p)
  760.         {
  761.         case L'/':   // Just skip any number of path separators
  762.             ++p;
  763.             break;
  764.         case L'.':   // Potentially "current directory" or "parent directory"
  765.             if (p[1] == L'/' || p[1] == 0)       // "current directory"
  766.             {
  767.                 ++p;
  768.                 break;
  769.             }
  770.             else if (p[1] == L'.' && (p[2] == L'/' || p[2] == 0)) // "parent directory"
  771.             {
  772.                 p += 2;  // Get the parent of our parent
  773.                 FSCatalogInfo catalogInfo;
  774.                 err = FSGetCatalogInfo(
  775.                     &ref,
  776.                     kFSCatInfoParentDirID,
  777.                     &catalogInfo,
  778.                     static_cast<HFSUniStr255*>(NULL),
  779.                     static_cast<FSSpec*>(NULL),
  780.                     &ref
  781.                     );
  782.                 // Check that we didn't go too far
  783.                 if (err != noErr || catalogInfo.parentDirID == fsRtParID)
  784.                     return false;
  785.                 break;
  786.             }
  787.             else // some other sequence of periods...fall through and treat as segment
  788.                 ;
  789.         default:
  790.             // Find the end of the path segment
  791.             for (pEnd = p; *pEnd && *pEnd != L'/'; ++pEnd) ;
  792.             segLen = pEnd - p;
  793.             // pEnd now points either to '/' or NUL
  794.             // Create a new ref using this path segment
  795.             err = FSMakeFSRefUnicode(
  796.                 &ref,
  797.                 segLen,
  798.                 ConvertColonToSlash(
  799.                  CopyXMLChsToUniChars(p, reinterpret_cast<UniChar*>(xmlBuf), segLen, kXMLBufCount),
  800.                  segLen),
  801.                 kTextEncodingUnknown,
  802.                 &ref
  803.                 );
  804.             p = pEnd;
  805.             break;
  806.         }
  807.     }
  808.     return err == noErr;
  809. }
  810. bool
  811. XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec,
  812.                             MemoryManager* const manager)
  813. {
  814. // Parse Path to an FSSpec
  815. // If we've got HFS+ APIs, do this in terms of refs so that
  816. // we can grandfather in the use of FSPathMakeRef under Mac OS X
  817. // and CarbonLib 1.1. Otherwise, do it the hard way.
  818. bool result = false;
  819. if (gHasHFSPlusAPIs)
  820. {
  821. // Parse to a ref
  822. FSRef ref;
  823. result = XMLParsePathToFSRef(pathName, ref, manager);
  824. // Down convert to a spec
  825. if (result)
  826. result = (noErr == FSGetCatalogInfo(&ref,
  827. kFSCatInfoNone,
  828. static_cast<FSCatalogInfo*>(NULL), // catalogInfo
  829. static_cast<HFSUniStr255*>(NULL), // outName
  830. &spec,
  831. static_cast<FSRef*>(NULL) // parentRef
  832. ));
  833. }
  834. else
  835. result = XMLParsePathToFSSpec_Classic(pathName, spec, manager);
  836. // Return true on success
  837. return result;
  838. }
  839. bool
  840. XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec,
  841.                             MemoryManager* const manager)
  842. {
  843. // Manually parse the path using FSSpec APIs.
  844.     // Transcode the path into ascii
  845.     const char* p = XMLString::transcode(pathName, manager);
  846.     ArrayJanitor<const char> janPath(p, manager);
  847.     const char* pEnd;
  848.     std::size_t segLen;
  849.     OSStatus err = noErr;
  850.     Str255 name;  // Must be long enough for a partial pathname consisting of two segments (64 bytes)
  851.     if (*p == '/')
  852.     {
  853.         // Absolute name: grab the first component as volume name
  854.         // Find the end of the path segment
  855.         for (pEnd = ++p; *pEnd && *pEnd != '/'; ++pEnd) ;
  856.         segLen = pEnd - p;
  857.         // Try to find a volume that matches this name
  858.         for (ItemCount volIndex = 1; err == noErr; ++volIndex)
  859.         {
  860.             FSVolumeRefNum volRefNum;
  861.             if (gHasFS2TBAPIs)
  862.             {
  863.                 XVolumeParam xVolParam;
  864.                 name[0] = 0;
  865.                 xVolParam.ioNamePtr  = name;
  866.                 xVolParam.ioVRefNum  = 0;
  867.                 xVolParam.ioXVersion = 0;
  868.                 xVolParam.ioVolIndex = volIndex;
  869.                 err = PBXGetVolInfoSync(&xVolParam);
  870.                 volRefNum = xVolParam.ioVRefNum;
  871.             }
  872.             else
  873.             {
  874. #if !TARGET_API_MAC_CARBON
  875.                 HParamBlockRec hfsParams;
  876.                 name[0] = 0;
  877.                 hfsParams.volumeParam.ioNamePtr  = name;
  878.                 hfsParams.volumeParam.ioVRefNum  = 0;
  879.                 hfsParams.volumeParam.ioVolIndex = volIndex;
  880.                 err = PBHGetVInfoSync(&hfsParams);
  881.                 volRefNum = hfsParams.volumeParam.ioVRefNum;
  882. #else
  883.                 err = nsvErr;
  884. #endif
  885.             }
  886.             // Compare against our path segment
  887.             if (err == noErr && segLen == StrLength(name))
  888.             {
  889.              // Case-insensitive compare
  890.              if (XMLString::compareNIString(
  891.              ConvertSlashToColon(reinterpret_cast<char*>(&name[1]), segLen),
  892.              p, segLen) == 0)
  893.                 {
  894.                     // we found our volume: fill in the spec
  895.                     err = FSMakeFSSpec(volRefNum, fsRtDirID, NULL, &spec);
  896.                     break;
  897.                 }
  898.             }
  899.         }
  900.         p = pEnd;
  901.     }
  902.     else
  903.     {
  904.         // Relative name, so get the default directory as parent spec
  905.         err = FSMakeFSSpec(0, 0, NULL, &spec);
  906.     }
  907.     // We now have a parent directory in the spec.
  908.     while (err == noErr && *p)
  909.     {
  910.         switch (*p)
  911.         {
  912.         case '/':  // Just skip any number of path separators
  913.             ++p;
  914.             break;
  915.         case L'.':  // Potentially "current directory" or "parent directory"
  916.             if (p[1] == '/' || p[1] == 0)      // "current directory"
  917.             {
  918.                 ++p;
  919.                 break;
  920.             }
  921.             else if (p[1] == '.' && (p[2] == '/' || p[2] == 0)) // "parent directory"
  922.             {
  923.                 p += 2;  // Get the parent of our parent
  924.                 CInfoPBRec catInfo;
  925.                 catInfo.dirInfo.ioNamePtr = NULL;
  926.                 catInfo.dirInfo.ioVRefNum = spec.vRefNum;
  927.                 catInfo.dirInfo.ioFDirIndex = -1;
  928.                 catInfo.dirInfo.ioDrDirID = spec.parID;
  929.                 err = PBGetCatInfoSync(&catInfo);
  930.                 // Check that we didn't go too far
  931.                 if (err != noErr || catInfo.dirInfo.ioDrParID == fsRtParID)
  932.                     return false;
  933.                 // Update our spec
  934.                 if (err == noErr)
  935.                     err = FSMakeFSSpec(spec.vRefNum, catInfo.dirInfo.ioDrDirID, NULL, &spec);
  936.                 break;
  937.             }
  938.             else // some other sequence of periods...fall through and treat as segment
  939.                 ;
  940.         default:
  941.             {
  942.                 // Find the end of the path segment
  943.                 for (pEnd = p; *pEnd && *pEnd != '/'; ++pEnd) ;
  944.                 segLen = pEnd - p;
  945.                 // Check for name length overflow
  946.                 if (segLen > 31)
  947.                     return false;
  948.                 // Make a partial pathname from our current spec to the new object
  949.                 unsigned char* partial = &name[1];
  950.                 *partial++ = ':';       // Partial leads with :
  951.                 const unsigned char* specName = spec.name; // Copy in spec name
  952.                 for (int specCnt = *specName++; specCnt > 0; --specCnt)
  953.                     *partial++ = *specName++;
  954.                 *partial++ = ':';       // Separator
  955.                 while (p != pEnd)       // Copy in new element
  956.                 {
  957.                  if (*p == ':') // Convert : to /
  958.                  {
  959.                  *partial++ = '/';
  960.                  p++;
  961.                  }
  962.                  else
  963.                  *partial++ = *p++;
  964. }
  965.                 name[0] = partial - &name[1];   // Set the name length
  966.                 // Update the spec
  967.                 err = FSMakeFSSpec(spec.vRefNum, spec.parID, name, &spec);
  968.             }
  969.             break;
  970.         }
  971.     }
  972.     return err == noErr;
  973. }
  974. XMLCh*
  975. XMLCreateFullPathFromFSRef(const FSRef& startingRef,
  976.                             MemoryManager* const manager)
  977. {
  978. XMLCh* result = NULL;
  979. // If FSRefMakePath is available, we use it to create the
  980. // path: this gives us "standard" path support under MacOS X.
  981. // Without this, our paths in that environment would always
  982. // have a volume name at their root...which would look
  983. // "normal" to Mac users, but not normal to unix users. Since
  984. // we're making "unix" paths, we'll stick with the unix
  985. // style paths. This also allows us to easilly take paths
  986. // off the command line.
  987. //
  988. // FSRefMakePath is available on Mac OS X and in CarbonLib 1.1
  989. // and greater. But we use it only on X since on Classic it
  990. // makes paths with ':' separators, which really confuses us!
  991. if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths)
  992. result = XMLCreateFullPathFromFSRef_X(startingRef, manager);
  993. else
  994. result = XMLCreateFullPathFromFSRef_Classic(startingRef, manager);
  995. return result;
  996. }
  997. XMLCh*
  998. XMLCreateFullPathFromFSRef_X(const FSRef& startingRef,
  999.                             MemoryManager* const manager)
  1000. {
  1001. // Create the path using FSRefMakePath as available on Mac OS X
  1002. // and under CarbonLib 1.1 and greater.
  1003. OSStatus err = noErr;
  1004. // Make the path in utf8 form
  1005. char utf8Buf[kMaxMacStaticPathChars];
  1006. utf8Buf[0] = '';
  1007. if (err == noErr)
  1008. err = FSRefMakePath(&startingRef, reinterpret_cast<UInt8*>(utf8Buf), kMaxMacStaticPathChars);
  1009. // Bail if path conversion failed
  1010. if (err != noErr)
  1011. return NULL;
  1012. // Transcode into UniChars
  1013. UniChar uniBuf[kMaxMacStaticPathChars];
  1014. std::size_t pathLen = TranscodeUTF8ToUniChars(utf8Buf, uniBuf, kMaxMacStaticPathChars-1);
  1015. uniBuf[pathLen++] = 0;
  1016. // Transcode into a dynamically allocated buffer of XMLChs
  1017. ArrayJanitor<XMLCh> result((XMLCh*) manager->allocate(pathLen * sizeof(XMLCh))/*new XMLCh[pathLen]*/,
  1018. manager);
  1019. if (result.get() != NULL)
  1020. CopyUniCharsToXMLChs(uniBuf, result.get(), pathLen, pathLen);
  1021. return result.release();
  1022. }
  1023. XMLCh*
  1024. XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef,
  1025.                             MemoryManager* const manager)
  1026. {
  1027. // Manually create the path using FSRef APIs.
  1028.     OSStatus err = noErr;
  1029.     FSCatalogInfo catalogInfo;
  1030.     HFSUniStr255 name;
  1031.     FSRef ref = startingRef;
  1032.     XMLCh buf[kMaxMacStaticPathChars];
  1033.     std::size_t bufPos   = kMaxMacStaticPathChars;
  1034.     std::size_t bufCnt   = 0;
  1035.     ArrayJanitor<XMLCh> result(NULL);
  1036.     std::size_t resultLen = 0;
  1037.     buf[--bufPos] = L'';
  1038.     ++bufCnt;
  1039. do
  1040. {
  1041. err = FSGetCatalogInfo(
  1042. &ref,
  1043. kFSCatInfoParentDirID,
  1044. &catalogInfo,
  1045. &name,
  1046. static_cast<FSSpec*>(NULL),
  1047. &ref
  1048. );
  1049. if (err == noErr)
  1050. {
  1051. // If there's not room in our static buffer for the new
  1052. // name plus separator, dump it to the dynamic result buffer.
  1053. if (bufPos < (std::size_t)name.length + 1)
  1054. {
  1055. ArrayJanitor<XMLCh> temp
  1056.                 (
  1057.                     (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh)) //new XMLCh[bufCnt + resultLen]
  1058.                     , manager
  1059.                 );
  1060. // Copy in the static buffer
  1061. std::memcpy(temp.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
  1062. // Copy in the old buffer
  1063. if (resultLen > 0)
  1064. std::memcpy(temp.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
  1065. result.reset(temp.release());
  1066. resultLen += bufCnt;
  1067. bufPos = kMaxMacStaticPathChars;
  1068. bufCnt = 0;
  1069. }
  1070. // Prepend our new name and a '/'
  1071. bufPos -= name.length;
  1072. ConvertSlashToColon(
  1073. CopyUniCharsToXMLChs(name.unicode, &buf[bufPos], name.length, name.length),
  1074. name.length);
  1075. buf[--bufPos] = L'/';
  1076. bufCnt += (name.length + 1);
  1077. }
  1078. }
  1079. while (err == noErr && catalogInfo.parentDirID != fsRtParID);
  1080. // Composite existing buffer + any previous result buffer
  1081. ArrayJanitor<XMLCh> final
  1082.     (
  1083.         (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh))//new XMLCh[bufCnt + resultLen]
  1084.         , manager
  1085.     );
  1086. // Copy in the static buffer
  1087. std::memcpy(final.get(), &buf[bufPos], bufCnt * sizeof(XMLCh));
  1088. // Copy in the old buffer
  1089. if (resultLen > 0)
  1090. std::memcpy(final.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh));
  1091.     return final.release();
  1092. }
  1093. XMLCh*
  1094. XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec,
  1095.                             MemoryManager* const manager)
  1096. {
  1097. XMLCh* result = NULL;
  1098. // If FSRefs are available, do this operation in terms of refs...this
  1099. // allows us to grandfather in the use of FSPathMakeRef and FSRefMakePath
  1100. // if possible.
  1101. if (gHasHFSPlusAPIs)
  1102. {
  1103. OSStatus err = noErr;
  1104. FSRef ref;
  1105. // Up convert to FSRef
  1106. if (err == noErr)
  1107. err = FSpMakeFSRef(&startingSpec, &ref);
  1108. // Create the path
  1109. if (err == noErr)
  1110. result = XMLCreateFullPathFromFSRef(ref, manager);
  1111. }
  1112. else
  1113. {
  1114. // Create using FSSpecs only
  1115. result = XMLCreateFullPathFromFSSpec_Classic(startingSpec, manager);
  1116. }
  1117. return result;
  1118. }
  1119. XMLCh*
  1120. XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec,
  1121.                                     MemoryManager* const manager)
  1122. {
  1123. // Manually create the path using FSSpec APIs.
  1124.     OSStatus err = noErr;
  1125.     FSSpec spec = startingSpec;
  1126.     char buf[kMaxMacStaticPathChars];
  1127.     std::size_t bufPos   = kMaxMacStaticPathChars;
  1128.     std::size_t bufCnt   = 0;
  1129.     ArrayJanitor<char> result(NULL);
  1130.     std::size_t resultLen = 0;
  1131.     buf[--bufPos] = '';
  1132.     ++bufCnt;
  1133. short index = 0;
  1134. do
  1135. {
  1136. CInfoPBRec catInfo;
  1137. catInfo.dirInfo.ioNamePtr = spec.name;
  1138. catInfo.dirInfo.ioVRefNum = spec.vRefNum;
  1139. catInfo.dirInfo.ioFDirIndex = index;
  1140. catInfo.dirInfo.ioDrDirID = spec.parID;
  1141. err = PBGetCatInfoSync(&catInfo);
  1142. if (err == noErr)
  1143. {
  1144. std::size_t nameLen = StrLength(spec.name);
  1145. // If there's not room in our static buffer for the new
  1146. // name plus separator, dump it to the dynamic result buffer.
  1147. if (bufPos < nameLen + 1)
  1148. {
  1149. ArrayJanitor<char> temp
  1150.                 (
  1151.                     (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen]
  1152.                     , manager
  1153.                 );
  1154. // Copy in the static buffer
  1155. std::memcpy(temp.get(), &buf[bufPos], bufCnt);
  1156. // Copy in the old buffer
  1157. if (resultLen > 0)
  1158. std::memcpy(temp.get() + bufCnt, result.get(), resultLen);
  1159. result.reset(temp.release());
  1160. resultLen += bufCnt;
  1161. bufPos = kMaxMacStaticPathChars;
  1162. bufCnt = 0;
  1163. }
  1164. // Prepend our new name and a '/'
  1165. bufPos -= nameLen;
  1166. ConvertSlashToColon((char*)std::memcpy(&buf[bufPos], &spec.name[1], nameLen), nameLen);
  1167. buf[--bufPos] = '/';
  1168. bufCnt += (nameLen + 1);
  1169. // From here on out, ignore the input file name
  1170. index = -1;
  1171. // Move up to the parent
  1172. spec.parID = catInfo.dirInfo.ioDrParID;
  1173. }
  1174. }
  1175. while (err == noErr && spec.parID != fsRtParID);
  1176. // Composite existing buffer with any previous result buffer
  1177. ArrayJanitor<char> final
  1178.     (
  1179.         (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen]
  1180.         , manager
  1181.     );
  1182. // Copy in the static buffer
  1183. std::memcpy(final.get(), &buf[bufPos], bufCnt);
  1184. // Copy in the old buffer
  1185. if (resultLen > 0)
  1186. std::memcpy(final.get() + bufCnt, result.get(), resultLen);
  1187.     // Cleanup and transcode to unicode
  1188.     return XMLString::transcode(final.get(), manager);
  1189. }
  1190. std::size_t
  1191. TranscodeUniCharsToUTF8(const UniChar* src, char* dst, std::size_t srcCnt, std::size_t maxChars)
  1192. {
  1193. std::size_t result = 0;
  1194.     // Use the text encoding converter to perform the format conversion.
  1195.     // Note that this is slightly heavyweight, but we're not in a performance
  1196.     // sensitive code-path.
  1197.     OSStatus err = noErr;
  1198.     TECObjectRef tec = 0;
  1199.     ByteCount bytesConsumed = 0;
  1200.     ByteCount bytesProduced = 0;
  1201.     TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1202.                                         kTextEncodingDefaultVariant,
  1203.                                         kUnicode16BitFormat);
  1204.     TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1205.                                         kTextEncodingDefaultVariant,
  1206.                                         kUnicodeUTF8Format);
  1207.     if (err == noErr)
  1208.         err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
  1209.     if (err == noErr)
  1210.         err = TECConvertText(tec,
  1211.                     (ConstTextPtr) src,
  1212.                     srcCnt * sizeof(UniChar), // inputBufferLength
  1213.                     &bytesConsumed, // actualInputLength
  1214.                     (TextPtr) dst, // outputBuffer
  1215.                     maxChars * sizeof(char), // outputBufferLength
  1216.                     &bytesProduced); // actualOutputLength
  1217.     TECDisposeConverter(tec);
  1218.     result = bytesProduced;
  1219.     // Return number of chars in dst
  1220. return result;
  1221. }
  1222. std::size_t
  1223. TranscodeUTF8ToUniChars(const char* src, UniChar* dst, std::size_t maxChars)
  1224. {
  1225. std::size_t result = 0;
  1226.     // Use the text encoding converter to perform the format conversion.
  1227.     // Note that this is slightly heavyweight, but we're not in a performance
  1228.     // sensitive code-path.
  1229.     OSStatus err = noErr;
  1230.     TECObjectRef tec = 0;
  1231.     ByteCount bytesConsumed = 0;
  1232.     ByteCount bytesProduced = 0;
  1233.     TextEncoding inputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1234.                                         kTextEncodingDefaultVariant,
  1235.                                         kUnicodeUTF8Format);
  1236.     TextEncoding outputEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
  1237.                                         kTextEncodingDefaultVariant,
  1238.                                         kUnicode16BitFormat);
  1239.     if (err == noErr)
  1240.         err = TECCreateConverter(&tec, inputEncoding, outputEncoding);
  1241.     if (err == noErr)
  1242.         err = TECConvertText(tec,
  1243.                     (ConstTextPtr) src,
  1244.                     std::strlen(src), // inputBufferLength
  1245.                     &bytesConsumed, // actualInputLength
  1246.                     (TextPtr) dst, // outputBuffer
  1247.                     maxChars * sizeof(UniChar), // outputBufferLength
  1248.                     &bytesProduced); // actualOutputLength
  1249.     TECDisposeConverter(tec);
  1250.     result = bytesProduced / sizeof(UniChar);
  1251.     // Return number of unicode characters in dst
  1252. return result;
  1253. }
  1254. #include <xercesc/util/LogicalPath.c>
  1255. XERCES_CPP_NAMESPACE_END