/* * Copyright 1999-2000,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: MacCarbonFile.cpp 176026 2004-09-08 13:57:07Z peiyongz $ */ #include #include #include #include #if defined(__APPLE__) // Include from Frameworks Headers under ProjectBuilder #include #else // Classic include styles #include #include #endif XERCES_CPP_NAMESPACE_BEGIN //---------------------------------------------------------------------------- // XMLMacCarbonFile methods //---------------------------------------------------------------------------- unsigned int XMLMacCarbonFile::currPos() { OSErr err = noErr; unsigned int pos = 0; if (!mFileValid) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos); if (gHasHFSPlusAPIs) { SInt64 bigPos = 0; err = FSGetForkPosition(mFileRefNum, &bigPos); if (err == noErr) pos = bigPos; } else { long longPos; err = GetFPos(mFileRefNum, &longPos); if (err == noErr) pos = longPos; } if (err != noErr) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos); return pos; } void XMLMacCarbonFile::close() { OSErr err = noErr; if (!mFileValid) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile); if (gHasHFSPlusAPIs) err = FSCloseFork(mFileRefNum); else err = FSClose(mFileRefNum); mFileValid = false; if (err != noErr) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile); } unsigned int XMLMacCarbonFile::size() { OSErr err = noErr; unsigned int len = 0; if (!mFileValid) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize); if (gHasHFSPlusAPIs) { SInt64 bigLen = 0; err = FSGetForkSize(mFileRefNum, &bigLen); if (err == noErr) len = bigLen; } else { long longLen; err = GetEOF(mFileRefNum, &longLen); if (err == noErr) len = longLen; } if (err != noErr) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize); return len; } bool XMLMacCarbonFile::openWithPermission(const XMLCh* const fileName, int macPermission) { OSErr err = noErr; if (mFileValid) ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName); if (gHasHFSPlusAPIs) { FSRef ref; if (!XMLParsePathToFSRef(fileName, ref)) err = fnfErr; HFSUniStr255 forkName; if (err == noErr) err = FSGetDataForkName(&forkName); if (err == noErr) err = FSOpenFork(&ref, forkName.length, forkName.unicode, macPermission, &mFileRefNum); } else { FSSpec spec; if (!XMLParsePathToFSSpec(fileName, spec)) err = fnfErr; if (err == noErr) err = FSpOpenDF(&spec, macPermission, &mFileRefNum); } if (err != noErr) ThrowXML1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, fileName); mFileValid = true; return mFileValid; } void XMLMacCarbonFile::create(const XMLCh* const filePath) { OSErr err = noErr; // Split path into directory and filename components int posSlash = XMLString::lastIndexOf(filePath, '/', XMLString::stringLen(filePath) - 1); int posName = (posSlash == -1) ? 0 : posSlash+1; const XMLCh* namePtr = filePath + posName; int nameLen = XMLString::stringLen(namePtr); // Make a temporary string of the directory ArrayJanitor dirPath(new XMLCh[namePtr - filePath + 1]); XMLString::subString(dirPath.get(), filePath, 0, posName); // Create the file as appropriate for API set if (gHasHFSPlusAPIs) { // HFS+ FSRef ref; // If we find an existing file, delete it if (XMLParsePathToFSRef(filePath, ref)) FSDeleteObject(&ref); // Get a ref to the parent directory if (!XMLParsePathToFSRef(dirPath.get(), ref)) err = fnfErr; // Create a new file using the unicode name if (err == noErr) { UniChar uniName[256]; err = FSCreateFileUnicode( &ref, nameLen, CopyXMLChsToUniChars(namePtr, uniName, nameLen, sizeof(uniName)), 0, NULL, NULL, NULL); } } else { // HFS FSSpec spec; // If we find an existing file, delete it if (XMLParsePathToFSSpec(filePath, spec)) FSpDelete(&spec); // Get a spec to the parent directory if (!XMLParsePathToFSSpec(dirPath.get(), spec)) err = fnfErr; // Check that the new name is not too long for HFS if (err == noErr && nameLen > 31) err = errFSNameTooLong; if (err == noErr) { // Transcode the unicode name to native encoding ArrayJanitor nativeName(XMLString::transcode(namePtr)); // Make a partial pathname from our current spec (parent directory) to the new file unsigned char name[31 * 2 + 1 * 2 + 1]; unsigned char* partial = &name[1]; *partial++ = ':'; // Partial leads with : const unsigned char* specName = spec.name; // Copy in spec name for (int specCnt = *specName++; specCnt > 0; --specCnt) *partial++ = *specName++; *partial++ = ':'; // Path component separator char c; for (const char* p = nativeName.get(); (c = *p++) != 0; ) // Copy in new element *partial++ = (c == ':') ? '/' : c; // Convert : to / name[0] = partial - &name[1]; // Set the pascal string name length // Update the spec: this will probably return fnfErr // (since we just deleted any existing file) err = FSMakeFSSpec(spec.vRefNum, spec.parID, name, &spec); // Create the file from the spec err = FSpCreate(&spec, '??\??', 'TEXT', smSystemScript); } } // Fail if we didn't create the file if (err != noErr) { ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile); //ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile); } } bool XMLMacCarbonFile::open(const XMLCh* const path, bool toWrite) { bool success = false; if (toWrite) { create(path); success = openWithPermission(path, fsRdWrPerm); } else { success = openWithPermission(path, fsRdPerm); } return success; } bool XMLMacCarbonFile::open(const char* fileName, bool toWrite) { // Transcode the input filename from UTF8 into UTF16 UniChar uniBuf[kMaxMacStaticPathChars]; std::size_t pathLen = TranscodeUTF8ToUniChars(fileName, uniBuf, kMaxMacStaticPathChars-1); uniBuf[pathLen++] = 0; // Call through to the unicode open routine return open(uniBuf, toWrite); } unsigned int XMLMacCarbonFile::read(const unsigned int toRead, XMLByte* const toFill) { unsigned int bytesRead = 0; OSErr err = noErr; if (!mFileValid) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile); if (gHasHFSPlusAPIs) { ByteCount actualCount; err = FSReadFork(mFileRefNum, fsFromMark, 0, toRead, toFill, &actualCount); bytesRead = actualCount; } else { long byteCount = toRead; err = FSRead(mFileRefNum, &byteCount, toFill); bytesRead = byteCount; } if (err != noErr && err != eofErr) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile); return bytesRead; } void XMLMacCarbonFile::write(const long byteCount, const XMLByte* const buffer) { long bytesWritten = 0; OSErr err = noErr; if (byteCount <= 0 || buffer == NULL) return; if (!mFileValid) { ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile); } if (gHasHFSPlusAPIs) { ByteCount actualCount; err = FSWriteFork(mFileRefNum, fsFromMark, 0, byteCount, buffer, &actualCount); bytesWritten = actualCount; } else { long count = byteCount; err = FSWrite(mFileRefNum, &count, buffer); bytesWritten = count; } if ((err != noErr && err != eofErr) || (bytesWritten != byteCount)) { ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile); } } void XMLMacCarbonFile::reset() { OSErr err = noErr; if (!mFileValid) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile); if (gHasHFSPlusAPIs) err = FSSetForkPosition(mFileRefNum, fsFromStart, 0); else err = SetFPos(mFileRefNum, fsFromStart, 0); if (err != noErr) ThrowXML(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile); } XMLMacCarbonFile::~XMLMacCarbonFile() { if (mFileValid) close(); } XERCES_CPP_NAMESPACE_END