1 /*
2 *
3 * Copyright (C) 2006-2020, OFFIS e.V.
4 * All rights reserved. See COPYRIGHT file for details.
5 *
6 * This software and supporting documentation were developed by
7 *
8 * OFFIS e.V.
9 * R&D Division Health
10 * Escherweg 2
11 * D-26121 Oldenburg, Germany
12 *
13 *
14 * Module: ofstd
15 *
16 * Author: Marco Eichelberg, Joerg Riesmeier
17 *
18 * Purpose: C++ wrapper class for stdio FILE functions and
19 * wide character filenames
20 *
21 */
22
23 #ifndef OFFILE_H
24 #define OFFILE_H
25
26 #include "dcmtk/config/osconfig.h"
27
28 #include "dcmtk/ofstd/oftypes.h" /* for class OFBool */
29 #include "dcmtk/ofstd/ofstring.h" /* for class OFString */
30 #include "dcmtk/ofstd/ofstd.h" /* for class OFStandard */
31
32 #define INCLUDE_UNISTD
33 #define INCLUDE_CSTDIO
34 #define INCLUDE_CSTRING
35 #define INCLUDE_CSTDARG
36 #define INCLUDE_CERRNO
37 //#define INCLUDE_CWCHAR /* not yet implemented in "ofstdinc.h" */
38 #include "dcmtk/ofstd/ofstdinc.h"
39
40 BEGIN_EXTERN_C
41 #ifdef HAVE_SYS_STAT_H
42 #include <sys/stat.h> /* needed for struct _stati64 on Win32 */
43 #endif
44 END_EXTERN_C
45
46 #ifdef HAVE_UNIX_H
47 #include <unix.h> /* needed for setlinebuf() on QNX */
48 #endif
49
50 /* HP-UX has clearerr both as macro and as a function definition. We have to
51 * undef the macro so that we can define a function called "clearerr".
52 */
53 #if defined(__hpux) && defined(clearerr)
54 #undef clearerr
55 #endif
56
57 /* When using the ISO C++ include files such as <cstdio>, <cstdarg> etc.,
58 * all ANSI C functions like fopen() are declared in namespace std,
59 * (e.g. we have to use std::fopen()), but non-ANSI Posix functions remain
60 * in global namespace, e.g. we have to use ::fopen64().
61 * To make things even more difficult, not all compilers really declare
62 * ANSI C functions in namespace std in accordance with the C++ standard.
63 * Yes, this is ugly.
64 */
65
66 /* Find out whether to use explicit LFS function calls to handle
67 * large file support
68 */
69 #if defined(DCMTK_ENABLE_LFS) && DCMTK_ENABLE_LFS == DCMTK_LFS64
70 #define EXPLICIT_LFS_64
71
72 // Use POSIX 64 bit file position type when available
73 #ifdef HAVE_FPOS64_T
74 typedef fpos64_t offile_fpos_t;
75 #else // Otherwise this should be sufficient
76 typedef fpos_t offile_fpos_t;
77 #endif
78
79 // Use POSIX 64 bit file offset type when available
80 #ifdef HAVE_OFF64_T
81 typedef off64_t offile_off_t;
82 #elif !defined(OF_NO_SINT64) // Otherwise use a 64 bit integer
83 typedef Sint64 offile_off_t;
84 #else // Cry when 64 LFS is required but no 64 bit integer exists
85 #error \
86 Could not find a suitable offset-type for LFS64 support.
87 #endif
88
89 #else // Implicit LFS or no LFS
90
91 #if defined(DCMTK_ENABLE_LFS) && DCMTK_ENABLE_LFS == DCMTK_LFS
92 #if defined(SIZEOF_FPOS_T) && (!defined(SIZEOF_OFF_T) || SIZEOF_FPOS_T > SIZEOF_OFF_T)
93 // strange Windows LFS where sizeof(fpos_t) == 8 but sizeof(off_t) == 4
94 #ifndef OF_NO_SINT64 // Use a 64 bit integer
95 typedef Sint64 offile_off_t;
96 #else // Cry when LFS is required but no 64 bit integer exists
97 #error \
98 Could not find a suitable offset-type for LFS support.
99 #endif
100 #else
101 typedef off_t offile_off_t;
102 #endif
103 #elif defined(HAVE_FSEEKO)
104 typedef off_t offile_off_t;
105 #else
106 typedef long offile_off_t;
107 #endif
108 typedef fpos_t offile_fpos_t;
109
110 #endif // basic type definitions
111
112 // the type we use to store the last error.
113 typedef int offile_errno_t;
114
115
116 // forward declarations
117 class OFpath;
118
119 /** class for managing filenames consisting either of conventional (8-bit) or
120 * wide (e.g.\ 16-bit) characters. The wide character support is currently
121 * Windows-specific because most other operating systems use UTF-8, which is
122 * compatible with conventional 8-bit character strings.
123 */
124 class DCMTK_OFSTD_EXPORT OFFilename
125 {
126 public:
127 /** default constructor
128 */
129 OFFilename();
130
131 /** constructor expecting a conventional character string
132 * @param filename filename to be stored (8-bit characters, e.g. UTF-8)
133 * @param convert convert given filename to wide character encoding as an
134 * alternative representation. Only works on Windows systems.
135 */
136 OFFilename(const char *filename,
137 const OFBool convert = OFFalse);
138
139 /** constructor expecting a character string as an OFString instance
140 * @param filename filename to be stored (8-bit characters, e.g. UTF-8)
141 * @param convert convert given filename to wide character encoding as an
142 * alternative representation. Only works on Windows systems.
143 */
144 OFFilename(const OFString &filename,
145 const OFBool convert = OFFalse);
146
147 /** constructor expecting an OFpath instance
148 * @param path OFpath instance storing a filename in native format
149 * (currently, identical to an 8-bit character string)
150 * @param convert convert given filename to wide character encoding as an
151 * alternative representation. Only works on Windows systems.
152 */
153 OFFilename(const OFpath &path,
154 const OFBool convert = OFFalse);
155
156 #if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
157 /** constructor expecting a wide character string
158 * @remark This constructor is only available if DCMTK is compiled on Windows
159 * Operating Systems with wide chars enabled (defining _WIN32 as well as
160 * WIDE_CHAR_FILE_IO_FUNCTIONS or WIDE_CHAR_MAIN_FUNCTION).
161 * @param filename filename to be stored (e.g. 16-bit characters)
162 * @param convert convert given filename to UTF-8 encoding as an
163 * alternative representation. Only works on Windows systems.
164 */
165 OFFilename(const wchar_t *filename,
166 const OFBool convert = OFTrue);
167 #endif
168
169 /** copy constructor
170 * @param arg filename object to be copied
171 */
172 OFFilename(const OFFilename &arg);
173
174 /** destructor. Frees memory.
175 */
176 ~OFFilename();
177
178 /** assignment operator
179 * @param arg filename object to be copied
180 * @return reference to this filename object
181 */
182 OFFilename &operator=(const OFFilename &arg);
183
184 /** clear currently stored filename
185 */
186 void clear();
187
188 /** fast, non-throwing swap function. The time complexity of this function
189 * is constant.
190 * @param arg filename object to swap with
191 */
192 void swap(OFFilename &arg);
193
194 /** checks whether this object stores an empty filename
195 * @return OFTrue if the filename is empty, OFFalse otherwise
196 */
197 OFBool isEmpty() const;
198
199 /** checks whether this object stores a wide character filename
200 * @return OFTrue if the filename uses wide characters, OFFalse otherwise
201 */
usesWideChars()202 inline OFBool usesWideChars() const
203 {
204 #if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
205 return (wfilename_ != NULL);
206 #else
207 return OFFalse;
208 #endif
209 }
210
211 /** get stored filename consisting of conventional characters
212 * @return filename (might be NULL if none is stored)
213 */
getCharPointer()214 inline const char *getCharPointer() const
215 {
216 return filename_;
217 }
218
219 #if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
220 /** get stored filename consisting of wide characters
221 * @remark This method is only available if DCMTK is compiled on Windows
222 * Operating Systems with wide chars enabled (defining _WIN32 as well as
223 * WIDE_CHAR_FILE_IO_FUNCTIONS or WIDE_CHAR_MAIN_FUNCTION).
224 * @return wide char filename (might be NULL if none is stored)
225 */
getWideCharPointer()226 inline const wchar_t *getWideCharPointer() const
227 {
228 return wfilename_;
229 }
230 #endif
231
232 /** replace currently stored filename by given value
233 * @param filename filename to be stored (8-bit characters, e.g. UTF-8)
234 * @param convert convert given filename to wide character encoding as an
235 * alternative representation. Only works on Windows systems.
236 */
237 void set(const char *filename,
238 const OFBool convert = OFFalse);
239
240 /** replace currently stored filename by given value
241 * @param filename filename to be stored (8-bit characters, e.g. UTF-8)
242 * @param convert convert given filename to wide character encoding as an
243 * alternative representation). Only works on Windows systems.
244 */
245 void set(const OFString &filename,
246 const OFBool convert = OFFalse);
247
248 /** replace currently stored filename by given value
249 * @param OFpath OFpath instance storing a filename in native format
250 * (currently, identical to an 8-bit character string)
251 * @param convert convert given filename to wide character encoding as an
252 * alternative representation). Only works on Windows systems.
253 */
254 void set(const OFpath &path,
255 const OFBool convert = OFFalse);
256
257 #if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
258 /** replace currently stored filename by given value
259 * @remark This method is only available if DCMTK is compiled on Windows
260 * Operating Systems with wide chars enabled (defining _WIN32 as well as
261 * WIDE_CHAR_FILE_IO_FUNCTIONS or WIDE_CHAR_MAIN_FUNCTION).
262 * @param filename filename to be stored (e.g. 16-bit characters)
263 * @param convert convert given filename to UTF-8 encoding as an alternative
264 * representation. Only works on Windows systems.
265 */
266 void set(const wchar_t *filename,
267 const OFBool convert = OFTrue);
268 #endif
269
270 private:
271 /// filename consisting of conventional characters (8-bit, e.g.\ UTF-8)
272 char *filename_;
273 #if (defined(WIDE_CHAR_FILE_IO_FUNCTIONS) || defined(WIDE_CHAR_MAIN_FUNCTION)) && defined(_WIN32)
274 /// filename consisting of wide characters (e.g. 16-bit on Windows)
275 /// @remark This member is only available if DCMTK is compiled on Windows
276 /// Operating Systems with wide chars enabled (defining _WIN32 as well as
277 /// WIDE_CHAR_FILE_IO_FUNCTIONS or WIDE_CHAR_MAIN_FUNCTION).
278 wchar_t *wfilename_;
279 #endif
280 };
281
282 /** swap function for OFFilename class. The time complexity of this function
283 * is constant.
284 * @param lhs left-hand side filename
285 * @param rhs right-hand side filename
286 */
swap(OFFilename & lhs,OFFilename & rhs)287 inline void swap(OFFilename &lhs, OFFilename &rhs)
288 {
289 lhs.swap(rhs);
290 }
291
292 /** output filename to the given stream.
293 * Only the string of conventional characters (e.g. ASCII or UTF-8) is printed since
294 * we do not expect the output stream (console or logger) to support wide characters.
295 * @param stream output stream
296 * @param filename OFFilename object to print
297 * @return reference to the output stream
298 */
299 DCMTK_OFSTD_EXPORT STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream, const OFFilename &filename);
300
301
302 /** this class provides a simple C++ encapsulation layer for stdio FILE pointers.
303 * All stdio functions on files are directly mapped into member functions.
304 * The handling of large files (64 bit file systems) is transparent. Instead
305 * of type off_t, fseek() and ftell() use offile_off_t which is a 64 bit type
306 * if available on the underlying platform. Similarly, getpos() and setpos() use
307 * type offile_fpos_t, which is defined appropriately.
308 * This class provides both fclose() and pclose(), but these are equivalent -
309 * the code always closes pipes with pclose() and files with fclose().
310 * Finally, an abstraction for errno is provided. Error codes should always
311 * be retrieves using methods getLastError() and getLastErrorString() which
312 * on Unix platforms are based on errno and strerror/strerror_r, but may be based
313 * on other mechanisms on platforms where errno does not exist.
314 */
315 class OFFile
316 {
317 public:
318 /// default constructor, creates an object that is not associated with any file.
OFFile()319 OFFile(): file_(NULL), popened_(OFFalse), lasterror_(0) {}
320
321 /** create object for given stdio FILE
322 * @param f stdio FILE
323 */
OFFile(FILE * f)324 OFFile(FILE *f): file_(f), popened_(OFFalse), lasterror_(0) {}
325
326 /// destructor. Closes file if still open.
~OFFile()327 ~OFFile()
328 {
329 if (file_) fclose();
330 }
331
332 /** opens the file whose name is the string pointed to by path and associates
333 * a stream with it.
334 * @param filename path to file
335 * @param modes "r", "w" or "a" with possible modifiers "+", "b"
336 * @return true if stream was successfully created, false otherwise, in which
337 * case the error code is set.
338 */
fopen(const char * filename,const char * modes)339 OFBool fopen(const char *filename, const char *modes)
340 {
341 if (file_) fclose();
342 #ifdef EXPLICIT_LFS_64
343 file_ = :: fopen64(filename, modes);
344 #else
345 file_ = STDIO_NAMESPACE fopen(filename, modes);
346 #endif
347 if (file_) popened_ = OFFalse; else storeLastError();
348 return (file_ != NULL);
349 }
350
351 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
352 /** opens the file whose name is the wide character string pointed to by path and
353 * associates a stream with it.
354 * @remark This member is only available if DCMTK is compiled on Windows
355 * Operating Systems with wide chars enabled (defining _WIN32 as well as
356 * WIDE_CHAR_FILE_IO_FUNCTIONS).
357 * @param filename Unicode filename path to file
358 * @param modes "r", "w" or "a" with possible modifiers "+", "b", as a wide
359 * character string
360 * @return true if stream was successfully created, false otherwise, in which case
361 * the error code is set.
362 */
wfopen(const wchar_t * filename,const wchar_t * modes)363 OFBool wfopen(const wchar_t *filename, const wchar_t *modes)
364 {
365 if (file_) fclose();
366 file_ = _wfopen(filename, modes);
367 if (file_) popened_ = OFFalse; else storeLastError();
368 return (file_ != NULL);
369 }
370 #endif
371
372 /** opens the file whose name is a conventional or wide character string pointed to
373 * by path and associates. The wide character support is currently Windows-specific.
374 * @param filename object containing the filename path to file
375 * @param modes "r", "w" or "a" with possible modifiers "+", "b"
376 * @return true if stream was successfully created, false otherwise, in which case
377 * the error code is set.
378 */
fopen(const OFFilename & filename,const char * modes)379 OFBool fopen(const OFFilename &filename, const char *modes)
380 {
381 OFBool result = OFFalse;
382 #if defined(WIDE_CHAR_FILE_IO_FUNCTIONS) && defined(_WIN32)
383 if (filename.usesWideChars())
384 {
385 // convert file mode to wide char string
386 const size_t length = strlen(modes) + 1;
387 wchar_t *wmodes = new wchar_t[length];
388 if (wmodes != NULL)
389 {
390 for (size_t i = 0; i < length; ++i)
391 {
392 // conversion of ASCII codes (7-bit) is easy
393 wmodes[i] = OFstatic_cast(wchar_t, modes[i]);
394 }
395 result = wfopen(filename.getWideCharPointer(), wmodes);
396 }
397 delete[] wmodes;
398 } else
399 #endif
400 result = fopen(filename.getCharPointer(), modes);
401 return result;
402 }
403
404 /** associates a stream with the existing file descriptor 'fd'. The mode of
405 * the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be
406 * compatible with the mode of the file descriptor. The file position
407 * indicator of the new stream is set to that belonging to 'fd', and the
408 * error and end-of-file indicators are cleared. Modes "w" or "w+" do not
409 * cause truncation of the file. The file descriptor is not dup'ed, and
410 * will be closed when the stream created by fdopen is closed. The result
411 * of applying fdopen to a shared memory object is undefined.
412 * @param fd file descriptor
413 * @param modes "r", "w" or "a" with possible modifiers "+", "b"
414 * @return true if stream was successfully created, false otherwise, in
415 * which case the error code is set.
416 */
fdopen(int fd,const char * modes)417 OFBool fdopen(int fd, const char *modes)
418 {
419 if (file_) fclose();
420 file_ = :: fdopen(fd, modes);
421 if (file_) popened_ = OFFalse; else storeLastError();
422 return (file_ != NULL);
423 }
424
425 /** opens a process by creating a pipe, forking, and invoking the shell.
426 * Since a pipe is by definition unidirectional, the type argument may
427 * specify only reading or writing, not both; the resulting stream is
428 * correspondingly read-only or write-only. If the object was already
429 * associated with another file or pipe, that one is closed.
430 * @param command shell command line
431 * @param modes "r" or "w"
432 * @return true if pipe was successfully created, false otherwise
433 */
popen(const char * command,const char * modes)434 OFBool popen(const char *command, const char *modes)
435 {
436 if (file_) fclose();
437 #ifdef HAVE_POPEN
438 file_ = :: popen(command, modes);
439 #else
440 file_ = _popen(command, modes);
441 #endif
442 if (file_) popened_ = OFTrue; else storeLastError();
443 return (file_ != NULL);
444 }
445
446 /** opens the file whose name is the string pointed to by path and associates
447 * the stream pointed maintained by this object with it. The original stream
448 * (if it exists) is closed. The mode argument is used just as in the fopen
449 * function. The primary use of the freopen function is to change the file
450 * associated with a standard text stream (stderr, stdin, or stdout).
451 * @param filename path to file
452 * @param modes "r", "w" or "a" with possible modifiers "+", "b"
453 * @return true if stream was successfully created, false otherwise, in
454 * which case the error code is set.
455 */
freopen(const char * filename,const char * modes)456 OFBool freopen(const char *filename, const char *modes)
457 {
458 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
459 // MinGW has EXPLICIT_LFS_64 but no freopen64()
460 file_ = :: freopen64(filename, modes, file_);
461 #else
462 file_ = STDIO_NAMESPACE freopen(filename, modes, file_);
463 #endif
464 if (file_) popened_ = OFFalse; else storeLastError();
465 return (file_ != NULL);
466 }
467
468 /** generates a unique temporary filename. The temporary file is then opened
469 * in binary read/write (w+b) mode. The file will be automatically deleted
470 * when it is closed or the program terminates normally.
471 * @return true if stream was successfully created, false otherwise, in
472 * which case the error code is set.
473 */
tmpfile()474 OFBool tmpfile()
475 {
476 if (file_) fclose();
477 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__)
478 // MinGW has EXPLICIT_LFS_64 but no tmpfile64()
479 file_ = :: tmpfile64();
480 #else
481 file_ = STDIO_NAMESPACE tmpfile();
482 #endif
483 if (file_) popened_ = OFFalse; else storeLastError();
484 return (file_ != NULL);
485 }
486
487 /** dissociates the named stream from its underlying file or set of functions.
488 * If the stream was being used for output, any buffered data is written
489 * first, using fflush. Independent of the return value of this method,
490 * any further access (including another call to fclose()) to the stream
491 * maintained by this object results in undefined behaviour.
492 * @return 0 upon success, EOF otherwise, in which case the error code is set.
493 */
fclose()494 int fclose()
495 {
496 int result = 0;
497 if (file_)
498 {
499 if (popened_)
500 {
501 #ifdef HAVE_PCLOSE
502 result = :: pclose(file_);
503 #else
504 result = _pclose(file_);
505 #endif
506 }
507 else
508 {
509 result = STDIO_NAMESPACE fclose(file_);
510 }
511 // After calling fclose() once, the FILE* is gone even if fclose() failed.
512 file_ = NULL;
513 }
514 if (result) storeLastError();
515 return result;
516 }
517
518 /** waits for the associated process (created with popen) to terminate and
519 * returns the exit status of the command as returned by wait4.
520 * In this implementation, fclose and pclose can be used synonymously.
521 * @return process ID of the child which exited, or -1 on error, in which
522 * case the error code is set
523 */
pclose()524 int pclose() { return fclose(); }
525
526 /** writes n elements of data, each size bytes long, to the stream, obtaining
527 * them from the location given by ptr. Returns the number of items successfully written
528 * (i.e., not the number of characters). If an error occurs the return value is a short
529 * item count (or zero).
530 * @param ptr pointer to buffer
531 * @param size size of item
532 * @param n number of items
533 * @return number of items written
534 */
fwrite(const void * ptr,size_t size,size_t n)535 size_t fwrite(const void *ptr, size_t size, size_t n)
536 {
537 return STDIO_NAMESPACE fwrite(ptr, size, n, file_);
538 }
539
540 /** reads n elements of data, each size bytes long, from the stream, storing
541 * them at the location given by ptr. Returns the number of items successfully
542 * read (i.e., not the number of characters). If an error occurs, or the
543 * end-of-file is reached, the return value is a short item count (or zero).
544 * fread does not distinguish between end-of-file and error, and callers must
545 * use feof and ferror to determine which occurred.
546 * @param ptr pointer to buffer
547 * @param size size of item
548 * @param n number of items
549 * @return number of items read
550 */
fread(void * ptr,size_t size,size_t n)551 size_t fread(void *ptr, size_t size, size_t n)
552 {
553 return STDIO_NAMESPACE fread(ptr, size, n, file_);
554 }
555
556 /** forces a write of all user-space buffered data for the given output or
557 * update stream via the stream's underlying write function. The open status
558 * of the stream is unaffected.
559 * @return 0 upon success, EOF otherwise, in which case the error code is set.
560 */
fflush()561 int fflush()
562 {
563 int result = STDIO_NAMESPACE fflush(file_);
564 if (result) storeLastError();
565 return result;
566 }
567
568 /** reads the next character from stream and returns it as an unsigned char
569 * cast to an int, or EOF on end of file or error.
570 * @return next character from stream or EOF
571 */
fgetc()572 int fgetc() { return STDIO_NAMESPACE fgetc(file_); }
573
574 /** The three types of buffering available are unbuffered, block buffered, and
575 * line buffered. When an output stream is unbuffered, information appears on
576 * the destination file or terminal as soon as written; when it is block
577 * buffered many characters are saved up and written as a block; when it is
578 * line buffered characters are saved up until a newline is output or input
579 * is read from any stream attached to a terminal device (typically stdin).
580 * Normally all files are block buffered. if a stream refers to a terminal
581 * (as stdout normally does) it is line buffered. The standard error stream
582 * stderr is always unbuffered by default. this function allows to set the
583 * mode of the stream to line buffered.
584 * @return 0 upon success, nonzero otherwise, in which case the error code may be set
585 *
586 */
setlinebuf()587 void setlinebuf()
588 {
589 #if defined(_WIN32) || defined(__hpux)
590 this->setvbuf(NULL, _IOLBF, 0);
591 #else
592 :: setlinebuf(file_);
593 #endif
594 }
595
596 /** sets the file position indicator for the stream pointed to by stream to
597 * the beginning of the file. This is equivalent to fseek(0, SEEK_SET)
598 * except that the error indicator for the stream is also cleared.
599 */
rewind()600 void rewind()
601 {
602 #if defined(_WIN32) || defined(__CYGWIN__)
603 /* On these platforms rewind() fails after reading to the end of file
604 * if the file is read-only. Using fseek() instead.
605 */
606 (void) this->fseek(0L, SEEK_SET);
607 #else
608 STDIO_NAMESPACE rewind(file_);
609 #endif
610 }
611
612 /** clears the end-of-file and error indicators for the stream
613 */
clearerr()614 void clearerr() { STDIO_NAMESPACE clearerr(file_); }
615
616 /** tests the end-of-file indicator for the stream, returning non-zero if it
617 * is set. The end-of-file indicator can only be cleared by the function
618 * clearerr. This method is called eof, not feof, because feof() is a macro
619 * on some systems and, therefore, cannot be used as a method name.
620 * @return non-zero if EOF, zero otherwise
621 */
eof()622 int eof() const
623 {
624 #ifdef feof
625 // feof is a macro on some systems. Macros never have namespaces.
626 return feof(file_);
627 #else
628 return STDIO_NAMESPACE feof(file_);
629 #endif
630 }
631
632 /** tests the error indicator for the stream, returning non-zero if it is set.
633 * This method is named error, not ferror, because ferror() is a macro
634 * on some systems and, therefore, cannot be used as a method name.
635 * The error indicator can only be reset by the clearerr function.
636 * @return non-zero if error flag is set, zero otherwise
637 */
error()638 int error()
639 {
640 #ifdef ferror
641 // ferror is a macro on some systems. Macros never have namespaces.
642 return ferror(file_);
643 #else
644 return STDIO_NAMESPACE ferror(file_);
645 #endif
646 }
647
648 /** returns the low-level file descriptor associated with the stream.
649 * The spelling of this member function is different from stdio fileno()
650 * because on some systems (such as MinGW) fileno() is a macro
651 * and, therefore, cannot be used as a method name.
652 * @return low-level file descriptor associated with stream
653 */
654 #ifdef fileno
fileNo()655 int fileNo() { return fileno(file_); }
656 #else
fileNo()657 int fileNo() { return :: fileno(file_); }
658 #endif
659
660 /** The three types of buffering available are unbuffered, block buffered, and
661 * line buffered. When an output stream is unbuffered, information appears on
662 * the destination file or terminal as soon as written; when it is block
663 * buffered many characters are saved up and written as a block; when it is
664 * line buffered characters are saved up until a newline is output or input
665 * is read from any stream attached to a terminal device (typically stdin).
666 * Normally all files are block buffered. if a stream refers to a terminal
667 * (as stdout normally does) it is line buffered. The standard error stream
668 * stderr is always unbuffered by default. This function allows to set the
669 * mode of the stream to unbuffered (if buf is NULL) or block buffered.
670 * @param buf pointer to buffer of size BUFSIZ as declared in cstdio, or NULL
671 * @return 0 upon success, nonzero otherwise, in which case the error code may be set
672 */
setbuf(char * buf)673 void setbuf(char *buf) { STDIO_NAMESPACE setbuf(file_, buf); }
674
675 /** The three types of buffering available are unbuffered, block buffered, and
676 * line buffered. When an output stream is unbuffered, information appears on
677 * the destination file or terminal as soon as written; when it is block
678 * buffered many characters are saved up and written as a block; when it is
679 * line buffered characters are saved up until a newline is output or input
680 * is read from any stream attached to a terminal device (typically stdin).
681 * Normally all files are block buffered. if a stream refers to a terminal
682 * (as stdout normally does) it is line buffered. The standard error stream
683 * stderr is always unbuffered by default. This function allows to set the
684 * stream mode.
685 * @param buf pointer to buffer, may be NULL
686 * @param modes _IONBF (unbuffered) _IOLBF (line buffered) or _IOFBF (fully buffered)
687 * @param n size of buffer, in bytes
688 * @return 0 upon success, nonzero otherwise, in which case the error code may be set
689 */
setvbuf(char * buf,int modes,size_t n)690 int setvbuf(char * buf, int modes, size_t n)
691 {
692 int result = STDIO_NAMESPACE setvbuf(file_, buf, modes, n);
693 if (result) storeLastError();
694 return result;
695 }
696
697 /** The three types of buffering available are unbuffered, block buffered, and
698 * line buffered. When an output stream is unbuffered, information appears on
699 * the destination file or terminal as soon as written; when it is block
700 * buffered many characters are saved up and written as a block; when it is
701 * line buffered characters are saved up until a newline is output or input
702 * is read from any stream attached to a terminal device (typically stdin).
703 * Normally all files are block buffered. if a stream refers to a terminal
704 * (as stdout normally does) it is line buffered. The standard error stream
705 * stderr is always unbuffered by default. This function allows to set the
706 * mode of the stream to unbuffered (if buf is NULL) or block buffered.
707 * @param buf pointer to buffer
708 * @param size size of buffer, in bytes
709 * @return 0 upon success, nonzero otherwise, in which case the error code may be set
710 */
setbuffer(char * buf,size_t size)711 void setbuffer(char *buf, size_t size)
712 {
713 #if defined(_WIN32) || defined(__hpux)
714 this->setvbuf(NULL, buf ? _IOFBF : _IONBF, size);
715 #else
716 :: setbuffer(file_, buf, size);
717 #endif
718 }
719
720 /** writes the character c, cast to an unsigned char, to stream.
721 * @param c character
722 * @return the character written as an unsigned char cast to an int or EOF on error
723 */
fputc(int c)724 int fputc(int c) { return STDIO_NAMESPACE fputc(c, file_); }
725
726 /** reads in at most one less than n characters from stream and stores them
727 * into the buffer pointed to by s. Reading stops after an EOF or a newline.
728 * If a newline is read, it is stored into the buffer. A '@\0' is stored after
729 * the last character in the buffer.
730 * @param s pointer to buffer of size n
731 * @param n buffer size
732 * @return pointer to string
733 */
fgets(char * s,int n)734 char *fgets(char *s, int n) { return STDIO_NAMESPACE fgets(s, n, file_); }
735
736 /** writes the string s to stream, without its trailing '@\0'.
737 * @param s string to be written
738 * @return a non-negative number on success, or EOF on error.
739 */
fputs(const char * s)740 int fputs(const char *s) { return STDIO_NAMESPACE fputs(s, file_); }
741
742 /** pushes c back to stream, cast to unsigned char, where it is available for
743 * subsequent read operations. Pushed - back characters will be returned in
744 * reverse order; only one pushback is guaranteed.
745 * @param c character to push back
746 * @return c on success, or EOF on error.
747 */
ungetc(int c)748 int ungetc(int c) { return STDIO_NAMESPACE ungetc(c, file_); }
749
750 /** sets the file position indicator for the stream pointed to by stream. The
751 * new position, measured in bytes, is obtained by adding offset bytes to the
752 * position specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or
753 * SEEK_END, the offset is relative to the start of the file, the current
754 * position indicator, or end-of-file, respectively. A successful call to the
755 * fseek function clears the end-of- file indicator for the stream and undoes
756 * any effects of the ungetc function on the same stream.
757 * @param off offset to seek to
758 * @param whence SEEK_SET, SEEK_CUR, or SEEK_END
759 * @return 0 upon success, -1 otherwise in which case the error code is set.
760 */
fseek(offile_off_t off,int whence)761 int fseek(offile_off_t off, int whence)
762 {
763 int result;
764 #ifdef _WIN32
765 // Windows does not have a 64-bit fseek.
766 // We emulate fseek through fsetpos, which does exist on Windows.
767 // fpos_t is (hopefully always) defined as __int64 on this platform
768 offile_fpos_t off2 = off;
769 fpos_t pos;
770 struct _stati64 buf;
771 switch (whence)
772 {
773 case SEEK_END:
774 // flush write buffer, if any, so that the file size is correct
775 STDIO_NAMESPACE fflush(file_);
776 #if 0
777 // Python implementation based on _lseeki64(). May be unsafe because
778 // there is no guarantee that fflush also empties read buffers.
779 STDIO_NAMESPACE fflush(file_);
780 #ifdef fileno
781 if (_lseeki64( fileno(file_), 0, 2) == -1)
782 #else
783 if (_lseeki64(:: fileno(file_), 0, 2) == -1)
784 #endif
785 {
786 storeLastError();
787 return -1;
788 }
789 // fall through
790 #else
791 // determine file size (using underlying file descriptor). This should be safe.
792 #ifdef fileno
793 if (_fstati64( fileno(file_), &buf) == -1)
794 #else
795 if (_fstati64(:: fileno(file_), &buf) == -1)
796 #endif
797 {
798 storeLastError();
799 return -1;
800 }
801
802 // fsetpos position is offset + file size.
803 off2 += buf.st_size;
804 break;
805 #endif
806 case SEEK_CUR:
807 if (STDIO_NAMESPACE fgetpos(file_, &pos) != 0)
808 {
809 storeLastError();
810 return -1;
811 }
812
813 off2 += pos;
814 break;
815 case SEEK_SET:
816 /* do nothing */
817 break;
818 }
819 result = this->fsetpos(&off2);
820 #elif defined(__BEOS__)
821 result = :: _fseek(file_, off, whence);
822 #else
823 #ifdef HAVE_FSEEKO
824 #ifdef EXPLICIT_LFS_64
825 result = :: fseeko64(file_, off, whence);
826 #else
827 result = :: fseeko(file_, off, whence);
828 #endif
829 #else
830 result = STDIO_NAMESPACE fseek(file_, off, whence);
831 #endif
832 #endif
833 if (result) storeLastError();
834 return result;
835 }
836
837 /** obtains the current value of the file position indicator for the stream pointed to by the stream.
838 * @return current file position
839 */
ftell()840 offile_off_t ftell()
841 {
842 offile_off_t result;
843 #ifdef _WIN32
844 // Windows does not have a 64-bit ftell, and _telli64 cannot be used
845 // because it operates on file descriptors and ignores FILE buffers.
846 // We emulate ftell through fgetpos, which does exist on Windows.
847 // fpos_t is (hopefully always) defined as __int64 on this platform.
848 offile_fpos_t pos;
849 if (this->fgetpos(&pos) != 0)
850 {
851 storeLastError();
852 return -1;
853 }
854 return pos;
855 #else
856 #ifdef HAVE_FSEEKO
857 #ifdef EXPLICIT_LFS_64
858 result = :: ftello64(file_);
859 #else
860 result = :: ftello(file_);
861 #endif
862 #else
863 result = STDIO_NAMESPACE ftell(file_);
864 #endif
865 #endif
866 if (result < 0) storeLastError();
867 return result;
868 }
869
870 /** alternate interface equivalent to ftell, storing the current value of the
871 * file offset into the object referenced by pos. On some non-UNIX systems an
872 * fpos_t object may be a complex object and these routines may be the only
873 * way to portably reposition a text stream.
874 * @param pos pointer to offile_fpos_t structure
875 * @return 0 upon success, -1 otherwise in which case the error code is set.
876 */
fgetpos(offile_fpos_t * pos)877 int fgetpos(offile_fpos_t *pos)
878 {
879 int result;
880 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__) && ! defined(__QNX__)
881 // MinGW and QNX have EXPLICIT_LFS_64 but no fgetpos64()
882 result = :: fgetpos64(file_, pos);
883 #else
884 result = STDIO_NAMESPACE fgetpos(file_, pos);
885 #endif
886 if (result) storeLastError();
887 return result;
888 }
889
890 /** alternate interface equivalent to fseek (with whence set to SEEK_SET),
891 * setting the current value of the file offset from the object referenced by
892 * pos. On some non-UNIX systems an fpos_t object may be a complex object and
893 * these routines may be the only way to portably reposition a text stream.
894 * @param pos pointer to offile_fpos_t structure
895 * @return 0 upon success, -1 otherwise in which case the error code is set.
896 */
fsetpos(offile_fpos_t * pos)897 int fsetpos(offile_fpos_t *pos)
898 {
899 int result;
900 #if defined(EXPLICIT_LFS_64) && ! defined(__MINGW32__) && ! defined(__QNX__)
901 // MinGW and QNX have EXPLICIT_LFS_64 but no fsetpos64()
902 result = :: fsetpos64(file_, pos);
903 #else
904 result = STDIO_NAMESPACE fsetpos(file_, pos);
905 #endif
906 if (result) storeLastError();
907 return result;
908 }
909
910 /** print formatted string into stream, see printf(3)
911 * @param format format string
912 * @param ... further parameters according to format string
913 * @return number of characters printed
914 */
fprintf(const char * format,...)915 int fprintf(const char *format, ...)
916 {
917 int result = 0;
918 va_list ap;
919 va_start(ap, format);
920 result = STDIO_NAMESPACE vfprintf(file_, format, ap);
921 va_end(ap);
922 return result;
923 }
924
925 /** print formatted string into stream, see printf(3)
926 * @param format format string
927 * @param arg list of further parameters according to format string
928 * @return number of characters printed
929 */
vfprintf(const char * format,va_list arg)930 int vfprintf(const char *format, va_list arg)
931 {
932 return STDIO_NAMESPACE vfprintf(file_, format, arg);
933 }
934
935 // we cannot emulate fscanf because we would need vfscanf for this
936 // purpose, which does not exist, e.g. on Win32.
937
938 /** return FILE pointer managed by this object. This allows the user
939 * to call some stdio functions that are not encapsulated in this class
940 * (but possibly should be).
941 * @return pointer to FILE structure managed by this object
942 */
file()943 FILE *file() { return file_; }
944
945 /** return true if this object is currently associated with a stream, false otherwise
946 * @return true if this object is currently associated with a stream, false otherwise
947 */
open()948 OFBool open() const { return file_ != NULL; }
949
950 /** return last error code for this stream
951 * @return last error code for this stream
952 */
getLastError()953 offile_errno_t getLastError() const { return lasterror_; }
954
955 /** return string describing last error code for this stream
956 * @param s string describing last error code for this stream returned in this parameter
957 */
getLastErrorString(OFString & s)958 void getLastErrorString(OFString& s) const
959 {
960 char buf[1000];
961 s = OFStandard::strerror(lasterror_, buf, 1000);
962 }
963
964 // wide character functions (disabled by default, since currently not used within DCMTK)
965 #ifdef WIDE_CHAR_FILE_IO_FUNCTIONS
966
967 /** When mode is zero, the fwide function determines the current orientation
968 * of stream. It returns a value > 0 if stream is wide-character oriented,
969 * i.e. if wide character I/O is permitted but char I/O is disallowed. It
970 * returns a value < 0 if stream is byte oriented, i.e. if char I/O is
971 * permitted but wide character I/O is disallowed. It returns zero if stream
972 * has no orientation yet; in this case the next I/O operation might change
973 * the orientation (to byte oriented if it is a char I/O operation, or to
974 * wide-character oriented if it is a wide character I/O operation).
975 * Once a stream has an orientation, it cannot be changed and persists until
976 * the stream is closed.
977 * When mode is non-zero, the fwide function first attempts to set stream's
978 * orientation (to wide-character oriented if mode > 0, or to byte oriented
979 * if mode < 0). It then returns a value denoting the current orientation, as
980 * above.
981 * @param mode mode of operation for fwide
982 * @return orientation of stream
983 */
fwide(int mode)984 int fwide(int mode)
985 {
986 return STDIO_NAMESPACE fwide(file_, mode);
987 }
988
989 /** reads a wide character from stream and returns it. If the end of stream is
990 * reached, or if ferror(stream) becomes true, it returns WEOF. If a wide
991 * character conversion error occurs, it sets the error code to EILSEQ and returns
992 * WEOF.
993 * @return next character from stream or WEOF
994 */
fgetwc()995 wint_t fgetwc()
996 {
997 wint_t result = STDIO_NAMESPACE fgetwc(file_);
998 if (result == WEOF) storeLastError();
999 return result;
1000 }
1001
1002 /** writes the wide character wc to stream. If ferror(stream) becomes true, it returns WEOF.
1003 * If a wide character conversion error occurs, it sets the error code to EILSEQ and returns WEOF.
1004 * Otherwise it returns wc.
1005 * @param wc wide character to write to stream
1006 * @return character written or WEOF
1007 */
fputwc(wchar_t wc)1008 wint_t fputwc(wchar_t wc)
1009 {
1010 wint_t result = STDIO_NAMESPACE fputwc(wc, file_);
1011 if (result == WEOF) storeLastError();
1012 return result;
1013 }
1014
1015 /** pushes back a wide character onto stream and returns it. If wc is WEOF, it
1016 * returns WEOF. If wc is an invalid wide character, it sets errno to EILSEQ
1017 * and returns WEOF. If wc is a valid wide character, it is pushed back onto
1018 * the stream and thus becomes available for future wide character read
1019 * operations. The file-position indicator is decremented by one or more.
1020 * The end-of-file indicator is cleared. The backing storage of the file is
1021 * not affected. Note: wc need not be the last wide character read from the
1022 * stream; it can be any other valid wide character. If the implementation
1023 * supports multiple push-back operations in a row, the pushed-back wide
1024 * characters will be read in reverse order; however, only one level of
1025 * push-back is guaranteed.
1026 * @param wc wide character to put back to stream
1027 * @return character put back or WEOF
1028 */
ungetwc(wint_t wc)1029 wint_t ungetwc(wint_t wc)
1030 {
1031 wint_t result = STDIO_NAMESPACE ungetwc(wc, file_);
1032 if (result == WEOF) storeLastError();
1033 return result;
1034 }
1035
1036 /** print formatted wide string into stream, see wprintf(3)
1037 * @param format format string
1038 * @param ... further parameters according to format string
1039 * @return number of characters printed
1040 */
fwprintf(const wchar_t * format,...)1041 int fwprintf(const wchar_t *format, ...)
1042 {
1043 int result = 0;
1044 va_list ap;
1045 va_start(ap, format);
1046 result = STDIO_NAMESPACE vfwprintf(file_, format, ap);
1047 va_end(ap);
1048 return result;
1049 }
1050
1051 /** print formatted wide string into stream, see printf(3)
1052 * @param format format string
1053 * @param arg list of further parameters according to format string
1054 * @return number of characters printed
1055 */
vfwprintf(const wchar_t * format,va_list arg)1056 int vfwprintf(const wchar_t *format, va_list arg)
1057 {
1058 return STDIO_NAMESPACE vfwprintf(file_, format, arg);
1059 }
1060
1061 // we cannot emulate fwscanf because we would need vfwscanf for this
1062 // purpose, which does not exist, e.g. on Win32.
1063
1064 #endif /* WIDE_CHAR_FILE_IO_FUNCTIONS */
1065
1066 private:
1067
1068 // private undefined copy constructor
1069 OFFile(const OFFile &arg);
1070
1071 // private undefined assignment operator
1072 OFFile &operator=(const OFFile &arg);
1073
1074 /// the file maintained by this object
1075 FILE *file_;
1076
1077 /// a flag indicating whether or not this object was created with popen().
1078 OFBool popened_;
1079
1080 /// the last error code for operations of this stream
1081 offile_errno_t lasterror_;
1082
1083 /// store last error code. For now we simply store the content of errno.
storeLastError()1084 inline void storeLastError()
1085 {
1086 lasterror_ = errno;
1087 }
1088
1089 };
1090
1091 #endif
1092