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-12-17 10:50:30 $
00022  *  CVS/RCS Revision: $Revision: 1.17 $
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    /* not yet implemented in "ofstdinc.h" */
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 /* HP-UX has clearerr both as macro and as a function definition. We have to
00052  * undef the macro so that we can define a function called "clearerr".
00053  */
00054 #if defined(__hpux) && defined(clearerr)
00055 #undef clearerr
00056 #endif
00057 
00058 /* When using the ISO C++ include files such as <cstdio>, <cstdarg> etc.,
00059  * all ANSI C functions like fopen() are declared in namespace std,
00060  * (e.g. we have to use std::fopen()), but non-ANSI Posix functions remain
00061  * in global namespace, e.g. we have to use ::fopen64().
00062  * To make things even more difficult, not all compilers really declare
00063  * ANSI C functions in namespace std in accordance with the C++ standard.
00064  * Yes, this is ugly.
00065  */
00066 
00067 /* Find out whether current operating system needs explicit function calls
00068  * to handle large file support
00069  */
00070 #ifdef _LARGEFILE64_SOURCE
00071   // Mac OS X defines _LARGEFILE64_SOURCE but anyhow expects implicit 64 bit calls.
00072   // The same is true for current Cygwin versions (tested with version 1.7.7-1).
00073   #if !(defined(__MACH__) && defined(__APPLE__)) && !defined(__CYGWIN__)
00074     #define EXPLICIT_LFS_64
00075   #endif
00076 #endif
00077 
00078 #if defined(_WIN32) && !defined(__MINGW32__)
00079   // On Win32 systems except MinGW (where Posix definitions are available)
00080   // we use Win32 specific definitions
00081   typedef __int64 offile_off_t;
00082   typedef fpos_t offile_fpos_t;
00083 #else
00084   #ifdef EXPLICIT_LFS_64
00085     // Explicit LFS (LFS64)
00086     typedef fpos64_t offile_fpos_t;
00087     typedef off64_t offile_off_t;
00088   #else
00089     // Implicit LFS or no LFS
00090     #ifdef HAVE_FSEEKO
00091       typedef off_t offile_off_t;
00092     #else
00093       typedef long offile_off_t;
00094     #endif
00095     typedef fpos_t offile_fpos_t;
00096   #endif
00097 #endif
00098 
00099 // the type we use to store the last error.
00100 typedef int offile_errno_t;
00101 
00115 class OFFile
00116 {
00117 public:
00119   OFFile(): file_(NULL), popened_(OFFalse), lasterror_(0) {}
00120 
00124   OFFile(FILE *f): file_(f), popened_(OFFalse), lasterror_(0) {}
00125 
00127   ~OFFile()
00128   {
00129     if (file_) fclose();
00130   }
00131 
00139   OFBool fopen(const char *filename, const char *modes)
00140   {
00141     if (file_) fclose();
00142 #ifdef EXPLICIT_LFS_64
00143     file_ = :: fopen64(filename, modes);
00144 #else
00145     file_ = STDIO_NAMESPACE fopen(filename, modes);
00146 #endif
00147     if (file_) popened_ = OFFalse; else storeLastError();
00148     return (file_ != NULL);
00149   }
00150 
00151 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
00152 
00158   OFBool wfopen(const wchar_t *filename, const wchar_t *modes)
00159   {
00160     if (file_) fclose();
00161     file_ = _wfopen(filename, modes);
00162     if (file_) popened_ = OFFalse; else storeLastError();
00163     return (file_ != NULL);
00164   }
00165 #endif
00166 
00179   OFBool fdopen(int fd, const char *modes)
00180   {
00181     if (file_) fclose();
00182     file_ = :: fdopen(fd, modes);
00183     if (file_) popened_ = OFFalse; else storeLastError();
00184     return (file_ != NULL);
00185   }
00186 
00196   OFBool popen(const char *command, const char *modes)
00197   {
00198     if (file_) fclose();
00199 #ifdef _WIN32
00200     file_ = _popen(command, modes);
00201 #else
00202     file_ = :: popen(command, modes);
00203 #endif
00204     if (file_) popened_ = OFTrue; else storeLastError();
00205     return (file_ != NULL);
00206   }
00207 
00217   OFBool freopen(const char *filename, const char *modes)
00218   {
00219 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00220     // MinGW has EXPLICIT_LFS_64 but no freopen64()
00221     file_ = :: freopen64(filename, modes, file_);
00222 #else
00223     file_ = STDIO_NAMESPACE freopen(filename, modes, file_);
00224 #endif
00225     if (file_) popened_ = OFFalse; else storeLastError();
00226     return (file_ != NULL);
00227   }
00228 
00234   OFBool tmpfile()
00235   {
00236     if (file_) fclose();
00237 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00238     // MinGW has EXPLICIT_LFS_64 but no tmpfile64()
00239     file_ = :: tmpfile64();
00240 #else
00241     file_ = STDIO_NAMESPACE tmpfile();
00242 #endif
00243     if (file_) popened_ = OFFalse; else storeLastError();
00244     return (file_ != NULL);
00245   }
00246 
00254   int fclose()
00255   {
00256     int result = 0;
00257     if (file_)
00258     {
00259       if (popened_)
00260       {
00261 #ifdef _WIN32
00262         result = _pclose(file_);
00263 #else
00264         result = :: pclose(file_);
00265 #endif
00266       }
00267       else
00268       {
00269         result = STDIO_NAMESPACE fclose(file_);
00270       }
00271       // After calling fclose() once, the FILE* is gone even if fclose() failed.
00272       file_ = NULL;
00273     }
00274     if (result) storeLastError();
00275     return result;
00276   }
00277 
00283   int pclose() { return fclose(); }
00284 
00294   size_t fwrite(const void *ptr, size_t size, size_t n)
00295   {
00296     return STDIO_NAMESPACE fwrite(ptr, size, n, file_);
00297   }
00298 
00310   size_t fread(void *ptr, size_t size, size_t n)
00311   {
00312     return STDIO_NAMESPACE fread(ptr, size, n, file_);
00313   }
00314 
00320   int fflush()
00321   {
00322     int result = STDIO_NAMESPACE fflush(file_);
00323     if (result) storeLastError();
00324     return result;
00325   }
00326 
00331   int fgetc() { return STDIO_NAMESPACE fgetc(file_); }
00332 
00346   void setlinebuf()
00347   {
00348 #if defined(_WIN32) || defined(__hpux)
00349     this->setvbuf(NULL, _IOLBF, 0);
00350 #else
00351     :: setlinebuf(file_);
00352 #endif
00353   }
00354 
00359   void rewind() { STDIO_NAMESPACE rewind(file_); }
00360 
00363   void clearerr() { STDIO_NAMESPACE clearerr(file_); }
00364 
00371   int eof() const
00372   {
00373 #ifdef feof
00374     // feof is a macro on some systems. Macros never have namespaces.
00375     return feof(file_);
00376 #else
00377     return STDIO_NAMESPACE feof(file_);
00378 #endif
00379   }
00380 
00387   int error()
00388   {
00389 #ifdef ferror
00390     // ferror is a macro on some systems. Macros never have namespaces.
00391     return ferror(file_);
00392 #else
00393     return STDIO_NAMESPACE ferror(file_);
00394 #endif
00395   }
00396 
00403 #ifdef fileno
00404   int fileNo() { return fileno(file_); }
00405 #else
00406   int fileNo() { return :: fileno(file_); }
00407 #endif
00408 
00422   void setbuf(char *buf) { STDIO_NAMESPACE setbuf(file_, buf); }
00423 
00439   int setvbuf(char * buf, int modes, size_t n)
00440   {
00441     int result = STDIO_NAMESPACE setvbuf(file_, buf, modes, n);
00442     if (result) storeLastError();
00443     return result;
00444   }
00445 
00460   void setbuffer(char *buf, size_t size)
00461   {
00462 #if defined(_WIN32) || defined(__hpux)
00463     this->setvbuf(NULL, buf ? _IOFBF : _IONBF, size);
00464 #else
00465     :: setbuffer(file_, buf, size);
00466 #endif
00467   }
00468 
00473   int fputc(int c) { return STDIO_NAMESPACE fputc(c, file_); }
00474 
00483   char *fgets(char *s, int n) { return STDIO_NAMESPACE fgets(s, n, file_); }
00484 
00489   int fputs(const char *s) { return STDIO_NAMESPACE fputs(s, file_); }
00490 
00497   int ungetc(int c) { return STDIO_NAMESPACE ungetc(c, file_); }
00498 
00510   int fseek(offile_off_t off, int whence)
00511   {
00512     int result;
00513 #ifdef _WIN32
00514     // Windows does not have a 64-bit fseek.
00515     // We emulate fseek through fsetpos, which does exist on Windows.
00516     // fpos_t is (hopefully always) defined as __int64 on this platform
00517     offile_fpos_t off2 = off;
00518     fpos_t pos;
00519     struct _stati64 buf;
00520     switch (whence)
00521     {
00522       case SEEK_END:
00523         // flush write buffer, if any, so that the file size is correct
00524         STDIO_NAMESPACE fflush(file_);
00525 #if 0
00526         // Python implementation based on _lseeki64(). May be unsafe because
00527         // there is no guarantee that fflush also empties read buffers.
00528         STDIO_NAMESPACE fflush(file_);
00529 #ifdef fileno
00530         if (_lseeki64(   fileno(file_), 0, 2) == -1)
00531 #else
00532         if (_lseeki64(:: fileno(file_), 0, 2) == -1)
00533 #endif
00534         {
00535           storeLastError();
00536           return -1;
00537         }
00538         // fall through
00539 #else
00540         // determine file size (using underlying file descriptor). This should be safe.
00541 #ifdef fileno
00542         if (_fstati64(   fileno(file_), &buf) == -1)
00543 #else
00544         if (_fstati64(:: fileno(file_), &buf) == -1)
00545 #endif
00546         {
00547           storeLastError();
00548           return -1;
00549         }
00550 
00551         // fsetpos position is offset + file size.
00552         off2 += buf.st_size;
00553         break;
00554 #endif
00555       case SEEK_CUR:
00556         if (STDIO_NAMESPACE fgetpos(file_, &pos) != 0)
00557         {
00558           storeLastError();
00559           return -1;
00560         }
00561 
00562         off2 += pos;
00563         break;
00564       case SEEK_SET:
00565         /* do nothing */
00566         break;
00567     }
00568     result = this->fsetpos(&off2);
00569 #elif defined(__BEOS__)
00570     result = :: _fseek(fp, offset, whence);
00571 #else
00572 #ifdef HAVE_FSEEKO
00573 #ifdef EXPLICIT_LFS_64
00574     result = :: fseeko64(file_, off, whence);
00575 #else
00576     result = :: fseeko(file_, off, whence);
00577 #endif
00578 #else
00579     result = STDIO_NAMESPACE fseek(file_, off, whence);
00580 #endif
00581 #endif
00582     if (result) storeLastError();
00583     return result;
00584   }
00585 
00589   offile_off_t ftell()
00590   {
00591     offile_off_t result;
00592 #ifdef _WIN32
00593     // Windows does not have a 64-bit ftell, and _telli64 cannot be used
00594     // because it operates on file descriptors and ignores FILE buffers.
00595     // We emulate ftell through fgetpos, which does exist on Windows.
00596     // fpos_t is (hopefully always) defined as __int64 on this platform.
00597     offile_fpos_t pos;
00598     if (this->fgetpos(&pos) != 0)
00599     {
00600       storeLastError();
00601       return -1;
00602     }
00603     return pos;
00604 #else
00605 #ifdef HAVE_FSEEKO
00606 #ifdef EXPLICIT_LFS_64
00607     result = :: ftello64(file_);
00608 #else
00609     result = :: ftello(file_);
00610 #endif
00611 #else
00612     result = STDIO_NAMESPACE ftell(file_);
00613 #endif
00614 #endif
00615     if (result < 0) storeLastError();
00616     return result;
00617   }
00618 
00626   int fgetpos(offile_fpos_t *pos)
00627   {
00628     int result;
00629 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00630     // MinGW has EXPLICIT_LFS_64 but no fgetpos64()
00631     result = :: fgetpos64(file_, pos);
00632 #else
00633     result = STDIO_NAMESPACE fgetpos(file_, pos);
00634 #endif
00635     if (result) storeLastError();
00636     return result;
00637   }
00638 
00646   int fsetpos(offile_fpos_t *pos)
00647   {
00648     int result;
00649 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
00650     // MinGW has EXPLICIT_LFS_64 but no fsetpos64()
00651     result = :: fsetpos64(file_, pos);
00652 #else
00653     result = STDIO_NAMESPACE fsetpos(file_, pos);
00654 #endif
00655     if (result) storeLastError();
00656     return result;
00657   }
00658 
00664   int fprintf(const char *format, ...)
00665   {
00666     int result = 0;
00667     va_list ap;
00668     va_start(ap, format);
00669     result = STDIO_NAMESPACE vfprintf(file_, format, ap);
00670     va_end(ap);
00671     return result;
00672   }
00673 
00679    int vfprintf(const char *format, va_list arg)
00680    {
00681      return STDIO_NAMESPACE vfprintf(file_, format, arg);
00682    }
00683 
00684   // we cannot emulate fscanf because we would need vfscanf for this
00685   // purpose, which does not exist, e.g. on Win32.
00686 
00692   FILE *file() { return file_; }
00693 
00697   OFBool open() const { return file_ != NULL; }
00698 
00702   offile_errno_t getLastError() const { return lasterror_; }
00703 
00707   void getLastErrorString(OFString& s) const
00708   {
00709     char buf[1000];
00710     s = OFStandard::strerror(lasterror_, buf, 1000);
00711   }
00712 
00713 // wide character functions (disabled by default, since currently not used within DCMTK)
00714 #ifdef WIDE_CHAR_FILE_IO_FUNCTIONS
00715 
00733   int fwide(int mode)
00734   {
00735     return STDIO_NAMESPACE fwide(file_, mode);
00736   }
00737 
00744   wint_t fgetwc()
00745   {
00746     wint_t result = STDIO_NAMESPACE fgetwc(file_);
00747     if (result == WEOF) storeLastError();
00748     return result;
00749   }
00750 
00757   wint_t fputwc(wchar_t wc)
00758   {
00759     wint_t result = STDIO_NAMESPACE fputwc(wc, file_);
00760     if (result == WEOF) storeLastError();
00761     return result;
00762   }
00763 
00778   wint_t ungetwc(wint_t wc)
00779   {
00780     wint_t result = STDIO_NAMESPACE ungetwc(wc, file_);
00781     if (result == WEOF) storeLastError();
00782     return result;
00783   }
00784 
00790   int fwprintf(const wchar_t *format, ...)
00791   {
00792     int result = 0;
00793     va_list ap;
00794     va_start(ap, format);
00795     result = STDIO_NAMESPACE vfwprintf(file_, format, ap);
00796     va_end(ap);
00797     return result;
00798   }
00799 
00805    int vfwprintf(const wchar_t *format, va_list arg)
00806    {
00807      return STDIO_NAMESPACE vfwprintf(file_, format, arg);
00808    }
00809 
00810   // we cannot emulate fwscanf because we would need vfwscanf for this
00811   // purpose, which does not exist, e.g. on Win32.
00812 
00813 #endif /* WIDE_CHAR_FILE_IO_FUNCTIONS */
00814 
00815 private:
00816 
00817   // private undefined copy constructor
00818   OFFile(const OFFile &arg);
00819 
00820   // private undefined assignment operator
00821   OFFile &operator=(const OFFile &arg);
00822 
00824   FILE *file_;
00825 
00827   OFBool popened_;
00828 
00830   offile_errno_t lasterror_;
00831 
00833   inline void storeLastError()
00834   {
00835     lasterror_ = errno;
00836   }
00837 
00838 };
00839 
00840 
00841 #endif
00842 
00843 /*
00844  * CVS/RCS Log:
00845  * $Log: offile.h,v $
00846  * Revision 1.17  2010-12-17 10:50:30  joergr
00847  * Check whether "feof" and "ferror" are defined as macros (e.g. on IRIX 6.3).
00848  *
00849  * Revision 1.16  2010-12-15 11:29:07  uli
00850  * Made OFFile compile successfully on HP-UX.
00851  *
00852  * Revision 1.15  2010-12-08 16:04:35  joergr
00853  * Disable currently unused wide character file I/O functions in order to avoid
00854  * problems with old compilers (e.g. gcc 2.95.3).
00855  *
00856  * Revision 1.14  2010-12-06 13:02:49  joergr
00857  * Fixed issue with large file support for current Cygwin systems (1.7.7-1).
00858  *
00859  * Revision 1.13  2010-10-14 13:15:50  joergr
00860  * Updated copyright header. Added reference to COPYRIGHT file.
00861  *
00862  * Revision 1.12  2010-06-02 12:55:30  joergr
00863  * Introduced new helper function strerror() which is used as a wrapper to the
00864  * various approaches found on different systems.
00865  *
00866  * Revision 1.11  2010-04-26 12:22:30  uli
00867  * Fixed a some minor doxygen warnings.
00868  *
00869  * Revision 1.10  2009-09-24 07:10:52  meichel
00870  * Fixed bug in class OFFile that caused undefined behaviour
00871  *   once fclose() failed
00872  *
00873  * Revision 1.9  2009-08-10 07:52:09  meichel
00874  * Some modifications needed to make class OFFile compile on MinGW.
00875  *
00876  * Revision 1.8  2009-03-12 11:37:54  joergr
00877  * Fixed various Doxygen API documentation issues.
00878  *
00879  * Revision 1.7  2009-02-13 12:56:18  joergr
00880  * Added private undefined copy constructor and assignment operator in order to
00881  * avoid compiler warnings (reported by gcc with additional flags).
00882  *
00883  * Revision 1.6  2009-01-30 13:49:01  joergr
00884  * Replaced checking of macro WIN32 by _WIN32.
00885  *
00886  * Revision 1.5  2008-05-29 10:37:11  meichel
00887  *  Fixed compile error on Cygwin where no wide-char FILE functions are available
00888  *
00889  * Revision 1.4  2008-02-07 16:57:46  meichel
00890  * Class OFFile now makes use of HAVE_CHARP_STRERROR_R to use the
00891  *   correct version of strerror_r.
00892  *
00893  * Revision 1.3  2007/06/06 13:55:58  onken
00894  * Fixed compilation for Mac OS X with making large file support function calls
00895  * implicit for this OS (Mac OS X misleadingly defines _LARGEFILE64_SOURCE).
00896  *
00897  * Revision 1.2  2007/02/19 16:03:47  meichel
00898  * Added constructor to class OFFile that takes FILE * as argument.
00899  *
00900  * Revision 1.1  2006/08/21 12:40:44  meichel
00901  * Added new class OFFile that provides a simple encapsulation layer for
00902  *   FILE based stream I/O and, in particular, provides long file support
00903  *   (LFS) if available on the underlying operating system platform through
00904  *   a single API.
00905  *
00906  *
00907  */


Generated on 6 Jan 2011 for OFFIS DCMTK Version 3.6.0 by Doxygen 1.5.1