blocxx
|
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