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