blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, 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 * Quest Software, 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 00038 #include "blocxx/BLOCXX_config.h" 00039 #include "blocxx/FileBuf.hpp" 00040 #include "blocxx/IOException.hpp" 00041 00042 #ifdef BLOCXX_HAVE_UNISTD_H 00043 #include <unistd.h> 00044 #endif 00045 00046 #include <fcntl.h> 00047 #include <ios> 00048 00049 #ifdef BLOCXX_WIN32 00050 #include <io.h> 00051 #endif 00052 00053 namespace BLOCXX_NAMESPACE 00054 { 00055 00056 FileBuf::FileBuf() 00057 : BaseStreamBuffer(E_IN_OUT) 00058 , m_file(0) 00059 { 00060 } 00061 00062 FileBuf::~FileBuf() 00063 { 00064 close(); 00065 } 00066 00067 bool 00068 FileBuf::isOpen() const 00069 { 00070 return m_file != 0; 00071 } 00072 00073 FileBuf* 00074 FileBuf::open(FILE* fp) 00075 { 00076 if (isOpen()) 00077 { 00078 return 0; 00079 } 00080 00081 m_file = fp; 00082 return this; 00083 } 00084 00085 FileBuf* 00086 FileBuf::open(AutoDescriptor fd) 00087 { 00088 if (isOpen()) 00089 { 00090 return 0; 00091 } 00092 00093 int d = -1; 00094 00095 #ifdef BLOCXX_WIN32 00096 #pragma message(Reminder "TODO: implement it for Win!") 00097 //maybe it's enough just to set flags = O_RDWR 00098 //but it's unclear what to do with O_APPEND 00099 int flags = O_RDWR; 00100 00101 d = _open_osfhandle(reinterpret_cast<long>(fd.get()), flags); 00102 #else 00103 d = fd.get(); 00104 int flags = ::fcntl(d, F_GETFL); 00105 if (flags == -1) 00106 { 00107 return 0; 00108 } 00109 #endif 00110 00111 m_file = ::fdopen(d, cppModeToCMode(posixModeToCppMode(flags))); 00112 if (m_file == 0) 00113 { 00114 return 0; 00115 } 00116 ::setbuf(m_file, 0); 00117 fd.release(); 00118 return this; 00119 } 00120 00121 #if 0 00122 FileBuf* 00123 FileBuf::open(const File& f) 00124 { 00125 if (isOpen()) 00126 { 00127 return 0; 00128 } 00129 int flags = ::fcntl(f.???, F_GETFL); 00130 if (flags == -1) 00131 { 00132 return 0; 00133 } 00134 00135 m_file = ::fdopen(???, cppModeToCMode(posixModeToCppMode(flags))); 00136 if (m_file == 0) 00137 { 00138 return 0; 00139 } 00140 ::setbuf(m_file, 0); 00141 return this; 00142 } 00143 #endif 00144 00145 FileBuf* 00146 FileBuf::open(const char* path, std::ios_base::openmode mode, mode_t permissions) 00147 { 00148 if (isOpen()) 00149 { 00150 return 0; 00151 } 00152 00153 int d = ::open(path, cppModeToPOSIXMode(mode), permissions); 00154 00155 #ifdef BLOCXX_WIN32 00156 Descriptor h = reinterpret_cast<Descriptor>(_get_osfhandle(d)); 00157 AutoDescriptor fd(h); 00158 #else 00159 AutoDescriptor fd(d); 00160 #endif 00161 00162 if (fd.get() == BLOCXX_INVALID_HANDLE) 00163 { 00164 return 0; 00165 } 00166 00167 m_file = ::fdopen(d, cppModeToCMode(mode)); 00168 00169 if (m_file == 0) 00170 { 00171 return 0; 00172 } 00173 00174 ::setbuf(m_file, 0); 00175 fd.release(); 00176 00177 return this; 00178 } 00179 00180 FileBuf* 00181 FileBuf::close() 00182 { 00183 if (isOpen()) 00184 { 00185 ::fclose(m_file); 00186 } 00187 m_file = 0; 00188 return this; 00189 } 00190 00191 int 00192 FileBuf::buffer_to_device(const char* c, int n) 00193 { 00194 size_t written = ::fwrite(c, 1, n, m_file); 00195 if (written == static_cast<size_t>(n)) 00196 { 00197 return 0; 00198 } 00199 else 00200 { 00201 return -1; 00202 } 00203 } 00204 00205 int 00206 FileBuf::buffer_from_device(char* c, int n) 00207 { 00208 if (!isOpen()) 00209 { 00210 return -1; 00211 } 00212 size_t numRead = ::fread(c, 1, n, m_file); 00213 if (numRead != static_cast<size_t>(n)) 00214 { 00215 if (ferror(m_file)) 00216 { 00217 BLOCXX_THROW_ERRNO_MSG(IOException, "FileBuf::buffer_from_device: ::fread()"); 00218 } 00219 else if (feof(m_file) && numRead == 0) 00220 { 00221 return -1; 00222 } 00223 else 00224 { 00225 return numRead; 00226 } 00227 } 00228 else 00229 { 00230 return n; 00231 } 00232 } 00233 00234 std::ios_base::openmode 00235 FileBuf::posixModeToCppMode(int posixMode) 00236 { 00237 std::ios_base::openmode mode = posixMode & O_APPEND ? std::ios::app : std::ios_base::openmode(0); 00238 00239 #ifdef BLOCXX_WIN32 00240 #define O_ACCMODE 3 00241 #endif 00242 switch (posixMode & O_ACCMODE) 00243 { 00244 case O_RDONLY: mode |= (std::ios::in | std::ios::binary); break; 00245 case O_WRONLY: mode |= (std::ios::out | std::ios::binary); break; 00246 case O_RDWR: mode |= (std::ios::in | std::ios::out | std::ios::binary); break; 00247 } 00248 return mode; 00249 } 00250 00251 int 00252 FileBuf::cppModeToPOSIXMode(std::ios_base::openmode cppMode) 00253 { 00254 int mode = 0; 00255 if (cppMode & std::ios::app) 00256 { 00257 mode |= O_APPEND; 00258 } 00259 00260 if (cppMode & std::ios::trunc) 00261 { 00262 mode |= O_TRUNC; 00263 } 00264 00265 if (cppMode & (std::ios::in | std::ios::out)) 00266 { 00267 mode |= O_RDWR; 00268 } 00269 else if (cppMode & std::ios::in) 00270 { 00271 mode |= O_RDONLY; 00272 } 00273 else if (cppMode & std::ios::out) 00274 { 00275 mode |= O_WRONLY; 00276 } 00277 return mode; 00278 } 00279 00280 const char* FileBuf::cppModeToCMode(std::ios_base::openmode cppMode) 00281 { 00282 // mask out irrelevant bits 00283 cppMode = cppMode & ~std::ios::ate; 00284 00285 using std::ios; 00286 // can't use a switch here because the ios flags aren't native types. 00287 if( cppMode == ios::app || 00288 cppMode == (ios::in|ios::app) || 00289 cppMode == (ios::out|ios::app) ) 00290 { 00291 return "a"; 00292 } 00293 00294 else if( cppMode == (ios::binary|ios::app) || 00295 cppMode == (ios::in|ios::binary|ios::app) || 00296 cppMode == (ios::out|ios::binary|ios::app) ) 00297 { 00298 return "ab"; 00299 } 00300 00301 else if (cppMode == ios::in) 00302 { 00303 return "r"; 00304 } 00305 00306 else if (cppMode == (ios::in|ios::binary)) 00307 { 00308 return "rb"; 00309 } 00310 00311 else if (cppMode == (ios::out|ios::in)) 00312 { 00313 return "r+"; 00314 } 00315 00316 else if (cppMode == (ios::out|ios::in|ios::app)) 00317 { 00318 return "a+"; 00319 } 00320 00321 else if (cppMode == (ios::out|ios::in|ios::binary)) 00322 { 00323 return "r+b"; 00324 } 00325 00326 else if (cppMode == (ios::out|ios::in|ios::binary|ios::app)) 00327 { 00328 return "a+b"; 00329 } 00330 00331 else if( (cppMode == ios::out) || 00332 cppMode == (ios::trunc) || 00333 cppMode == (ios::trunc|ios::app) || 00334 cppMode == (ios::trunc|ios::out) || 00335 cppMode == (ios::trunc|ios::out|ios::app) ) 00336 { 00337 return "w"; 00338 } 00339 00340 else if( (cppMode == (ios::trunc|ios::binary)) || 00341 (cppMode == (ios::trunc|ios::binary|ios::app)) || 00342 (cppMode == (ios::out|ios::binary)) || 00343 (cppMode == (ios::trunc|ios::out|ios::binary)) || 00344 (cppMode == (ios::trunc|ios::out|ios::binary|ios::app) )) 00345 { 00346 return "wb"; 00347 } 00348 00349 else if( (cppMode == (ios::trunc|ios::out|ios::in)) || 00350 (cppMode == (ios::trunc|ios::out|ios::in|ios::app)) ) 00351 { 00352 return "w+"; 00353 } 00354 00355 else if( (cppMode == (ios::trunc|ios::out|ios::in|ios::binary)) || 00356 (cppMode == (ios::trunc|ios::out|ios::in|ios::binary|ios::app)) ) 00357 { 00358 return "w+b"; 00359 } 00360 else 00361 { 00362 return ""; // bad mode 00363 } 00364 00365 } 00366 00367 00368 } // end namespace BLOCXX_NAMESPACE 00369 00370