1039 lines
37 KiB
C
1039 lines
37 KiB
C
|
/*
|
||
|
*
|
||
|
* Copyright (C) 2006-2016, OFFIS e.V.
|
||
|
* All rights reserved. See COPYRIGHT file for details.
|
||
|
*
|
||
|
* This software and supporting documentation were developed by
|
||
|
*
|
||
|
* OFFIS e.V.
|
||
|
* R&D Division Health
|
||
|
* Escherweg 2
|
||
|
* D-26121 Oldenburg, Germany
|
||
|
*
|
||
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Marco Eichelberg, Joerg Riesmeier
|
||
|
*
|
||
|
* Purpose: C++ wrapper class for stdio FILE functions and
|
||
|
* wide character filenames
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef OFFILE_H
|
||
|
#define OFFILE_H
|
||
|
|
||
|
#include "dcmtk/config/osconfig.h"
|
||
|
|
||
|
#include "dcmtk/ofstd/oftypes.h" /* for class OFBool */
|
||
|
#include "dcmtk/ofstd/ofstring.h" /* for class OFString */
|
||
|
#include "dcmtk/ofstd/ofstd.h" /* for class OFStandard */
|
||
|
|
||
|
#define INCLUDE_UNISTD
|
||
|
#define INCLUDE_CSTDIO
|
||
|
#define INCLUDE_CSTRING
|
||
|
#define INCLUDE_CSTDARG
|
||
|
#define INCLUDE_CERRNO
|
||
|
//#define INCLUDE_CWCHAR /* not yet implemented in "ofstdinc.h" */
|
||
|
#include "dcmtk/ofstd/ofstdinc.h"
|
||
|
|
||
|
BEGIN_EXTERN_C
|
||
|
#ifdef HAVE_SYS_STAT_H
|
||
|
#include <sys/stat.h> /* needed for struct _stati64 on Win32 */
|
||
|
#endif
|
||
|
END_EXTERN_C
|
||
|
|
||
|
/* HP-UX has clearerr both as macro and as a function definition. We have to
|
||
|
* undef the macro so that we can define a function called "clearerr".
|
||
|
*/
|
||
|
#if defined(__hpux) && defined(clearerr)
|
||
|
#undef clearerr
|
||
|
#endif
|
||
|
|
||
|
/* When using the ISO C++ include files such as <cstdio>, <cstdarg> etc.,
|
||
|
* all ANSI C functions like fopen() are declared in namespace std,
|
||
|
* (e.g. we have to use std::fopen()), but non-ANSI Posix functions remain
|
||
|
* in global namespace, e.g. we have to use ::fopen64().
|
||
|
* To make things even more difficult, not all compilers really declare
|
||
|
* ANSI C functions in namespace std in accordance with the C++ standard.
|
||
|
* Yes, this is ugly.
|
||
|
*/
|
||
|
|
||
|
/* Find out whether current operating system needs explicit function calls
|
||
|
* to handle large file support
|
||
|
*/
|
||
|
#ifdef _LARGEFILE64_SOURCE
|
||
|
// Mac OS X defines _LARGEFILE64_SOURCE but anyhow expects implicit 64 bit calls.
|
||
|
// The same is true for current Cygwin versions (tested with version 1.7.7-1).
|
||
|
#if !(defined(__MACH__) && defined(__APPLE__)) && !defined(__CYGWIN__)
|
||
|
#define EXPLICIT_LFS_64
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
// Explicit LFS (LFS64) and Windows need 64 bit types
|
||
|
#if defined(EXPLICIT_LFS_64) || defined(_WIN32)
|
||
|
|
||
|
// Use POSIX 64 bit file position type when available
|
||
|
#ifdef HAVE_FPOS64_T
|
||
|
typedef fpos64_t offile_fpos_t;
|
||
|
#else // Otherwise this should be sufficient
|
||
|
typedef fpos_t offile_fpos_t;
|
||
|
#endif
|
||
|
|
||
|
// Use POSIX 64 bit file offset type when available
|
||
|
#ifdef HAVE_OFF64_T
|
||
|
typedef off64_t offile_off_t;
|
||
|
#elif !defined(OF_NO_SINT64) // Otherwise use a 64 bit integer
|
||
|
typedef Sint64 offile_off_t;
|
||
|
#else // Cry when 64 LFS is required but no 64 bit integer exists
|
||
|
#error \
|
||
|
Could not find a suitable offset-type for LFS64 support.
|
||
|
#endif
|
||
|
|
||
|
#else // Implicit LFS or no LFS
|
||
|
|
||
|
#ifdef HAVE_FSEEKO
|
||
|
typedef off_t offile_off_t;
|
||
|
#else
|
||
|
typedef long offile_off_t;
|
||
|
#endif
|
||
|
typedef fpos_t offile_fpos_t;
|
||
|
|
||
|
#endif // basic type definitions
|
||
|
|
||
|
// the type we use to store the last error.
|
||
|
typedef int offile_errno_t;
|
||
|
|
||
|
|
||
|
/** class for managing filenames consisting either of conventional (8-bit) or
|
||
|
* wide (e.g.\ 16-bit) characters. The wide character support is currently
|
||
|
* Windows-specific because most other operating systems use UTF-8, which is
|
||
|
* compatible with conventional 8-bit character strings.
|
||
|
*/
|
||
|
class DCMTK_OFSTD_EXPORT OFFilename
|
||
|
{
|
||
|
public:
|
||
|
/** default constructor
|
||
|
*/
|
||
|
OFFilename();
|
||
|
|
||
|
/** constructor expecting a conventional character string
|
||
|
* @param filename filename to be stored (8-bit characters, e.g. UTF-8)
|
||
|
* @param convert convert given filename to wide character encoding as an
|
||
|
* alternative representation
|
||
|
*/
|
||
|
OFFilename(const char *filename,
|
||
|
const OFBool convert = OFFalse);
|
||
|
|
||
|
/** constructor expecting a character string as an OFString instance
|
||
|
* @param filename filename to be stored (8-bit characters, e.g. UTF-8)
|
||
|
* @param convert convert given filename to wide character encoding as an
|
||
|
* alternative representation. Only works on Windows systems.
|
||
|
*/
|
||
|
OFFilename(const OFString &filename,
|
||
|
const OFBool convert = OFFalse);
|
||
|
|
||
|
#if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
|
||
|
/** constructor expecting a wide character string
|
||
|
* @param filename filename to be stored (e.g. 16-bit characters)
|
||
|
* @param convert convert given filename to UTF-8 encoding as an
|
||
|
* alternative representation. Only works on Windows systems.
|
||
|
*/
|
||
|
OFFilename(const wchar_t *filename,
|
||
|
const OFBool convert = OFTrue);
|
||
|
#endif
|
||
|
|
||
|
/** copy constructor
|
||
|
* @param arg filename object to be copied
|
||
|
*/
|
||
|
OFFilename(const OFFilename &arg);
|
||
|
|
||
|
/** destructor. Frees memory.
|
||
|
*/
|
||
|
~OFFilename();
|
||
|
|
||
|
/** assignment operator
|
||
|
* @param arg filename object to be copied
|
||
|
* @return reference to this filename object
|
||
|
*/
|
||
|
OFFilename &operator=(const OFFilename &arg);
|
||
|
|
||
|
/** clear currently stored filename
|
||
|
*/
|
||
|
void clear();
|
||
|
|
||
|
/** fast, non-throwing swap function. The time complexity of this function
|
||
|
* is constant.
|
||
|
* @param arg filename object to swap with
|
||
|
*/
|
||
|
void swap(OFFilename &arg);
|
||
|
|
||
|
/** checks whether this object stores an empty filename
|
||
|
* @return OFTrue if the filename is empty, OFFalse otherwise
|
||
|
*/
|
||
|
OFBool isEmpty() const;
|
||
|
|
||
|
/** checks whether this object stores a wide character filename
|
||
|
* @return OFTrue if the filename uses wide characters, OFFalse otherwise
|
||
|
*/
|
||
|
inline OFBool usesWideChars() const
|
||
|
{
|
||
|
#if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
|
||
|
return (wfilename_ != NULL);
|
||
|
#else
|
||
|
return OFFalse;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** get stored filename consisting of conventional characters
|
||
|
* @return filename (might be NULL if none is stored)
|
||
|
*/
|
||
|
inline const char *getCharPointer() const
|
||
|
{
|
||
|
return filename_;
|
||
|
}
|
||
|
|
||
|
#if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
|
||
|
/** get stored filename consisting of wide characters
|
||
|
* @return wide char filename (might be NULL if none is stored)
|
||
|
*/
|
||
|
inline const wchar_t *getWideCharPointer() const
|
||
|
{
|
||
|
return wfilename_;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/** replace currently stored filename by given value
|
||
|
* @param filename filename to be stored (8-bit characters, e.g. UTF-8)
|
||
|
* @param convert convert given filename to wide character encoding as an
|
||
|
* alternative representation. Only works on Windows systems.
|
||
|
*/
|
||
|
void set(const char *filename,
|
||
|
const OFBool convert = OFFalse);
|
||
|
|
||
|
/** replace currently stored filename by given value
|
||
|
* @param filename filename to be stored (8-bit characters, e.g. UTF-8)
|
||
|
* @param convert convert given filename to wide character encoding as an
|
||
|
* alternative representation). Only works on Windows systems.
|
||
|
*/
|
||
|
void set(const OFString &filename,
|
||
|
const OFBool convert = OFFalse);
|
||
|
|
||
|
#if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
|
||
|
/** replace currently stored filename by given value
|
||
|
* @param filename filename to be stored (e.g. 16-bit characters)
|
||
|
* @param convert convert given filename to UTF-8 encoding as an alternative
|
||
|
* representation. Only works on Windows systems.
|
||
|
*/
|
||
|
void set(const wchar_t *filename,
|
||
|
const OFBool convert = OFTrue);
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
/// filename consisting of conventional characters (8-bit, e.g. UTF-8)
|
||
|
char *filename_;
|
||
|
#if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
|
||
|
/// filename consisting of wide characters (e.g. 16-bit on Windows)
|
||
|
wchar_t *wfilename_;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
/** swap function for OFFilename class. The time complexity of this function
|
||
|
* is constant.
|
||
|
* @param lhs left-hand side filename
|
||
|
* @param rhs right-hand side filename
|
||
|
*/
|
||
|
inline void swap(OFFilename &lhs, OFFilename &rhs)
|
||
|
{
|
||
|
lhs.swap(rhs);
|
||
|
}
|
||
|
|
||
|
/** output filename to the given stream.
|
||
|
* Only the string of conventional characters (e.g. ASCII or UTF-8) is printed since
|
||
|
* we do not expect the output stream (console or logger) to support wide characters.
|
||
|
* @param stream output stream
|
||
|
* @param filename OFFilename object to print
|
||
|
* @return reference to the output stream
|
||
|
*/
|
||
|
DCMTK_OFSTD_EXPORT STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream, const OFFilename &filename);
|
||
|
|
||
|
|
||
|
/** this class provides a simple C++ encapsulation layer for stdio FILE pointers.
|
||
|
* All stdio functions on files are directly mapped into member functions.
|
||
|
* The handling of large files (64 bit file systems) is transparent. Instead
|
||
|
* of type off_t, fseek() and ftell() use offile_off_t which is a 64 bit type
|
||
|
* if available on the underlying platform. Similarly, getpos() and setpos() use
|
||
|
* type offile_fpos_t, which is defined appropriately.
|
||
|
* This class provides both fclose() and pclose(), but these are equivalent -
|
||
|
* the code always closes pipes with pclose() and files with fclose().
|
||
|
* Finally, an abstraction for errno is provided. Error codes should always
|
||
|
* be retrieves using methods getLastError() and getLastErrorString() which
|
||
|
* on Unix platforms are based on errno and strerror/strerror_r, but may be based
|
||
|
* on other mechanisms on platforms where errno does not exist.
|
||
|
*/
|
||
|
class OFFile
|
||
|
{
|
||
|
public:
|
||
|
/// default constructor, creates an object that is not associated with any file.
|
||
|
OFFile(): file_(NULL), popened_(OFFalse), lasterror_(0) {}
|
||
|
|
||
|
/** create object for given stdio FILE
|
||
|
* @param f stdio FILE
|
||
|
*/
|
||
|
OFFile(FILE *f): file_(f), popened_(OFFalse), lasterror_(0) {}
|
||
|
|
||
|
/// destructor. Closes file if still open.
|
||
|
~OFFile()
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
}
|
||
|
|
||
|
/** opens the file whose name is the string pointed to by path and associates
|
||
|
* a stream with it.
|
||
|
* @param filename path to file
|
||
|
* @param modes "r", "w" or "a" with possible modifiers "+", "b"
|
||
|
* @return true if stream was successfully created, false otherwise, in which
|
||
|
* case the error code is set.
|
||
|
*/
|
||
|
OFBool fopen(const char *filename, const char *modes)
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
#ifdef EXPLICIT_LFS_64
|
||
|
file_ = :: fopen64(filename, modes);
|
||
|
#else
|
||
|
file_ = STDIO_NAMESPACE fopen(filename, modes);
|
||
|
#endif
|
||
|
if (file_) popened_ = OFFalse; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
|
||
|
#if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
|
||
|
/** opens the file whose name is the wide character string pointed to by path and
|
||
|
* associates a stream with it. This function is Win32 specific and only exists on
|
||
|
* WinNT and newer.
|
||
|
* @param filename Unicode filename path to file
|
||
|
* @param modes "r", "w" or "a" with possible modifiers "+", "b", as a wide
|
||
|
* character string
|
||
|
* @return true if stream was successfully created, false otherwise, in which case
|
||
|
* the error code is set.
|
||
|
*/
|
||
|
OFBool wfopen(const wchar_t *filename, const wchar_t *modes)
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
file_ = _wfopen(filename, modes);
|
||
|
if (file_) popened_ = OFFalse; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/** opens the file whose name is a conventional or wide character string pointed to
|
||
|
* by path and associates. The wide character support is currently Windows-specific.
|
||
|
* @param filename object containing the filename path to file
|
||
|
* @param modes "r", "w" or "a" with possible modifiers "+", "b"
|
||
|
* @return true if stream was successfully created, false otherwise, in which case
|
||
|
* the error code is set.
|
||
|
*/
|
||
|
OFBool fopen(const OFFilename &filename, const char *modes)
|
||
|
{
|
||
|
OFBool result = OFFalse;
|
||
|
#if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
|
||
|
if (filename.usesWideChars())
|
||
|
{
|
||
|
// convert file mode to wide char string
|
||
|
const size_t length = strlen(modes) + 1;
|
||
|
wchar_t *wmodes = new wchar_t[length];
|
||
|
if (wmodes != NULL)
|
||
|
{
|
||
|
for (size_t i = 0; i < length; ++i)
|
||
|
{
|
||
|
// conversion of ASCII codes (7-bit) is easy
|
||
|
wmodes[i] = OFstatic_cast(wchar_t, modes[i]);
|
||
|
}
|
||
|
result = wfopen(filename.getWideCharPointer(), wmodes);
|
||
|
}
|
||
|
delete[] wmodes;
|
||
|
} else
|
||
|
#endif
|
||
|
result = fopen(filename.getCharPointer(), modes);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** associates a stream with the existing file descriptor 'fd'. The mode of
|
||
|
* the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be
|
||
|
* compatible with the mode of the file descriptor. The file position
|
||
|
* indicator of the new stream is set to that belonging to 'fd', and the
|
||
|
* error and end-of-file indicators are cleared. Modes "w" or "w+" do not
|
||
|
* cause truncation of the file. The file descriptor is not dup'ed, and
|
||
|
* will be closed when the stream created by fdopen is closed. The result
|
||
|
* of applying fdopen to a shared memory object is undefined.
|
||
|
* @param fd file descriptor
|
||
|
* @param modes "r", "w" or "a" with possible modifiers "+", "b"
|
||
|
* @return true if stream was successfully created, false otherwise, in
|
||
|
* which case the error code is set.
|
||
|
*/
|
||
|
OFBool fdopen(int fd, const char *modes)
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
file_ = :: fdopen(fd, modes);
|
||
|
if (file_) popened_ = OFFalse; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
|
||
|
/** opens a process by creating a pipe, forking, and invoking the shell.
|
||
|
* Since a pipe is by definition unidirectional, the type argument may
|
||
|
* specify only reading or writing, not both; the resulting stream is
|
||
|
* correspondingly read-only or write-only. If the object was already
|
||
|
* associated with another file or pipe, that one is closed.
|
||
|
* @param command shell command line
|
||
|
* @param modes "r" or "w"
|
||
|
* @return true if pipe was successfully created, false otherwise
|
||
|
*/
|
||
|
OFBool popen(const char *command, const char *modes)
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
#ifdef HAVE_POPEN
|
||
|
file_ = :: popen(command, modes);
|
||
|
#else
|
||
|
file_ = _popen(command, modes);
|
||
|
#endif
|
||
|
if (file_) popened_ = OFTrue; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
|
||
|
/** opens the file whose name is the string pointed to by path and associates
|
||
|
* the stream pointed maintained by this object with it. The original stream
|
||
|
* (if it exists) is closed. The mode argument is used just as in the fopen
|
||
|
* function. The primary use of the freopen function is to change the file
|
||
|
* associated with a standard text stream (stderr, stdin, or stdout).
|
||
|
* @param filename path to file
|
||
|
* @param modes "r", "w" or "a" with possible modifiers "+", "b"
|
||
|
* @return true if stream was successfully created, false otherwise, in
|
||
|
* which case the error code is set.
|
||
|
*/
|
||
|
OFBool freopen(const char *filename, const char *modes)
|
||
|
{
|
||
|
#if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
|
||
|
// MinGW has EXPLICIT_LFS_64 but no freopen64()
|
||
|
file_ = :: freopen64(filename, modes, file_);
|
||
|
#else
|
||
|
file_ = STDIO_NAMESPACE freopen(filename, modes, file_);
|
||
|
#endif
|
||
|
if (file_) popened_ = OFFalse; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
|
||
|
/** generates a unique temporary filename. The temporary file is then opened
|
||
|
* in binary read/write (w+b) mode. The file will be automatically deleted
|
||
|
* when it is closed or the program terminates normally.
|
||
|
* @return true if stream was successfully created, false otherwise, in
|
||
|
* which case the error code is set.
|
||
|
*/
|
||
|
OFBool tmpfile()
|
||
|
{
|
||
|
if (file_) fclose();
|
||
|
#if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
|
||
|
// MinGW has EXPLICIT_LFS_64 but no tmpfile64()
|
||
|
file_ = :: tmpfile64();
|
||
|
#else
|
||
|
file_ = STDIO_NAMESPACE tmpfile();
|
||
|
#endif
|
||
|
if (file_) popened_ = OFFalse; else storeLastError();
|
||
|
return (file_ != NULL);
|
||
|
}
|
||
|
|
||
|
/** dissociates the named stream from its underlying file or set of functions.
|
||
|
* If the stream was being used for output, any buffered data is written
|
||
|
* first, using fflush. Independent of the return value of this method,
|
||
|
* any further access (including another call to fclose()) to the stream
|
||
|
* maintained by this object results in undefined behaviour.
|
||
|
* @return 0 upon success, EOF otherwise, in which case the error code is set.
|
||
|
*/
|
||
|
int fclose()
|
||
|
{
|
||
|
int result = 0;
|
||
|
if (file_)
|
||
|
{
|
||
|
if (popened_)
|
||
|
{
|
||
|
#ifdef HAVE_PCLOSE
|
||
|
result = :: pclose(file_);
|
||
|
#else
|
||
|
result = _pclose(file_);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = STDIO_NAMESPACE fclose(file_);
|
||
|
}
|
||
|
// After calling fclose() once, the FILE* is gone even if fclose() failed.
|
||
|
file_ = NULL;
|
||
|
}
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** waits for the associated process (created with popen) to terminate and
|
||
|
* returns the exit status of the command as returned by wait4.
|
||
|
* In this implementation, fclose and pclose can be used synonymously.
|
||
|
* @return process ID of the child which exited, or -1 on error, in which
|
||
|
* case the error code is set
|
||
|
*/
|
||
|
int pclose() { return fclose(); }
|
||
|
|
||
|
/** writes n elements of data, each size bytes long, to the stream, obtaining
|
||
|
* them from the location given by ptr. Returns the number of items successfully written
|
||
|
* (i.e., not the number of characters). If an error occurs the return value is a short
|
||
|
* item count (or zero).
|
||
|
* @param ptr pointer to buffer
|
||
|
* @param size size of item
|
||
|
* @param n number of items
|
||
|
* @return number of items written
|
||
|
*/
|
||
|
size_t fwrite(const void *ptr, size_t size, size_t n)
|
||
|
{
|
||
|
return STDIO_NAMESPACE fwrite(ptr, size, n, file_);
|
||
|
}
|
||
|
|
||
|
/** reads n elements of data, each size bytes long, from the stream, storing
|
||
|
* them at the location given by ptr. Returns the number of items successfully
|
||
|
* read (i.e., not the number of characters). If an error occurs, or the
|
||
|
* end-of-file is reached, the return value is a short item count (or zero).
|
||
|
* fread does not distinguish between end-of-file and error, and callers must
|
||
|
* use feof and ferror to determine which occurred.
|
||
|
* @param ptr pointer to buffer
|
||
|
* @param size size of item
|
||
|
* @param n number of items
|
||
|
* @return number of items read
|
||
|
*/
|
||
|
size_t fread(void *ptr, size_t size, size_t n)
|
||
|
{
|
||
|
return STDIO_NAMESPACE fread(ptr, size, n, file_);
|
||
|
}
|
||
|
|
||
|
/** forces a write of all user-space buffered data for the given output or
|
||
|
* update stream via the stream's underlying write function. The open status
|
||
|
* of the stream is unaffected.
|
||
|
* @return 0 upon success, EOF otherwise, in which case the error code is set.
|
||
|
*/
|
||
|
int fflush()
|
||
|
{
|
||
|
int result = STDIO_NAMESPACE fflush(file_);
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** reads the next character from stream and returns it as an unsigned char
|
||
|
* cast to an int, or EOF on end of file or error.
|
||
|
* @return next character from stream or EOF
|
||
|
*/
|
||
|
int fgetc() { return STDIO_NAMESPACE fgetc(file_); }
|
||
|
|
||
|
/** The three types of buffering available are unbuffered, block buffered, and
|
||
|
* line buffered. When an output stream is unbuffered, information appears on
|
||
|
* the destination file or terminal as soon as written; when it is block
|
||
|
* buffered many characters are saved up and written as a block; when it is
|
||
|
* line buffered characters are saved up until a newline is output or input
|
||
|
* is read from any stream attached to a terminal device (typically stdin).
|
||
|
* Normally all files are block buffered. if a stream refers to a terminal
|
||
|
* (as stdout normally does) it is line buffered. The standard error stream
|
||
|
* stderr is always unbuffered by default. this function allows to set the
|
||
|
* mode of the stream to line buffered.
|
||
|
* @return 0 upon success, nonzero otherwise, in which case the error code may be set
|
||
|
*
|
||
|
*/
|
||
|
void setlinebuf()
|
||
|
{
|
||
|
#if defined(_WIN32) || defined(__hpux)
|
||
|
this->setvbuf(NULL, _IOLBF, 0);
|
||
|
#else
|
||
|
:: setlinebuf(file_);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** sets the file position indicator for the stream pointed to by stream to
|
||
|
* the beginning of the file. This is equivalent to fseek(0, SEEK_SET)
|
||
|
* except that the error indicator for the stream is also cleared.
|
||
|
*/
|
||
|
void rewind() { STDIO_NAMESPACE rewind(file_); }
|
||
|
|
||
|
/** clears the end-of-file and error indicators for the stream
|
||
|
*/
|
||
|
void clearerr() { STDIO_NAMESPACE clearerr(file_); }
|
||
|
|
||
|
/** tests the end-of-file indicator for the stream, returning non-zero if it
|
||
|
* is set. The end-of-file indicator can only be cleared by the function
|
||
|
* clearerr. This method is called eof, not feof, because feof() is a macro
|
||
|
* on some systems and, therefore, cannot be used as a method name.
|
||
|
* @return non-zero if EOF, zero otherwise
|
||
|
*/
|
||
|
int eof() const
|
||
|
{
|
||
|
#ifdef feof
|
||
|
// feof is a macro on some systems. Macros never have namespaces.
|
||
|
return feof(file_);
|
||
|
#else
|
||
|
return STDIO_NAMESPACE feof(file_);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** tests the error indicator for the stream, returning non-zero if it is set.
|
||
|
* This method is named error, not ferror, because ferror() is a macro
|
||
|
* on some systems and, therefore, cannot be used as a method name.
|
||
|
* The error indicator can only be reset by the clearerr function.
|
||
|
* @return non-zero if error flag is set, zero otherwise
|
||
|
*/
|
||
|
int error()
|
||
|
{
|
||
|
#ifdef ferror
|
||
|
// ferror is a macro on some systems. Macros never have namespaces.
|
||
|
return ferror(file_);
|
||
|
#else
|
||
|
return STDIO_NAMESPACE ferror(file_);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** returns the low-level file descriptor associated with the stream.
|
||
|
* The spelling of this member function is different from stdio fileno()
|
||
|
* because on some systems (such as MinGW) fileno() is a macro
|
||
|
* and, therefore, cannot be used as a method name.
|
||
|
* @return low-level file descriptor associated with stream
|
||
|
*/
|
||
|
#ifdef fileno
|
||
|
int fileNo() { return fileno(file_); }
|
||
|
#else
|
||
|
int fileNo() { return :: fileno(file_); }
|
||
|
#endif
|
||
|
|
||
|
/** The three types of buffering available are unbuffered, block buffered, and
|
||
|
* line buffered. When an output stream is unbuffered, information appears on
|
||
|
* the destination file or terminal as soon as written; when it is block
|
||
|
* buffered many characters are saved up and written as a block; when it is
|
||
|
* line buffered characters are saved up until a newline is output or input
|
||
|
* is read from any stream attached to a terminal device (typically stdin).
|
||
|
* Normally all files are block buffered. if a stream refers to a terminal
|
||
|
* (as stdout normally does) it is line buffered. The standard error stream
|
||
|
* stderr is always unbuffered by default. This function allows to set the
|
||
|
* mode of the stream to unbuffered (if buf is NULL) or block buffered.
|
||
|
* @param buf pointer to buffer of size BUFSIZ as declared in cstdio, or NULL
|
||
|
* @return 0 upon success, nonzero otherwise, in which case the error code may be set
|
||
|
*/
|
||
|
void setbuf(char *buf) { STDIO_NAMESPACE setbuf(file_, buf); }
|
||
|
|
||
|
/** The three types of buffering available are unbuffered, block buffered, and
|
||
|
* line buffered. When an output stream is unbuffered, information appears on
|
||
|
* the destination file or terminal as soon as written; when it is block
|
||
|
* buffered many characters are saved up and written as a block; when it is
|
||
|
* line buffered characters are saved up until a newline is output or input
|
||
|
* is read from any stream attached to a terminal device (typically stdin).
|
||
|
* Normally all files are block buffered. if a stream refers to a terminal
|
||
|
* (as stdout normally does) it is line buffered. The standard error stream
|
||
|
* stderr is always unbuffered by default. This function allows to set the
|
||
|
* stream mode.
|
||
|
* @param buf pointer to buffer, may be NULL
|
||
|
* @param modes _IONBF (unbuffered) _IOLBF (line buffered) or _IOFBF (fully buffered)
|
||
|
* @param n size of buffer, in bytes
|
||
|
* @return 0 upon success, nonzero otherwise, in which case the error code may be set
|
||
|
*/
|
||
|
int setvbuf(char * buf, int modes, size_t n)
|
||
|
{
|
||
|
int result = STDIO_NAMESPACE setvbuf(file_, buf, modes, n);
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** The three types of buffering available are unbuffered, block buffered, and
|
||
|
* line buffered. When an output stream is unbuffered, information appears on
|
||
|
* the destination file or terminal as soon as written; when it is block
|
||
|
* buffered many characters are saved up and written as a block; when it is
|
||
|
* line buffered characters are saved up until a newline is output or input
|
||
|
* is read from any stream attached to a terminal device (typically stdin).
|
||
|
* Normally all files are block buffered. if a stream refers to a terminal
|
||
|
* (as stdout normally does) it is line buffered. The standard error stream
|
||
|
* stderr is always unbuffered by default. This function allows to set the
|
||
|
* mode of the stream to unbuffered (if buf is NULL) or block buffered.
|
||
|
* @param buf pointer to buffer
|
||
|
* @param size size of buffer, in bytes
|
||
|
* @return 0 upon success, nonzero otherwise, in which case the error code may be set
|
||
|
*/
|
||
|
void setbuffer(char *buf, size_t size)
|
||
|
{
|
||
|
#if defined(_WIN32) || defined(__hpux)
|
||
|
this->setvbuf(NULL, buf ? _IOFBF : _IONBF, size);
|
||
|
#else
|
||
|
:: setbuffer(file_, buf, size);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/** writes the character c, cast to an unsigned char, to stream.
|
||
|
* @param c character
|
||
|
* @return the character written as an unsigned char cast to an int or EOF on error
|
||
|
*/
|
||
|
int fputc(int c) { return STDIO_NAMESPACE fputc(c, file_); }
|
||
|
|
||
|
/** reads in at most one less than n characters from stream and stores them
|
||
|
* into the buffer pointed to by s. Reading stops after an EOF or a newline.
|
||
|
* If a newline is read, it is stored into the buffer. A '@\0' is stored after
|
||
|
* the last character in the buffer.
|
||
|
* @param s pointer to buffer of size n
|
||
|
* @param n buffer size
|
||
|
* @return pointer to string
|
||
|
*/
|
||
|
char *fgets(char *s, int n) { return STDIO_NAMESPACE fgets(s, n, file_); }
|
||
|
|
||
|
/** writes the string s to stream, without its trailing '@\0'.
|
||
|
* @param s string to be written
|
||
|
* @return a non-negative number on success, or EOF on error.
|
||
|
*/
|
||
|
int fputs(const char *s) { return STDIO_NAMESPACE fputs(s, file_); }
|
||
|
|
||
|
/** pushes c back to stream, cast to unsigned char, where it is available for
|
||
|
* subsequent read operations. Pushed - back characters will be returned in
|
||
|
* reverse order; only one pushback is guaranteed.
|
||
|
* @param c character to push back
|
||
|
* @return c on success, or EOF on error.
|
||
|
*/
|
||
|
int ungetc(int c) { return STDIO_NAMESPACE ungetc(c, file_); }
|
||
|
|
||
|
/** sets the file position indicator for the stream pointed to by stream. The
|
||
|
* new position, measured in bytes, is obtained by adding offset bytes to the
|
||
|
* position specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or
|
||
|
* SEEK_END, the offset is relative to the start of the file, the current
|
||
|
* position indicator, or end-of-file, respectively. A successful call to the
|
||
|
* fseek function clears the end-of- file indicator for the stream and undoes
|
||
|
* any effects of the ungetc function on the same stream.
|
||
|
* @param off offset to seek to
|
||
|
* @param whence SEEK_SET, SEEK_CUR, or SEEK_END
|
||
|
* @return 0 upon success, -1 otherwise in which case the error code is set.
|
||
|
*/
|
||
|
int fseek(offile_off_t off, int whence)
|
||
|
{
|
||
|
int result;
|
||
|
#ifdef _WIN32
|
||
|
// Windows does not have a 64-bit fseek.
|
||
|
// We emulate fseek through fsetpos, which does exist on Windows.
|
||
|
// fpos_t is (hopefully always) defined as __int64 on this platform
|
||
|
offile_fpos_t off2 = off;
|
||
|
fpos_t pos;
|
||
|
struct _stati64 buf;
|
||
|
switch (whence)
|
||
|
{
|
||
|
case SEEK_END:
|
||
|
// flush write buffer, if any, so that the file size is correct
|
||
|
STDIO_NAMESPACE fflush(file_);
|
||
|
#if 0
|
||
|
// Python implementation based on _lseeki64(). May be unsafe because
|
||
|
// there is no guarantee that fflush also empties read buffers.
|
||
|
STDIO_NAMESPACE fflush(file_);
|
||
|
#ifdef fileno
|
||
|
if (_lseeki64( fileno(file_), 0, 2) == -1)
|
||
|
#else
|
||
|
if (_lseeki64(:: fileno(file_), 0, 2) == -1)
|
||
|
#endif
|
||
|
{
|
||
|
storeLastError();
|
||
|
return -1;
|
||
|
}
|
||
|
// fall through
|
||
|
#else
|
||
|
// determine file size (using underlying file descriptor). This should be safe.
|
||
|
#ifdef fileno
|
||
|
if (_fstati64( fileno(file_), &buf) == -1)
|
||
|
#else
|
||
|
if (_fstati64(:: fileno(file_), &buf) == -1)
|
||
|
#endif
|
||
|
{
|
||
|
storeLastError();
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// fsetpos position is offset + file size.
|
||
|
off2 += buf.st_size;
|
||
|
break;
|
||
|
#endif
|
||
|
case SEEK_CUR:
|
||
|
if (STDIO_NAMESPACE fgetpos(file_, &pos) != 0)
|
||
|
{
|
||
|
storeLastError();
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
off2 += pos;
|
||
|
break;
|
||
|
case SEEK_SET:
|
||
|
/* do nothing */
|
||
|
break;
|
||
|
}
|
||
|
result = this->fsetpos(&off2);
|
||
|
#elif defined(__BEOS__)
|
||
|
result = :: _fseek(fp, offset, whence);
|
||
|
#else
|
||
|
#ifdef HAVE_FSEEKO
|
||
|
#ifdef EXPLICIT_LFS_64
|
||
|
result = :: fseeko64(file_, off, whence);
|
||
|
#else
|
||
|
result = :: fseeko(file_, off, whence);
|
||
|
#endif
|
||
|
#else
|
||
|
result = STDIO_NAMESPACE fseek(file_, off, whence);
|
||
|
#endif
|
||
|
#endif
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** obtains the current value of the file position indicator for the stream pointed to by the stream.
|
||
|
* @return current file position
|
||
|
*/
|
||
|
offile_off_t ftell()
|
||
|
{
|
||
|
offile_off_t result;
|
||
|
#ifdef _WIN32
|
||
|
// Windows does not have a 64-bit ftell, and _telli64 cannot be used
|
||
|
// because it operates on file descriptors and ignores FILE buffers.
|
||
|
// We emulate ftell through fgetpos, which does exist on Windows.
|
||
|
// fpos_t is (hopefully always) defined as __int64 on this platform.
|
||
|
offile_fpos_t pos;
|
||
|
if (this->fgetpos(&pos) != 0)
|
||
|
{
|
||
|
storeLastError();
|
||
|
return -1;
|
||
|
}
|
||
|
return pos;
|
||
|
#else
|
||
|
#ifdef HAVE_FSEEKO
|
||
|
#ifdef EXPLICIT_LFS_64
|
||
|
result = :: ftello64(file_);
|
||
|
#else
|
||
|
result = :: ftello(file_);
|
||
|
#endif
|
||
|
#else
|
||
|
result = STDIO_NAMESPACE ftell(file_);
|
||
|
#endif
|
||
|
#endif
|
||
|
if (result < 0) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** alternate interface equivalent to ftell, storing the current value of the
|
||
|
* file offset into the object referenced by pos. On some non-UNIX systems an
|
||
|
* fpos_t object may be a complex object and these routines may be the only
|
||
|
* way to portably reposition a text stream.
|
||
|
* @param pos pointer to offile_fpos_t structure
|
||
|
* @return 0 upon success, -1 otherwise in which case the error code is set.
|
||
|
*/
|
||
|
int fgetpos(offile_fpos_t *pos)
|
||
|
{
|
||
|
int result;
|
||
|
#if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
|
||
|
// MinGW has EXPLICIT_LFS_64 but no fgetpos64()
|
||
|
result = :: fgetpos64(file_, pos);
|
||
|
#else
|
||
|
result = STDIO_NAMESPACE fgetpos(file_, pos);
|
||
|
#endif
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** alternate interface equivalent to fseek (with whence set to SEEK_SET),
|
||
|
* setting the current value of the file offset from the object referenced by
|
||
|
* pos. On some non-UNIX systems an fpos_t object may be a complex object and
|
||
|
* these routines may be the only way to portably reposition a text stream.
|
||
|
* @param pos pointer to offile_fpos_t structure
|
||
|
* @return 0 upon success, -1 otherwise in which case the error code is set.
|
||
|
*/
|
||
|
int fsetpos(offile_fpos_t *pos)
|
||
|
{
|
||
|
int result;
|
||
|
#if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
|
||
|
// MinGW has EXPLICIT_LFS_64 but no fsetpos64()
|
||
|
result = :: fsetpos64(file_, pos);
|
||
|
#else
|
||
|
result = STDIO_NAMESPACE fsetpos(file_, pos);
|
||
|
#endif
|
||
|
if (result) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** print formatted string into stream, see printf(3)
|
||
|
* @param format format string
|
||
|
* @param ... further parameters according to format string
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int fprintf(const char *format, ...)
|
||
|
{
|
||
|
int result = 0;
|
||
|
va_list ap;
|
||
|
va_start(ap, format);
|
||
|
result = STDIO_NAMESPACE vfprintf(file_, format, ap);
|
||
|
va_end(ap);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** print formatted string into stream, see printf(3)
|
||
|
* @param format format string
|
||
|
* @param arg list of further parameters according to format string
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int vfprintf(const char *format, va_list arg)
|
||
|
{
|
||
|
return STDIO_NAMESPACE vfprintf(file_, format, arg);
|
||
|
}
|
||
|
|
||
|
// we cannot emulate fscanf because we would need vfscanf for this
|
||
|
// purpose, which does not exist, e.g. on Win32.
|
||
|
|
||
|
/** return FILE pointer managed by this object. This allows the user
|
||
|
* to call some stdio functions that are not encapsulated in this class
|
||
|
* (but possibly should be).
|
||
|
* @return pointer to FILE structure managed by this object
|
||
|
*/
|
||
|
FILE *file() { return file_; }
|
||
|
|
||
|
/** return true if this object is currently associated with a stream, false otherwise
|
||
|
* @return true if this object is currently associated with a stream, false otherwise
|
||
|
*/
|
||
|
OFBool open() const { return file_ != NULL; }
|
||
|
|
||
|
/** return last error code for this stream
|
||
|
* @return last error code for this stream
|
||
|
*/
|
||
|
offile_errno_t getLastError() const { return lasterror_; }
|
||
|
|
||
|
/** return string describing last error code for this stream
|
||
|
* @param s string describing last error code for this stream returned in this parameter
|
||
|
*/
|
||
|
void getLastErrorString(OFString& s) const
|
||
|
{
|
||
|
char buf[1000];
|
||
|
s = OFStandard::strerror(lasterror_, buf, 1000);
|
||
|
}
|
||
|
|
||
|
// wide character functions (disabled by default, since currently not used within DCMTK)
|
||
|
#ifdef WIDE_CHAR_FILE_IO_FUNCTIONS
|
||
|
|
||
|
/** When mode is zero, the fwide function determines the current orientation
|
||
|
* of stream. It returns a value > 0 if stream is wide-character oriented,
|
||
|
* i.e. if wide character I/O is permitted but char I/O is disallowed. It
|
||
|
* returns a value < 0 if stream is byte oriented, i.e. if char I/O is
|
||
|
* permitted but wide character I/O is disallowed. It returns zero if stream
|
||
|
* has no orientation yet; in this case the next I/O operation might change
|
||
|
* the orientation (to byte oriented if it is a char I/O operation, or to
|
||
|
* wide-character oriented if it is a wide character I/O operation).
|
||
|
* Once a stream has an orientation, it cannot be changed and persists until
|
||
|
* the stream is closed.
|
||
|
* When mode is non-zero, the fwide function first attempts to set stream's
|
||
|
* orientation (to wide-character oriented if mode > 0, or to byte oriented
|
||
|
* if mode < 0). It then returns a value denoting the current orientation, as
|
||
|
* above.
|
||
|
* @param mode mode of operation for fwide
|
||
|
* @return orientation of stream
|
||
|
*/
|
||
|
int fwide(int mode)
|
||
|
{
|
||
|
return STDIO_NAMESPACE fwide(file_, mode);
|
||
|
}
|
||
|
|
||
|
/** reads a wide character from stream and returns it. If the end of stream is
|
||
|
* reached, or if ferror(stream) becomes true, it returns WEOF. If a wide
|
||
|
* character conversion error occurs, it sets the error code to EILSEQ and returns
|
||
|
* WEOF.
|
||
|
* @return next character from stream or WEOF
|
||
|
*/
|
||
|
wint_t fgetwc()
|
||
|
{
|
||
|
wint_t result = STDIO_NAMESPACE fgetwc(file_);
|
||
|
if (result == WEOF) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** writes the wide character wc to stream. If ferror(stream) becomes true, it returns WEOF.
|
||
|
* If a wide character conversion error occurs, it sets the error code to EILSEQ and returns WEOF.
|
||
|
* Otherwise it returns wc.
|
||
|
* @param wc wide character to write to stream
|
||
|
* @return character written or WEOF
|
||
|
*/
|
||
|
wint_t fputwc(wchar_t wc)
|
||
|
{
|
||
|
wint_t result = STDIO_NAMESPACE fputwc(wc, file_);
|
||
|
if (result == WEOF) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** pushes back a wide character onto stream and returns it. If wc is WEOF, it
|
||
|
* returns WEOF. If wc is an invalid wide character, it sets errno to EILSEQ
|
||
|
* and returns WEOF. If wc is a valid wide character, it is pushed back onto
|
||
|
* the stream and thus becomes available for future wide character read
|
||
|
* operations. The file-position indicator is decremented by one or more.
|
||
|
* The end-of-file indicator is cleared. The backing storage of the file is
|
||
|
* not affected. Note: wc need not be the last wide character read from the
|
||
|
* stream; it can be any other valid wide character. If the implementation
|
||
|
* supports multiple push-back operations in a row, the pushed-back wide
|
||
|
* characters will be read in reverse order; however, only one level of
|
||
|
* push-back is guaranteed.
|
||
|
* @param wc wide character to put back to stream
|
||
|
* @return character put back or WEOF
|
||
|
*/
|
||
|
wint_t ungetwc(wint_t wc)
|
||
|
{
|
||
|
wint_t result = STDIO_NAMESPACE ungetwc(wc, file_);
|
||
|
if (result == WEOF) storeLastError();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** print formatted wide string into stream, see wprintf(3)
|
||
|
* @param format format string
|
||
|
* @param ... further parameters according to format string
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int fwprintf(const wchar_t *format, ...)
|
||
|
{
|
||
|
int result = 0;
|
||
|
va_list ap;
|
||
|
va_start(ap, format);
|
||
|
result = STDIO_NAMESPACE vfwprintf(file_, format, ap);
|
||
|
va_end(ap);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** print formatted wide string into stream, see printf(3)
|
||
|
* @param format format string
|
||
|
* @param arg list of further parameters according to format string
|
||
|
* @return number of characters printed
|
||
|
*/
|
||
|
int vfwprintf(const wchar_t *format, va_list arg)
|
||
|
{
|
||
|
return STDIO_NAMESPACE vfwprintf(file_, format, arg);
|
||
|
}
|
||
|
|
||
|
// we cannot emulate fwscanf because we would need vfwscanf for this
|
||
|
// purpose, which does not exist, e.g. on Win32.
|
||
|
|
||
|
#endif /* WIDE_CHAR_FILE_IO_FUNCTIONS */
|
||
|
|
||
|
private:
|
||
|
|
||
|
// private undefined copy constructor
|
||
|
OFFile(const OFFile &arg);
|
||
|
|
||
|
// private undefined assignment operator
|
||
|
OFFile &operator=(const OFFile &arg);
|
||
|
|
||
|
/// the file maintained by this object
|
||
|
FILE *file_;
|
||
|
|
||
|
/// a flag indicating whether or not this object was created with popen().
|
||
|
OFBool popened_;
|
||
|
|
||
|
/// the last error code for operations of this stream
|
||
|
offile_errno_t lasterror_;
|
||
|
|
||
|
/// store last error code. For now we simply store the content of errno.
|
||
|
inline void storeLastError()
|
||
|
{
|
||
|
lasterror_ = errno;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
#endif
|