Vault  4.1
vbufferedfilestream.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00003 This file is part of the Code Vault version 4.1
00004 http://www.bombaydigital.com/
00005 License: MIT. See LICENSE.md in the Vault top level directory.
00006 */
00007 
00010 #include "vbufferedfilestream.h"
00011 #include "vtypes_internal.h"
00012 
00013 #include "vexception.h"
00014 
00015 VBufferedFileStream::VBufferedFileStream()
00016     : VAbstractFileStream()
00017     , mFile(NULL)
00018     , mCloseOnDestruct(true)
00019     {
00020 }
00021 
00022 VBufferedFileStream::VBufferedFileStream(const VFSNode& node)
00023     : VAbstractFileStream(node)
00024     , mFile(NULL)
00025     , mCloseOnDestruct(true)
00026     {
00027 }
00028 
00029 VBufferedFileStream::VBufferedFileStream(FILE* f, bool closeOnDestruct)
00030     : VAbstractFileStream()
00031     , mFile(f)
00032     , mCloseOnDestruct(closeOnDestruct)
00033     {
00034 }
00035 
00036 VBufferedFileStream::~VBufferedFileStream() {
00037     if (mCloseOnDestruct) {
00038         VBufferedFileStream::close();
00039     }
00040 
00041     mFile = NULL;
00042 }
00043 
00044 void VBufferedFileStream::setFile(FILE* f, bool closeOnDestruct) {
00045     mFile = f;
00046     mCloseOnDestruct = closeOnDestruct;
00047 }
00048 
00049 void VBufferedFileStream::openReadOnly() {
00050     mFile = VFileSystem::fopen(mNode.getPath(), "rb");
00051 
00052     this->_throwIfOpenFailed("VBufferedFileStream::openReadOnly", mNode.getPath());
00053 }
00054 
00055 void VBufferedFileStream::openReadWrite() {
00056     /*
00057     The semantics of ::fopen() and ::open() run counter to the normal desire
00058     to open a file r/w and have it created if it doesn't exist. For example,
00059     mode "r" does not create the file. Mode "w" does. So instead, we check for
00060     existence first, and then open it exactly the way we intend.
00061     */
00062 
00063     mFile = VFileSystem::fopen(mNode.getPath(), mNode.exists() ? "r+b" : "w+b");
00064 
00065     this->_throwIfOpenFailed("VBufferedFileStream::openReadWrite", mNode.getPath());
00066 }
00067 
00068 void VBufferedFileStream::openWrite() {
00069     mFile = VFileSystem::fopen(mNode.getPath(), "wb");
00070 
00071     this->_throwIfOpenFailed("VBufferedFileStream::openWrite", mNode.getPath());
00072 }
00073 
00074 bool VBufferedFileStream::isOpen() const {
00075     return (mFile != NULL);
00076 }
00077 
00078 void VBufferedFileStream::close() {
00079     if (this->isOpen()) {
00080         (void) VFileSystem::fclose(mFile);
00081         mFile = NULL;
00082     }
00083 }
00084 
00085 Vs64 VBufferedFileStream::read(Vu8* targetBuffer, Vs64 numBytesToRead) {
00086     /*
00087     Most of the work here is to deal with the fact that we are providing
00088     a SInt64 count in our API, but the underlying OS API may only
00089     allow a size_t count. So we may have to read in a loop until the
00090     requested number of bytes is read or EOF is reached. In the typical
00091     case, of course, we only go through the loop once.
00092     */
00093 
00094     bool    needsSizeConversion = (sizeof(Vs64) != sizeof(size_t));
00095     Vs64    numBytesRemaining = numBytesToRead;
00096     Vs64    numBytesRead = 0;
00097     size_t  requestCount;
00098     size_t  actualCount;
00099 
00100     do {
00101         if (needsSizeConversion) {
00102             requestCount = static_cast<size_t>(V_MIN(((Vs64)(0x7FFFFFFF)), numBytesRemaining));
00103         } else {
00104             requestCount = static_cast<size_t>(numBytesRemaining);
00105         }
00106 
00107         actualCount = VFileSystem::fread(targetBuffer + numBytesRead, 1, requestCount, mFile);
00108 
00109         numBytesRead += actualCount;
00110         numBytesRemaining -= actualCount;
00111 
00112     } while ((actualCount == requestCount) && (numBytesRemaining > 0));
00113 
00114     return numBytesRead;
00115 }
00116 
00117 Vs64 VBufferedFileStream::write(const Vu8* buffer, Vs64 numBytesToWrite) {
00118     /*
00119     Most of the work here is to deal with the fact that we are providing
00120     a SInt64 count in our API, but the underlying OS API may only
00121     allow a size_t count. So we may have to write in a loop until the
00122     requested number of bytes is written. In the typical
00123     case, of course, we only go through the loop once.
00124     */
00125 
00126     bool    needsSizeConversion = VStream::needSizeConversion(numBytesToWrite);
00127     Vs64    numBytesRemaining = numBytesToWrite;
00128     Vs64    numBytesWritten = 0;
00129     size_t  requestCount;
00130     size_t  actualCount;
00131 
00132     do {
00133         if (needsSizeConversion) {
00134             requestCount = static_cast<size_t>(V_MIN((static_cast<Vs64>(LONG_MAX)), numBytesRemaining));
00135         } else {
00136             requestCount = static_cast<size_t>(numBytesRemaining);
00137         }
00138 
00139         actualCount = VFileSystem::fwrite(buffer + numBytesWritten, 1, requestCount, mFile);
00140 
00141         numBytesWritten += actualCount;
00142         numBytesRemaining -= actualCount;
00143 
00144     } while ((actualCount == requestCount) && (numBytesRemaining > 0));
00145 
00146     if (numBytesWritten != numBytesToWrite) {
00147         VString path;
00148         mNode.getPath(path);
00149 
00150         throw VException(VSystemError(), VSTRING_FORMAT("VBufferedFileStream::write to '%s' only wrote " VSTRING_FORMATTER_S64 " of " VSTRING_FORMATTER_S64 " requested bytes.", path.chars(), numBytesWritten, numBytesToWrite));
00151     }
00152 
00153     return numBytesWritten;
00154 }
00155 
00156 void VBufferedFileStream::flush() {
00157     int result = VFileSystem::fflush(mFile);
00158 
00159     if (result != 0) {
00160         VString path;
00161         mNode.getPath(path);
00162         throw VException(VSystemError(), VSTRING_FORMAT("VBufferedFileStream::flush to '%s' failed with result %d.", path.chars(), result));
00163     }
00164 }
00165 
00166 bool VBufferedFileStream::skip(Vs64 numBytesToSkip) {
00167     /*
00168     Most of the work here is to deal with the fact that we are providing
00169     a SInt64 count in our API, but the underlying OS API may only
00170     allow a long count. So we may have to seek in a loop until the
00171     requested offset is seeked. In the typical case, of course, we only go
00172     through the loop once.
00173     */
00174 
00175     bool success;
00176     bool needsSizeConversion = VStream::needSizeConversion(numBytesToSkip);
00177     Vs64 numBytesRemaining = numBytesToSkip;
00178     Vs64 requestCount;
00179 
00180     do {
00181         if (needsSizeConversion) {
00182             requestCount = V_MIN((static_cast<Vs64>(LONG_MAX)), numBytesRemaining);
00183         } else {
00184             requestCount = numBytesRemaining;
00185         }
00186 
00187         success = this->seek(numBytesToSkip, SEEK_CUR);
00188 
00189         numBytesRemaining -= requestCount;
00190 
00191     } while (success && (numBytesRemaining > 0));
00192 
00193     return success;
00194 }
00195 
00196 bool VBufferedFileStream::seek(Vs64 offset, int whence) {
00197     // FIXME: need to deal with Vs64-to-long conversion
00198     return (VFileSystem::fseek(mFile, static_cast<long>(offset), whence) == 0);
00199 }
00200 
00201 Vs64 VBufferedFileStream::getIOOffset() const {
00202     return VFileSystem::ftell(mFile);
00203 }
00204 
00205 Vs64 VBufferedFileStream::available() const {
00206     Vs64 currentOffset = this->getIOOffset();
00207     Vs64 eofOffset;
00208 
00209     // const_cast: WORKAROUND. Save/restore state.
00210     const_cast<VBufferedFileStream*>(this)->seek(0, SEEK_END);
00211     eofOffset = this->getIOOffset();
00212     const_cast<VBufferedFileStream*>(this)->seek(currentOffset, SEEK_SET);    // restore original position
00213 
00214     return eofOffset - currentOffset;
00215 }
00216 

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.