Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008 #include "ibrcommon/data/BLOB.h"
00009 #include "ibrcommon/thread/MutexLock.h"
00010 #include "ibrcommon/Exceptions.h"
00011 #include "ibrcommon/Logger.h"
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <cstring>
00016 #include <cerrno>
00017
00018 #ifdef __DEVELOPMENT_ASSERTIONS__
00019 #include <cassert>
00020 #endif
00021
00022 namespace ibrcommon
00023 {
00024 ibrcommon::Semaphore BLOB::_filelimit(10);
00025
00026 File BLOB::tmppath;
00027
00028 BLOB::BLOB()
00029 : ibrcommon::Mutex(ibrcommon::Mutex::MUTEX_NORMAL), _locked(false), _refcount(0), _reflock(ibrcommon::Mutex::MUTEX_NORMAL)
00030 { }
00031
00032 BLOB::~BLOB()
00033 {
00034 }
00035
00036 std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const size_t size, const size_t buffer_size)
00037 {
00038
00039 char buffer[buffer_size];
00040 size_t remain = size;
00041
00042 while (remain > 0)
00043 {
00044
00045 if (input.bad())
00046 {
00047 std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00048 throw ibrcommon::IOException(errmsg.str());
00049 }
00050
00051
00052 if (input.eof())
00053 {
00054 std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00055 throw ibrcommon::IOException(errmsg.str());
00056 }
00057
00058
00059 if (output.bad())
00060 {
00061 std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00062 throw ibrcommon::IOException(errmsg.str());
00063 }
00064
00065
00066 if (input.fail())
00067 {
00068 IBRCOMMON_LOGGER(warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00069 input.clear();
00070 }
00071
00072
00073 if (output.fail())
00074 {
00075 IBRCOMMON_LOGGER(warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00076 output.clear();
00077 }
00078 else
00079 {
00080
00081 if (remain > buffer_size)
00082 {
00083 input.read(buffer, buffer_size);
00084 }
00085 else
00086 {
00087 input.read(buffer, remain);
00088 }
00089
00090
00091 if (input.fail()) continue;
00092 }
00093
00094
00095 output.write(buffer, input.gcount());
00096
00097
00098 remain -= input.gcount();
00099 }
00100
00101 return output;
00102 }
00103
00104 BLOB::Reference::Reference(const Reference &ref)
00105 : ibrcommon::Mutex(MUTEX_NORMAL), _blob(ref._blob)
00106 {
00107 MutexLock l(_blob->_reflock);
00108 _blob->_refcount++;
00109 }
00110
00111 BLOB::Reference::~Reference()
00112 {
00113
00114 {
00115 MutexLock l(_blob->_reflock);
00116 if ((_blob->_refcount--) > 1) return;
00117 }
00118
00119 delete _blob;
00120 }
00121
00122 BLOB::iostream BLOB::Reference::iostream()
00123 {
00124 return BLOB::iostream(_blob);
00125 }
00126
00127 std::iostream& BLOB::Reference::operator*()
00128 {
00129 #ifdef __DEVELOPMENT_ASSERTIONS__
00130 assert(_blob->_locked);
00131 #endif
00132 return _blob->__get_stream();
00133 }
00134
00135 BLOB::Reference::Reference(BLOB *blob)
00136 : _blob(blob)
00137 {
00138 MutexLock l(_blob->_reflock);
00139 _blob->_refcount++;
00140 }
00141
00142 void BLOB::Reference::enter() throw (ibrcommon::MutexException)
00143 {
00144
00145 _blob->enter();
00146 _blob->_locked = true;
00147
00148
00149 _blob->open();
00150 }
00151
00152 void BLOB::Reference::leave() throw (ibrcommon::MutexException)
00153 {
00154 _blob->_locked = false;
00155
00156
00157 _blob->close();
00158
00159
00160 _blob->leave();
00161 }
00162
00163 void BLOB::Reference::trylock() throw (ibrcommon::MutexException)
00164 {
00165
00166 _blob->trylock();
00167 _blob->_locked = true;
00168
00169
00170 _blob->open();
00171 }
00172
00173 size_t BLOB::Reference::getSize() const
00174 {
00175 #ifdef __DEVELOPMENT_ASSERTIONS__
00176 assert(_blob->_locked);
00177 #endif
00178 return _blob->__get_size();
00179 }
00180
00181 void BLOB::Reference::clear()
00182 {
00183 #ifdef __DEVELOPMENT_ASSERTIONS__
00184 assert(_blob->_locked);
00185 #endif
00186 _blob->clear();
00187 }
00188
00189 BLOB::Reference StringBLOB::create()
00190 {
00191 BLOB::Reference ref(new StringBLOB());
00192 return ref;
00193 }
00194
00195 void StringBLOB::clear()
00196 {
00197 _stringstream.str("");
00198 }
00199
00200 StringBLOB::StringBLOB()
00201 : BLOB(), _stringstream()
00202 {
00203
00204 }
00205
00206 StringBLOB::~StringBLOB()
00207 {
00208 }
00209
00210 void StringBLOB::open()
00211 {
00212
00213 _stringstream.clear();
00214 _stringstream.seekp(0);
00215 _stringstream.seekg(0);
00216 }
00217
00218 void StringBLOB::close()
00219 {
00220 }
00221
00222 size_t StringBLOB::__get_size()
00223 {
00224
00225 size_t pos = _stringstream.tellg();
00226
00227 _stringstream.seekg(0, std::ios_base::end);
00228 size_t size = _stringstream.tellg();
00229 _stringstream.seekg(pos);
00230
00231 return size;
00232 }
00233
00234 BLOB::Reference FileBLOB::create(const File &f)
00235 {
00236 return BLOB::Reference(new FileBLOB(f));
00237 }
00238
00239 void FileBLOB::clear()
00240 {
00241 throw ibrcommon::IOException("clear is not possible on a read only file");
00242 }
00243
00244 FileBLOB::FileBLOB(const File &f)
00245 : BLOB(), _filestream(), _file(f)
00246 {
00247 if (!f.exists())
00248 {
00249 throw ibrcommon::FileNotExistsException(f);
00250 }
00251 }
00252
00253 FileBLOB::~FileBLOB()
00254 {
00255 }
00256
00257 void FileBLOB::open()
00258 {
00259 BLOB::_filelimit.wait();
00260
00261
00262 _filestream.open(_file.getPath().c_str(), ios::in|ios::binary);
00263
00264 if (!_filestream.is_open())
00265 {
00266 throw ibrcommon::CanNotOpenFileException(_file);
00267 }
00268 }
00269
00270 void FileBLOB::close()
00271 {
00272
00273 _filestream.close();
00274
00275 BLOB::_filelimit.post();
00276 }
00277
00278 size_t FileBLOB::__get_size()
00279 {
00280 return _file.size();
00281 }
00282
00283 BLOB::Reference TmpFileBLOB::create()
00284 {
00285 try {
00286 return BLOB::Reference(new TmpFileBLOB());
00287 } catch (const ibrcommon::IOException&) {
00288 return StringBLOB::create();
00289 }
00290 }
00291
00292 void TmpFileBLOB::clear()
00293 {
00294
00295 _filestream.close();
00296
00297
00298 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary );
00299
00300 if (!_filestream.is_open())
00301 {
00302 IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00303 throw ibrcommon::CanNotOpenFileException(_tmpfile);
00304 }
00305 }
00306
00307 TmpFileBLOB::TmpFileBLOB()
00308 : BLOB(), _filestream()
00309 {
00310
00311 if (!BLOB::tmppath.isDirectory())
00312 {
00313 throw ibrcommon::IOException("BLOB::tmppath not initialized or path is not a directory.");
00314 }
00315
00316 createtmpfile();
00317 }
00318
00319 void TmpFileBLOB::createtmpfile()
00320 {
00321 _tmpfile = ibrcommon::TemporaryFile(BLOB::tmppath, "blob");
00322 _tmpfile.update();
00323 }
00324
00325 TmpFileBLOB::~TmpFileBLOB()
00326 {
00327
00328 _tmpfile.remove();
00329 }
00330
00331 void TmpFileBLOB::open()
00332 {
00333 BLOB::_filelimit.wait();
00334
00335
00336 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary );
00337
00338 if (!_filestream.is_open())
00339 {
00340 IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00341 throw ibrcommon::CanNotOpenFileException(_tmpfile);
00342 }
00343 }
00344
00345 void TmpFileBLOB::close()
00346 {
00347
00348 _filestream.flush();
00349
00350
00351 _filestream.close();
00352
00353 BLOB::_filelimit.post();
00354 }
00355
00356 size_t TmpFileBLOB::__get_size()
00357 {
00358 return _tmpfile.size();
00359 }
00360 }