ofstd/include/dcmtk/ofstd/offile.h

00001 /*
00002  *
00003  *  Copyright (C) 2006-2010, OFFIS e.V.
00004  *  All rights reserved.  See COPYRIGHT file for details.
00005  *
00006  *  This software and supporting documentation were developed by
00007  *
00008  *    OFFIS e.V.
00009  *    R&D Division Health
00010  *    Escherweg 2
00011  *    D-26121 Oldenburg, Germany
00012  *
00013  *
00014  *  Module:  ofstd
00015  *
00016  *  Author:  Marco Eichelberg
00017  *
00018  *  Purpose: C++ wrapper class for stdio FILE functions
00019  *
00020  *  Last Update:      $Author: joergr $
00021  *  Update Date:      $Date: 2010-10-14 13:15:50 $
00022  *  CVS/RCS Revision: $Revision: 1.13 $
00023  *  Status:           $State: Exp $
00024  *
00025  *  CVS/RCS Log at end of file
00026  *
00027  */
00028 
00029 #ifndef OFFILE_H
00030 #define OFFILE_H
00031 
00032 #include "dcmtk/config/osconfig.h"
00033 #include "dcmtk/ofstd/oftypes.h"    /* for class OFBool */
00034 #include "dcmtk/ofstd/ofstring.h"   /* for class OFString */
00035 #include "dcmtk/ofstd/ofstd.h"      /* for class OFStandard */
00036 
00037 #define INCLUDE_UNISTD
00038 #define INCLUDE_CSTDIO
00039 #define INCLUDE_CSTRING
00040 #define INCLUDE_CSTDARG
00041 #define INCLUDE_CERRNO
00042 #define INCLUDE_CWCHAR
00043 #include "dcmtk/ofstd/ofstdinc.h"
00044 
00045 BEGIN_EXTERN_C
00046 #ifdef HAVE_SYS_STAT_H
00047 #include <sys/stat.h>   /* needed for struct _stati64 on Win32 */
00048 #endif
00049 END_EXTERN_C
00050 
00051 /* When using the ISO C++ include files such as <cstdio>, <cstdarg> etc.,
00052  * all ANSI C functions like fopen() are declared in namespace std,
00053  * (e.g. we have to use std::fopen()), but non-ANSI Posix functions remain
00054  * in global namespace, e.g. we have to use ::fopen64().
00055  * To make things even more difficult, not all compilers really declare
00056  * ANSI C functions in namespace std in accordance with the C++ standard.
00057  * Yes, this is ugly.
00058  */
00059 
00060 /* Find out whether current operating system needs explicit function calls
00061  * to handle large file support
00062  */
00063 #ifdef _LARGEFILE64_SOURCE
00064 // Mac OSX defines _LARGEFILE64_SOURCE but anyhow expects implicit 64 bit calls
00065   #if !(defined(__MACH__) && defined(__APPLE__))
00066     #define EXPLICIT_LFS_64
00067 #endif
00068 #endif
00069 
00070 #if defined(_WIN32) && !defined(__MINGW32__)
00071   // On Win32 systems except MinGW (where Posix definitions are available)
00072   // we use Win32 specific definitions
00073   typedef __int64 offile_off_t;
00074   typedef fpos_t offile_fpos_t;
00075 #else
00076   #ifdef EXPLICIT_LFS_64
00077     // Explicit LFS (LFS64)
00078     typedef fpos64_t offile_fpos_t;
00079     typedef off64_t offile_off_t;
00080   #else
00081     // Implicit LFS or no LFS
00082     #ifdef HAVE_FSEEKO
00083       typedef off_t offile_off_t;
00084     #else
00085       typedef long offile_off_t;
00086     #endif
00087     typedef fpos_t offile_fpos_t;
00088   #endif
00089 #endif
00090 
00091 // the type we use to store the last error.
00092 typedef int offile_errno_t;
00093 
00107 class OFFile
00108 {
00109 public:
00111   OFFile(): file_(NULL), popened_(OFFalse), lasterror_(0) {}
00112 
00116   OFFile(FILE *f): file_(f), popened_(OFFalse), lasterror_(0) {}
00117 
00119   ~OFFile()
00120   {
00121     if (file_) fclose();
00122   }
00123 
00131   OFBool fopen(const char *filename, const char *modes)
00132   {
00133     if (file_) fclose();
00134 #ifdef EXPLICIT_LFS_64
00135     file_ = :: fopen64(filename, modes);
00136 #else
00137     file_ = STDIO_NAMESPACE fopen(filename, modes);
00138 #endif
00139     if (file_) popened_ = OFFalse; else storeLastError();
00140     return (file_ != NULL);
00141   }
00142 
00143 #ifdef _WIN32
00144 
00150   OFBool wfopen(const wchar_t *filename, const wchar_t *modes)
00151   {
00152     if (file_) fclose();
00153     file_ = _wfopen(filename, modes);
00154     if (file_) popened_ = OFFalse; else storeLastError();
00155     return (file_ != NULL);
00156   }
00157 #endif
00158 
00171   OFBool fdopen(int fd, const char *modes)
00172   {
00173     if (file_) fclose();
00174     file_ = :: fdopen(fd, modes);
00175     if (file_) popened_ = OFFalse; else storeLastError();
00176     return (file_ != NULL);
00177   }
00178 
00188   OFBool popen(const char *command, const char *modes)
00189   {
00190     if (file_) fclose();
00191 #ifdef _WIN32
00192     file_ = _popen(command, modes);
00193 #else
00194     file_ = :: popen(command, modes);
00195 #endif
00196     if (file_) popened_ = OFTrue; else storeLastError();
00197     return (file_ != NULL);
00198   }
00199 
00209   OFBool freopen(const char *filename, const char *modes)
00210   {
00211 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00212     // MinGW has EXPLICIT_LFS_64 but no freopen64()
00213     file_ = :: freopen64(filename, modes, file_);
00214 #else
00215     file_ = STDIO_NAMESPACE freopen(filename, modes, file_);
00216 #endif
00217     if (file_) popened_ = OFFalse; else storeLastError();
00218     return (file_ != NULL);
00219   }
00220 
00226   OFBool tmpfile()
00227   {
00228     if (file_) fclose();
00229 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00230     // MinGW has EXPLICIT_LFS_64 but no tmpfile64()
00231     file_ = :: tmpfile64();
00232 #else
00233     file_ = STDIO_NAMESPACE tmpfile();
00234 #endif
00235     if (file_) popened_ = OFFalse; else storeLastError();
00236     return (file_ != NULL);
00237   }
00238 
00246   int fclose()
00247   {
00248     int result = 0;
00249     if (file_)
00250     {
00251       if (popened_)
00252       {
00253 #ifdef _WIN32
00254         result = _pclose(file_);
00255 #else
00256         result = :: pclose(file_);
00257 #endif
00258       }
00259       else
00260       {
00261         result = STDIO_NAMESPACE fclose(file_);
00262       }
00263       // After calling fclose() once, the FILE* is gone even if fclose() failed.
00264       file_ = NULL;
00265     }
00266     if (result) storeLastError();
00267     return result;
00268   }
00269 
00275   int pclose() { return fclose(); }
00276 
00286   size_t fwrite(const void *ptr, size_t size, size_t n)
00287   {
00288     return STDIO_NAMESPACE fwrite(ptr, size, n, file_);
00289   }
00290 
00302   size_t fread(void *ptr, size_t size, size_t n)
00303   {
00304     return STDIO_NAMESPACE fread(ptr, size, n, file_);
00305   }
00306 
00312   int fflush()
00313   {
00314     int result = STDIO_NAMESPACE fflush(file_);
00315     if (result) storeLastError();
00316     return result;
00317   }
00318 
00323   int fgetc() { return STDIO_NAMESPACE fgetc(file_); }
00324 
00338   void setlinebuf()
00339   {
00340 #ifdef _WIN32
00341     this->setvbuf(NULL, _IOLBF, 0);
00342 #else
00343     :: setlinebuf(file_);
00344 #endif
00345   }
00346 
00351   void rewind() { STDIO_NAMESPACE rewind(file_); }
00352 
00355   void clearerr() { STDIO_NAMESPACE clearerr(file_); }
00356 
00363   int eof() const
00364   {
00365 #ifdef _WIN32
00366     // feof is a macro on Win32. Macros never have namespaces.
00367     return feof(file_);
00368 #else
00369     return STDIO_NAMESPACE feof(file_);
00370 #endif
00371   }
00372 
00379   int error()
00380   {
00381 #ifdef _WIN32
00382     // ferror is a macro on Win32. Macros never have namespaces.
00383     return ferror(file_);
00384 #else
00385     return STDIO_NAMESPACE ferror(file_);
00386 #endif
00387   }
00388 
00395 #ifdef fileno
00396   int fileNo() { return fileno(file_); }
00397 #else
00398   int fileNo() { return :: fileno(file_); }
00399 #endif
00400 
00414   void setbuf(char *buf) { STDIO_NAMESPACE setbuf(file_, buf); }
00415 
00431   int setvbuf(char * buf, int modes, size_t n)
00432   {
00433     int result = STDIO_NAMESPACE setvbuf(file_, buf, modes, n);
00434     if (result) storeLastError();
00435     return result;
00436   }
00437 
00452   void setbuffer(char *buf, size_t size)
00453   {
00454 #ifdef _WIN32
00455     this->setvbuf(NULL, buf ? _IOFBF : _IONBF, size);
00456 #else
00457     :: setbuffer(file_, buf, size);
00458 #endif
00459   }
00460 
00465   int fputc(int c) { return STDIO_NAMESPACE fputc(c, file_); }
00466 
00475   char *fgets(char *s, int n) { return STDIO_NAMESPACE fgets(s, n, file_); }
00476 
00481   int fputs(const char *s) { return STDIO_NAMESPACE fputs(s, file_); }
00482 
00489   int ungetc(int c) { return STDIO_NAMESPACE ungetc(c, file_); }
00490 
00502   int fseek(offile_off_t off, int whence)
00503   {
00504     int result;
00505 #ifdef _WIN32
00506     // Windows does not have a 64-bit fseek.
00507     // We emulate fseek through fsetpos, which does exist on Windows.
00508     // fpos_t is (hopefully always) defined as __int64 on this platform
00509     offile_fpos_t off2 = off;
00510     fpos_t pos;
00511     struct _stati64 buf;
00512     switch (whence)
00513     {
00514       case SEEK_END:
00515         // flush write buffer, if any, so that the file size is correct
00516         STDIO_NAMESPACE fflush(file_);
00517 #if 0
00518         // Python implementation based on _lseeki64(). May be unsafe because
00519         // there is no guarantee that fflush also empties read buffers.
00520         STDIO_NAMESPACE fflush(file_);
00521 #ifdef fileno
00522         if (_lseeki64(   fileno(file_), 0, 2) == -1)
00523 #else
00524         if (_lseeki64(:: fileno(file_), 0, 2) == -1)
00525 #endif
00526         {
00527           storeLastError();
00528           return -1;
00529         }
00530         // fall through
00531 #else
00532         // determine file size (using underlying file descriptor). This should be safe.
00533 #ifdef fileno
00534         if (_fstati64(   fileno(file_), &buf) == -1)
00535 #else
00536         if (_fstati64(:: fileno(file_), &buf) == -1)
00537 #endif
00538         {
00539           storeLastError();
00540           return -1;
00541         }
00542 
00543         // fsetpos position is offset + file size.
00544         off2 += buf.st_size;
00545         break;
00546 #endif
00547       case SEEK_CUR:
00548         if (STDIO_NAMESPACE fgetpos(file_, &pos) != 0)
00549         {
00550           storeLastError();
00551           return -1;
00552         }
00553 
00554         off2 += pos;
00555         break;
00556       case SEEK_SET:
00557         /* do nothing */
00558         break;
00559     }
00560     result = this->fsetpos(&off2);
00561 #elif defined(__BEOS__)
00562     result = :: _fseek(fp, offset, whence);
00563 #else
00564 #ifdef HAVE_FSEEKO
00565 #ifdef EXPLICIT_LFS_64
00566     result = :: fseeko64(file_, off, whence);
00567 #else
00568     result = :: fseeko(file_, off, whence);
00569 #endif
00570 #else
00571     result = STDIO_NAMESPACE fseek(file_, off, whence);
00572 #endif
00573 #endif
00574     if (result) storeLastError();
00575     return result;
00576   }
00577 
00581   offile_off_t ftell()
00582   {
00583     offile_off_t result;
00584 #ifdef _WIN32
00585     // Windows does not have a 64-bit ftell, and _telli64 cannot be used
00586     // because it operates on file descriptors and ignores FILE buffers.
00587     // We emulate ftell through fgetpos, which does exist on Windows.
00588     // fpos_t is (hopefully always) defined as __int64 on this platform.
00589     offile_fpos_t pos;
00590     if (this->fgetpos(&pos) != 0)
00591     {
00592       storeLastError();
00593       return -1;
00594     }
00595     return pos;
00596 #else
00597 #ifdef HAVE_FSEEKO
00598 #ifdef EXPLICIT_LFS_64
00599     result = :: ftello64(file_);
00600 #else
00601     result = :: ftello(file_);
00602 #endif
00603 #else
00604     result = STDIO_NAMESPACE ftell(file_);
00605 #endif
00606 #endif
00607     if (result < 0) storeLastError();
00608     return result;
00609   }
00610 
00618   int fgetpos(offile_fpos_t *pos)
00619   {
00620     int result;
00621 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00622     // MinGW has EXPLICIT_LFS_64 but no fgetpos64()
00623     result = :: fgetpos64(file_, pos);
00624 #else
00625     result = STDIO_NAMESPACE fgetpos(file_, pos);
00626 #endif
00627     if (result) storeLastError();
00628     return result;
00629   }
00630 
00638   int fsetpos(offile_fpos_t *pos)
00639   {
00640     int result;
00641 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00642     // MinGW has EXPLICIT_LFS_64 but no fsetpos64()
00643     result = :: fsetpos64(file_, pos);
00644 #else
00645     result = STDIO_NAMESPACE fsetpos(file_, pos);
00646 #endif
00647     if (result) storeLastError();
00648     return result;
00649   }
00650 
00656   int fprintf(const char *format, ...)
00657   {
00658     int result = 0;
00659     va_list ap;
00660     va_start(ap, format);
00661     result = STDIO_NAMESPACE vfprintf(file_, format, ap);
00662     va_end(ap);
00663     return result;
00664   }
00665 
00671    int vfprintf(const char *format, va_list arg)
00672    {
00673      return STDIO_NAMESPACE vfprintf(file_, format, arg);
00674    }
00675 
00676   // we cannot emulate fscanf because we would need vfscanf for this
00677   // purpose, which does not exist, e.g. on Win32.
00678 
00684   FILE *file() { return file_; }
00685 
00689   OFBool open() const { return file_ != NULL; }
00690 
00694   offile_errno_t getLastError() const { return lasterror_; }
00695 
00699   void getLastErrorString(OFString& s) const
00700   {
00701     char buf[1000];
00702     s = OFStandard::strerror(lasterror_, buf, 1000);
00703   }
00704 
00705 // Cygwin does not support the wide character functions
00706 #ifndef __CYGWIN__
00707 
00725   int fwide(int mode)
00726   {
00727     return STDIO_NAMESPACE fwide(file_, mode);
00728   }
00729 
00736   wint_t fgetwc()
00737   {
00738     wint_t result = STDIO_NAMESPACE fgetwc(file_);
00739     if (result == WEOF) storeLastError();
00740     return result;
00741   }
00742 
00749   wint_t fputwc(wchar_t wc)
00750   {
00751     wint_t result = STDIO_NAMESPACE fputwc(wc, file_);
00752     if (result == WEOF) storeLastError();
00753     return result;
00754   }
00755 
00770   wint_t ungetwc(wint_t wc)
00771   {
00772     wint_t result = STDIO_NAMESPACE ungetwc(wc, file_);
00773     if (result == WEOF) storeLastError();
00774     return result;
00775   }
00776 
00782   int fwprintf(const wchar_t *format, ...)
00783   {
00784     int result = 0;
00785     va_list ap;
00786     va_start(ap, format);
00787     result = STDIO_NAMESPACE vfwprintf(file_, format, ap);
00788     va_end(ap);
00789     return result;
00790   }
00791 
00797    int vfwprintf(const wchar_t *format, va_list arg)
00798    {
00799      return STDIO_NAMESPACE vfwprintf(file_, format, arg);
00800    }
00801 
00802   // we cannot emulate fwscanf because we would need vfwscanf for this
00803   // purpose, which does not exist, e.g. on Win32.
00804 
00805 #endif /* __CYGWIN__ */
00806 
00807 private:
00808 
00809   // private undefined copy constructor
00810   OFFile(const OFFile &arg);
00811 
00812   // private undefined assignment operator
00813   OFFile &operator=(const OFFile &arg);
00814 
00816   FILE *file_;
00817 
00819   OFBool popened_;
00820 
00822   offile_errno_t lasterror_;
00823 
00825   inline void storeLastError()
00826   {
00827     lasterror_ = errno;
00828   }
00829 
00830 };
00831 
00832 
00833 #endif
00834 
00835 /*
00836  * CVS/RCS Log:
00837  * $Log: offile.h,v $
00838  * Revision 1.13  2010-10-14 13:15:50  joergr
00839  * Updated copyright header. Added reference to COPYRIGHT file.
00840  *
00841  * Revision 1.12  2010-06-02 12:55:30  joergr
00842  * Introduced new helper function strerror() which is used as a wrapper to the
00843  * various approaches found on different systems.
00844  *
00845  * Revision 1.11  2010-04-26 12:22:30  uli
00846  * Fixed a some minor doxygen warnings.
00847  *
00848  * Revision 1.10  2009-09-24 07:10:52  meichel
00849  * Fixed bug in class OFFile that caused undefined behaviour
00850  *   once fclose() failed
00851  *
00852  * Revision 1.9  2009-08-10 07:52:09  meichel
00853  * Some modifications needed to make class OFFile compile on MinGW.
00854  *
00855  * Revision 1.8  2009-03-12 11:37:54  joergr
00856  * Fixed various Doxygen API documentation issues.
00857  *
00858  * Revision 1.7  2009-02-13 12:56:18  joergr
00859  * Added private undefined copy constructor and assignment operator in order to
00860  * avoid compiler warnings (reported by gcc with additional flags).
00861  *
00862  * Revision 1.6  2009-01-30 13:49:01  joergr
00863  * Replaced checking of macro WIN32 by _WIN32.
00864  *
00865  * Revision 1.5  2008-05-29 10:37:11  meichel
00866  *  Fixed compile error on Cygwin where no wide-char FILE functions are available
00867  *
00868  * Revision 1.4  2008-02-07 16:57:46  meichel
00869  * Class OFFile now makes use of HAVE_CHARP_STRERROR_R to use the
00870  *   correct version of strerror_r.
00871  *
00872  * Revision 1.3  2007/06/06 13:55:58  onken
00873  * Fixed compilation for Mac OS X with making large file support function calls
00874  * implicit for this OS (Mac OS X misleadingly defines _LARGEFILE64_SOURCE).
00875  *
00876  * Revision 1.2  2007/02/19 16:03:47  meichel
00877  * Added constructor to class OFFile that takes FILE * as argument.
00878  *
00879  * Revision 1.1  2006/08/21 12:40:44  meichel
00880  * Added new class OFFile that provides a simple encapsulation layer for
00881  *   FILE based stream I/O and, in particular, provides long file support
00882  *   (LFS) if available on the underlying operating system platform through
00883  *   a single API.
00884  *
00885  *
00886  */


Generated on 30 Nov 2010 for OFFIS DCMTK Version 3.5.5 20101130 by Doxygen 1.5.1