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 */