blocxx

FileBuf.cpp

Go to the documentation of this file.
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