blocxx

TempFileStream.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Vintela, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00039 // gptr() && !pptr() == input mode
00040 // !gptr() && pptr() == output mode
00041 // pptr() && gptr() should never happen
00042 // !gptr() && !pptr() should never happen
00043 // pptr() should never be 0 unless we're gone to file.
00044 #include "blocxx/BLOCXX_config.h"
00045 #include "blocxx/TempFileStream.hpp"
00046 #include "blocxx/FileSystem.hpp"
00047 #include "blocxx/Assertion.hpp"
00048 #include "blocxx/IOException.hpp"
00049 #include <cstring>
00050 
00051 namespace BLOCXX_NAMESPACE
00052 {
00053 
00054 using std::iostream;
00056 TempFileBuffer::TempFileBuffer(size_t bufSize, EKeepFileFlag keepflg)
00057    : m_bufSize(bufSize)
00058    , m_buffer(new char[m_bufSize])
00059    , m_tempFile()
00060    , m_readPos(0)
00061    , m_writePos(0)
00062    , m_isEOF(false)
00063    , m_dir()
00064    , m_keepFlag(keepflg)
00065    , m_filePath()
00066 {
00067    setg(0,0,0); // start out in output mode.
00068    initPutBuffer();
00069 }
00070 
00072 TempFileBuffer::TempFileBuffer(const String& dir, size_t bufSize, EKeepFileFlag keepflg)
00073    : m_bufSize(bufSize)
00074    , m_buffer(new char[m_bufSize])
00075    , m_tempFile()
00076    , m_readPos(0)
00077    , m_writePos(0)
00078    , m_isEOF(false)
00079    , m_dir(dir)
00080    , m_keepFlag(keepflg)
00081    , m_filePath()
00082 {
00083    setg(0,0,0); // start out in output mode.
00084    initPutBuffer();
00085 }
00086 
00088 void
00089 TempFileBuffer::initBuffers()
00090 {
00091    initPutBuffer();
00092    initGetBuffer();
00093 }
00095 void
00096 TempFileBuffer::initPutBuffer()
00097 {
00098    setp(m_buffer, m_buffer + m_bufSize);
00099 }
00101 void
00102 TempFileBuffer::initGetBuffer()
00103 {
00104    setg(m_buffer, m_buffer, m_buffer);
00105 }
00107 TempFileBuffer::~TempFileBuffer()
00108 {
00109    try
00110    {
00111       if (m_filePath.length())
00112       {
00113          String fname = releaseFileAndReset();
00114          if (fname.length())
00115          {
00116             // At this point we know we have been ask to keep the underlying
00117             // file but the user never called releaseFileAndReset, so we'll 
00118             // attempt to removed that here.
00119             FileSystem::removeFile(fname);
00120          }
00121       }
00122    }
00123    catch(...)
00124    {
00125       // Ignore?
00126    }
00127 
00128    delete [] m_buffer;
00129 }
00131 int
00132 TempFileBuffer::buffer_out()
00133 {
00134    int cnt = pptr() - pbase();
00135    int retval = buffer_to_device(m_buffer, cnt);
00136    initPutBuffer();
00137    return retval;
00138 }
00140 int
00141 TempFileBuffer::overflow(int c)
00142 {
00143    if (pptr()) // buffer is full
00144    {
00145       if (buffer_out() < 0)
00146       {
00147          return EOF;
00148       }
00149    }
00150    else  // switching from input to output
00151    {
00152       if (!m_tempFile)
00153       {
00154          initPutBuffer();
00155          pbump(m_writePos);
00156          m_readPos = gptr() - eback();
00157       }
00158       else
00159       {
00160          m_readPos = m_tempFile.tell() - (egptr() - gptr());
00161          m_tempFile.seek(m_writePos, SEEK_SET);
00162          initPutBuffer();
00163       }
00164       setg(0,0,0);
00165    }
00166    if (c != EOF)
00167    {
00168       return sputc(c);
00169    }
00170    else
00171    {
00172       return c;
00173    }
00174 }
00176 std::streamsize
00177 TempFileBuffer::xsputn(const char* s, std::streamsize n)
00178 {
00179    if (n < epptr() - pptr())
00180    {
00181       memcpy(pptr(), s, n * sizeof(char));
00182       pbump(n);
00183       return n;
00184    }
00185    else
00186    {
00187       for (std::streamsize i = 0; i < n; i++)
00188       {
00189          if (sputc(s[i]) == EOF)
00190          {
00191             return i;
00192          }
00193       }
00194       return n;
00195    }
00196 }
00198 int
00199 TempFileBuffer::underflow()
00200 {
00201    if (m_isEOF)
00202    {
00203       return EOF;
00204    }
00205    if (gptr()) // need to fill buffer
00206    {
00207       if (buffer_in() < 0)
00208       {
00209          return EOF;
00210       }
00211    }
00212    else // we're in output mode; switch to input mode
00213    {
00214       if (m_tempFile)
00215       {
00216          buffer_out();
00217          m_writePos = m_tempFile.tell();
00218          m_tempFile.seek(m_readPos, SEEK_SET);
00219          if (buffer_in() < 0)
00220          {
00221             return EOF;
00222          }
00223       }
00224       else
00225       {
00226          m_writePos = pptr() - pbase();
00227          setg(m_buffer, m_buffer + m_readPos, pptr());
00228       }
00229       setp(0,0);
00230    }
00231    return static_cast<unsigned char>(*gptr());
00232 }
00234 int
00235 TempFileBuffer::buffer_in()
00236 {
00237    int retval = buffer_from_device(m_buffer, m_bufSize);
00238    if (retval <= 0)
00239    {
00240       setg(0,0,0);
00241       m_isEOF = true;
00242       return -1;
00243    }
00244    else
00245    {
00246       setg(m_buffer, m_buffer, m_buffer + retval);
00247       return retval;
00248    }
00249 }
00251 int
00252 TempFileBuffer::buffer_to_device(const char* c, int n)
00253 {
00254    if (!m_tempFile)
00255    {
00256       if (m_keepFlag == E_KEEP_FILE)
00257       {
00258          m_tempFile = FileSystem::createTempFile(m_filePath, m_dir);
00259       }
00260       else
00261       {
00262          m_tempFile = FileSystem::createAutoDeleteTempFile(m_dir);
00263       }
00264 
00265       if (!m_tempFile)
00266       {
00267          BLOCXX_THROW(IOException, "Failed to create temp file");
00268       }
00269    }
00270    return static_cast<int>(m_tempFile.write(c, n));
00271 }
00273 int
00274 TempFileBuffer::buffer_from_device(char* c, int n)
00275 {
00276    if (!m_tempFile)
00277    {
00278       return -1;
00279    }
00280    else
00281    {
00282       return static_cast<int>(m_tempFile.read(c, n));
00283    }
00284 }
00286 std::streamsize
00287 TempFileBuffer::getSize()
00288 {
00289    if (gptr() && !m_tempFile)
00290    {
00291       return egptr() - eback();
00292    }
00293    std::streamsize rval = m_writePos;
00294    if (m_tempFile)
00295    {
00296       rval = m_tempFile.size();
00297    }
00298    if (pptr())
00299    {
00300       rval += pptr() - pbase();
00301    }
00302    return rval;
00303 }
00305 void
00306 TempFileBuffer::rewind()
00307 {
00308    m_readPos = 0;
00309    if (m_tempFile)
00310    {
00311       if (pptr())
00312       {
00313          m_writePos += pptr() - pbase();
00314          buffer_out();
00315       }
00316       m_tempFile.seek(0, SEEK_SET);
00317       initGetBuffer();
00318    }
00319    else
00320    {
00321       if (pptr())
00322       {
00323          m_writePos = pptr() - pbase();
00324       }
00325       else if (gptr())
00326       {
00327          m_writePos = egptr() - eback();
00328       }
00329       setg(m_buffer, m_buffer, m_buffer + m_writePos);
00330    }
00331    setp(0,0);
00332    m_isEOF = false;
00333 }
00335 void
00336 TempFileBuffer::reset()
00337 {
00338    if (m_tempFile)
00339    {
00340       m_tempFile.close();
00341    }
00342 
00343    m_writePos = m_readPos = 0;
00344    setg(0,0,0);
00345    initPutBuffer();
00346    m_isEOF = false;
00347 }
00348 
00350 String
00351 TempFileBuffer::releaseFileAndReset()
00352 {
00353    buffer_out();  // Flush the buffer and cause the temp file to be written
00354    reset();    // Close file and reset
00355    String rv = m_filePath;    // Save to return
00356    m_filePath.erase();        // Clear filePath to indicate release called
00357    return rv;
00358 }
00359 
00361 bool
00362 TempFileBuffer::usingTempFile() const
00363 {
00364    return bool(m_tempFile);
00365 }
00367 TempFileStream::TempFileStream(size_t bufSize, TempFileBuffer::EKeepFileFlag keepflg)
00368    : std::basic_iostream<char, std::char_traits<char> >(new TempFileBuffer(bufSize, keepflg))
00369    , m_buffer(dynamic_cast<TempFileBuffer*>(rdbuf()))
00370 {
00371 }
00372 
00374 TempFileStream::TempFileStream(const String& dir, size_t bufSize, TempFileBuffer::EKeepFileFlag keepflg)
00375    : std::basic_iostream<char, std::char_traits<char> >(new TempFileBuffer(dir, bufSize, keepflg))
00376    , m_buffer(dynamic_cast<TempFileBuffer*>(rdbuf()))
00377 {
00378 }
00379 
00381 void
00382 TempFileStream::rewind()
00383 {
00384    m_buffer->rewind();
00385    // clear eof bit
00386    clear(rdstate() & ~std::ios::eofbit);
00387 }
00389 void
00390 TempFileStream::reset()
00391 {
00392    m_buffer->reset();
00393    clear();
00394 }
00396 String
00397 TempFileStream::releaseFileAndReset()
00398 {
00399    String rval = m_buffer->releaseFileAndReset();
00400    clear();
00401    return rval;
00402 }
00404 bool
00405 TempFileStream::usingTempFile() const
00406 {
00407    return m_buffer->usingTempFile();
00408 }
00409 
00410 } // end namespace BLOCXX_NAMESPACE
00411