blocxx
TempFileStream.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Vintela, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
39 // gptr() && !pptr() == input mode
40 // !gptr() && pptr() == output mode
41 // pptr() && gptr() should never happen
42 // !gptr() && !pptr() should never happen
43 // pptr() should never be 0 unless we're gone to file.
44 #include "blocxx/BLOCXX_config.h"
46 #include "blocxx/FileSystem.hpp"
47 #include "blocxx/Assertion.hpp"
48 #include "blocxx/IOException.hpp"
49 #include <cstring>
50 
51 namespace BLOCXX_NAMESPACE
52 {
53 
54 using std::iostream;
57  : m_bufSize(bufSize)
58  , m_buffer(new char[m_bufSize])
59  , m_tempFile()
60  , m_readPos(0)
61  , m_writePos(0)
62  , m_isEOF(false)
63  , m_dir()
64  , m_keepFlag(keepflg)
65  , m_filePath()
66 {
67  setg(0,0,0); // start out in output mode.
68  initPutBuffer();
69 }
70 
72 TempFileBuffer::TempFileBuffer(const String& dir, size_t bufSize, EKeepFileFlag keepflg)
73  : m_bufSize(bufSize)
74  , m_buffer(new char[m_bufSize])
75  , m_tempFile()
76  , m_readPos(0)
77  , m_writePos(0)
78  , m_isEOF(false)
79  , m_dir(dir)
80  , m_keepFlag(keepflg)
81  , m_filePath()
82 {
83  setg(0,0,0); // start out in output mode.
84  initPutBuffer();
85 }
86 
88 void
90 {
91  initPutBuffer();
92  initGetBuffer();
93 }
95 void
97 {
98  setp(m_buffer, m_buffer + m_bufSize);
99 }
101 void
103 {
104  setg(m_buffer, m_buffer, m_buffer);
105 }
108 {
109  try
110  {
111  if (m_filePath.length())
112  {
113  String fname = releaseFileAndReset();
114  if (fname.length())
115  {
116  // At this point we know we have been ask to keep the underlying
117  // file but the user never called releaseFileAndReset, so we'll
118  // attempt to removed that here.
119  FileSystem::removeFile(fname);
120  }
121  }
122  }
123  catch(...)
124  {
125  // Ignore?
126  }
127 
128  delete [] m_buffer;
129 }
131 int
133 {
134  int cnt = pptr() - pbase();
135  int retval = buffer_to_device(m_buffer, cnt);
136  initPutBuffer();
137  return retval;
138 }
140 int
142 {
143  if (pptr()) // buffer is full
144  {
145  if (buffer_out() < 0)
146  {
147  return EOF;
148  }
149  }
150  else // switching from input to output
151  {
152  if (!m_tempFile)
153  {
154  initPutBuffer();
155  pbump(m_writePos);
156  m_readPos = gptr() - eback();
157  }
158  else
159  {
160  m_readPos = m_tempFile.tell() - (egptr() - gptr());
161  m_tempFile.seek(m_writePos, SEEK_SET);
162  initPutBuffer();
163  }
164  setg(0,0,0);
165  }
166  if (c != EOF)
167  {
168  return sputc(c);
169  }
170  else
171  {
172  return c;
173  }
174 }
176 std::streamsize
177 TempFileBuffer::xsputn(const char* s, std::streamsize n)
178 {
179  if (n < epptr() - pptr())
180  {
181  memcpy(pptr(), s, n * sizeof(char));
182  pbump(n);
183  return n;
184  }
185  else
186  {
187  for (std::streamsize i = 0; i < n; i++)
188  {
189  if (sputc(s[i]) == EOF)
190  {
191  return i;
192  }
193  }
194  return n;
195  }
196 }
198 int
200 {
201  if (m_isEOF)
202  {
203  return EOF;
204  }
205  if (gptr()) // need to fill buffer
206  {
207  if (buffer_in() < 0)
208  {
209  return EOF;
210  }
211  }
212  else // we're in output mode; switch to input mode
213  {
214  if (m_tempFile)
215  {
216  buffer_out();
218  m_tempFile.seek(m_readPos, SEEK_SET);
219  if (buffer_in() < 0)
220  {
221  return EOF;
222  }
223  }
224  else
225  {
226  m_writePos = pptr() - pbase();
227  setg(m_buffer, m_buffer + m_readPos, pptr());
228  }
229  setp(0,0);
230  }
231  return static_cast<unsigned char>(*gptr());
232 }
234 int
236 {
237  int retval = buffer_from_device(m_buffer, m_bufSize);
238  if (retval <= 0)
239  {
240  setg(0,0,0);
241  m_isEOF = true;
242  return -1;
243  }
244  else
245  {
246  setg(m_buffer, m_buffer, m_buffer + retval);
247  return retval;
248  }
249 }
251 int
252 TempFileBuffer::buffer_to_device(const char* c, int n)
253 {
254  if (!m_tempFile)
255  {
256  if (m_keepFlag == E_KEEP_FILE)
257  {
259  }
260  else
261  {
263  }
264 
265  if (!m_tempFile)
266  {
267  BLOCXX_THROW(IOException, "Failed to create temp file");
268  }
269  }
270  return static_cast<int>(m_tempFile.write(c, n));
271 }
273 int
275 {
276  if (!m_tempFile)
277  {
278  return -1;
279  }
280  else
281  {
282  return static_cast<int>(m_tempFile.read(c, n));
283  }
284 }
286 std::streamsize
288 {
289  if (gptr() && !m_tempFile)
290  {
291  return egptr() - eback();
292  }
293  std::streamsize rval = m_writePos;
294  if (m_tempFile)
295  {
296  rval = m_tempFile.size();
297  }
298  if (pptr())
299  {
300  rval += pptr() - pbase();
301  }
302  return rval;
303 }
305 void
307 {
308  m_readPos = 0;
309  if (m_tempFile)
310  {
311  if (pptr())
312  {
313  m_writePos += pptr() - pbase();
314  buffer_out();
315  }
316  m_tempFile.seek(0, SEEK_SET);
317  initGetBuffer();
318  }
319  else
320  {
321  if (pptr())
322  {
323  m_writePos = pptr() - pbase();
324  }
325  else if (gptr())
326  {
327  m_writePos = egptr() - eback();
328  }
330  }
331  setp(0,0);
332  m_isEOF = false;
333 }
335 void
337 {
338  if (m_tempFile)
339  {
340  m_tempFile.close();
341  }
342 
343  m_writePos = m_readPos = 0;
344  setg(0,0,0);
345  initPutBuffer();
346  m_isEOF = false;
347 }
348 
350 String
352 {
353  buffer_out(); // Flush the buffer and cause the temp file to be written
354  reset(); // Close file and reset
355  String rv = m_filePath; // Save to return
356  m_filePath.erase(); // Clear filePath to indicate release called
357  return rv;
358 }
359 
361 bool
363 {
364  return bool(m_tempFile);
365 }
368  : std::basic_iostream<char, std::char_traits<char> >(new TempFileBuffer(bufSize, keepflg))
369  , m_buffer(dynamic_cast<TempFileBuffer*>(rdbuf()))
370 {
371 }
372 
375  : std::basic_iostream<char, std::char_traits<char> >(new TempFileBuffer(dir, bufSize, keepflg))
376  , m_buffer(dynamic_cast<TempFileBuffer*>(rdbuf()))
377 {
378 }
379 
381 void
383 {
384  m_buffer->rewind();
385  // clear eof bit
386  clear(rdstate() & ~std::ios::eofbit);
387 }
389 void
391 {
392  m_buffer->reset();
393  clear();
394 }
396 String
398 {
400  clear();
401  return rval;
402 }
404 bool
406 {
407  return m_buffer->usingTempFile();
408 }
409 
410 } // end namespace BLOCXX_NAMESPACE
411