/* * 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: URLAccessBinInputStream.cpp 176026 2004-09-08 13:57:07Z peiyongz $ */ #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN URLAccessBinInputStream::URLAccessBinInputStream(const XMLURL& urlSource) : mBytesProcessed(0), mURLReference(NULL), mBuffer(NULL), mBufPos(NULL), mBufAvailable(0) { OSStatus status = noErr; // Get the full URL from the source char* url = XMLString::transcode(urlSource.getURLText(), urlSource.getMemoryManager()); ArrayJanitor janBuf(url, urlSource.getMemoryManager()); // Create a URL reference from the URL status = URLNewReference(url, &mURLReference); // Begin the transfer if (status == noErr) status = URLOpen( mURLReference, NULL, // FSSpec* (not reading to file) 0, // URLOpenFlags NULL, // URLNotifyUPP 0, // URLEventMask 0); // userContext // If we failed, we throw switch (status) { case noErr: break; case kURLInvalidURLError: ThrowXML(MalformedURLException, XMLExcepts::URL_MalformedURL); break; case kURLUnsupportedSchemeError: ThrowXML(MalformedURLException, XMLExcepts::URL_UnsupportedProto); break; default: ThrowXML1(NetAccessorException, XMLExcepts::NetAcc_ConnSocket, urlSource.getURLText()); break; } } URLAccessBinInputStream::~URLAccessBinInputStream() { OSStatus status = noErr; // Release any buffer we've still got a hold of if (status == noErr && mBuffer) { status = URLReleaseBuffer(mURLReference, mBuffer); mBuffer = NULL; } // Get the current state URLState state = 0; if (status == noErr) status = URLGetCurrentState(mURLReference, &state); // Abort if we're not completed if (status == noErr && state != kURLNullState && state != kURLCompletedState) status = URLAbort(mURLReference); // Loop til we reach a terminal state. // This may be unneeded by URLAccess, but the docs are // not very good. while ( status == noErr && state != kURLNullState && state != kURLErrorOccurredState && state != kURLCompletedState ) { status = URLIdle(); if (status == noErr) status = URLGetCurrentState(mURLReference, &state); } // Dispose the reference status = URLDisposeReference(mURLReference); } // // Call URLAccess to fullfill the read request. Since it // passes us back buffers full of data, our object maintains // a partial buffer across calls. // unsigned int URLAccessBinInputStream::readBytes(XMLByte* const toFill , const unsigned int maxToRead) { OSStatus status = noErr; XMLByte* writePos = toFill; std::size_t bytesDesired = maxToRead; URLState state = kURLNullState; while ( // while... status == noErr // there's been no error && bytesDesired > 0 // more data is wanted && (status = URLGetCurrentState(mURLReference, &state)) == noErr // we can get the state && (state != kURLErrorOccurredState) // no error has occurred in the transaction && (mBuffer || state != kURLCompletedState) // we have data still buffered or the request isn't complete && (mBuffer || bytesDesired == maxToRead) // we have data still buffered or we've supplied absolutely none ) { // Give time to URLAccess status = URLIdle(); // If we've got buffered data, use it if (status == noErr && mBuffer) { // Supply as much as we can from the buffer std::size_t n = mBufAvailable; if (n > bytesDesired) n = bytesDesired; // If we've got data, copy it over and update our pointers if (n > 0) { std::memcpy(writePos, mBufPos, n); writePos += n; bytesDesired -= n; mBufPos += n; mBufAvailable -= n; mBytesProcessed += n; } // If we exhausted the buffer, release it if (mBufAvailable == 0) { status = URLReleaseBuffer(mURLReference, mBuffer); mBuffer = NULL; } } // If the buffer is exhausted, get a new one if (status == noErr && !mBuffer) { status = URLGetBuffer(mURLReference, &mBuffer, &mBufAvailable); if (status == noErr) mBufPos = reinterpret_cast(mBuffer); } } // Throw on any error if (status != noErr || state == kURLErrorOccurredState) ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket); // Return number of bytes delivered return maxToRead - bytesDesired; } XERCES_CPP_NAMESPACE_END