1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/*
*
* Copyright (C) 2002-2024, 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: dcmdata
*
* Author: Marco Eichelberg
*
* Purpose: DcmOutputFileStream and related classes,
* implements streamed output to files.
*
*/
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dcostrmf.h"
#include "dcmtk/dcmdata/dcerror.h"
#include "dcmtk/ofstd/ofconsol.h"
BEGIN_EXTERN_C
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_IO_H
#include <io.h>
#endif
END_EXTERN_C
DcmFileConsumer::DcmFileConsumer(const OFFilename &filename)
: DcmConsumer()
, file_container_()
, file_(file_container_)
, status_(EC_Normal)
{
if (!file_.fopen(filename, "wb"))
{
OFString buffer = OFStandard::getLastSystemErrorCode().message();
status_ = makeOFCondition(OFM_dcmdata, 19, OF_error, buffer.c_str());
}
}
DcmFileConsumer::DcmFileConsumer(FILE *file)
: DcmConsumer()
, file_container_(file)
, file_(file_container_)
, status_(EC_Normal)
{
}
DcmFileConsumer::DcmFileConsumer(OFFile &file)
: DcmConsumer()
, file_container_()
, file_(file)
, status_(EC_Normal)
{
}
DcmFileConsumer::~DcmFileConsumer()
{
file_.fclose();
}
OFBool DcmFileConsumer::good() const
{
return status_.good();
}
OFCondition DcmFileConsumer::status() const
{
return status_;
}
OFBool DcmFileConsumer::isFlushed() const
{
return OFTrue;
}
offile_off_t DcmFileConsumer::avail() const
{
// since we cannot report "unlimited", let's claim that we can still write 2GB.
// Note that offile_off_t is a signed type.
return 2147483647L;
}
offile_off_t DcmFileConsumer::write(const void *buf, offile_off_t buflen)
{
offile_off_t result = 0;
if (buflen && buf && status_.good() && file_.open())
{
#ifdef WRITE_VERY_LARGE_CHUNKS
/* This is the old behaviour prior to DCMTK 3.5.5 */
result = OFstatic_cast(offile_off_t, file_.fwrite(buf, 1, OFstatic_cast(size_t, buflen)));
#else
/* On Windows (at least for some versions of MSVC), calls to fwrite() for more than
* 67,076,095 bytes (a bit less than 64 MByte) fail if we're writing to a network
* share. See MSDN KB899149. As a workaround, we always write in chunks of
* 32M which should hardly negatively affect performance.
*/
#define DcmFileConsumer_MAX_CHUNK_SIZE 33554432 /* 32 MByte */
offile_off_t written;
const char *buf2 = OFstatic_cast(const char *, buf);
while (buflen > DcmFileConsumer_MAX_CHUNK_SIZE)
{
written = OFstatic_cast(offile_off_t, file_.fwrite(buf2, 1, DcmFileConsumer_MAX_CHUNK_SIZE));
result += written;
buf2 += written;
// if we have not written a complete chunk, there is problem; bail out
if (written == DcmFileConsumer_MAX_CHUNK_SIZE) buflen -= DcmFileConsumer_MAX_CHUNK_SIZE; else buflen = 0;
}
// last call to fwrite if the file size is not a multiple of DcmFileConsumer_MAX_CHUNK_SIZE
if (buflen)
{
written = OFstatic_cast(offile_off_t, file_.fwrite(buf2, 1, OFstatic_cast(size_t, buflen)));
result += written;
}
#endif
}
return result;
}
void DcmFileConsumer::flush()
{
// nothing to flush
}
void DcmFileConsumer::fclose()
{
int result = file_.fclose();
if (result)
{
OFString buffer = OFStandard::getLastSystemErrorCode().message();
status_ = makeOFCondition(OFM_dcmdata, 19, OF_error, buffer.c_str());
}
else status_ = EC_Normal;
}
/* ======================================================================= */
DcmOutputFileStream::DcmOutputFileStream(const OFFilename &filename)
: DcmOutputStream(&consumer_) // safe because DcmOutputStream only stores pointer
, consumer_(filename)
{
}
DcmOutputFileStream::DcmOutputFileStream(FILE *file)
: DcmOutputStream(&consumer_) // safe because DcmOutputStream only stores pointer
, consumer_(file)
{
}
DcmOutputFileStream::DcmOutputFileStream(OFFile& file)
: DcmOutputStream(&consumer_) // safe because DcmOutputStream only stores pointer
, consumer_(file)
{
}
OFCondition DcmOutputFileStream::fclose()
{
// last attempt to flush stream before file is closed
flush();
#ifdef DEBUG
if (! isFlushed())
{
DCMDATA_WARN("closing unflushed DcmOutputFileStream, loss of data!");
}
#endif
consumer_.fclose();
return consumer_.status();
}
DcmOutputFileStream::~DcmOutputFileStream()
{
// last attempt to flush stream before file is closed
flush();
#ifdef DEBUG
if (! isFlushed())
{
DCMDATA_WARN("closing unflushed DcmOutputFileStream, loss of data!");
}
#endif
}
|