/* * * Copyright (C) 2002-2021, 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: DcmInputFileStream and related classes, * implements streamed input from files. * */ #include "dcmtk/config/osconfig.h" #include "dcmtk/dcmdata/dcistrmf.h" #include "dcmtk/dcmdata/dcistrmb.h" #include "dcmtk/dcmdata/dcerror.h" BEGIN_EXTERN_C #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_IO_H #include #endif END_EXTERN_C DcmFileProducer::DcmFileProducer(const OFFilename &filename, offile_off_t offset) : DcmProducer() , file_() , status_(EC_Normal) , size_(0) { if (file_.fopen(filename, "rb")) { // Get number of bytes in file file_.fseek(0L, SEEK_END); size_ = file_.ftell(); if (0 != file_.fseek(offset, SEEK_SET)) { OFString s("(unknown error code)"); file_.getLastErrorString(s); status_ = makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str()); } } else { OFString s("(unknown error code)"); file_.getLastErrorString(s); status_ = makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str()); } } DcmFileProducer::~DcmFileProducer() { } OFBool DcmFileProducer::good() const { return status_.good(); } OFCondition DcmFileProducer::status() const { return status_; } OFBool DcmFileProducer::eos() { if (file_.open()) { return (file_.eof() || (size_ == file_.ftell())); } else return OFTrue; } offile_off_t DcmFileProducer::avail() { if (file_.open()) return size_ - file_.ftell(); else return 0; } offile_off_t DcmFileProducer::read(void *buf, offile_off_t buflen) { offile_off_t result = 0; if (status_.good() && file_.open() && buf && buflen) { result = OFstatic_cast(offile_off_t, file_.fread(buf, 1, OFstatic_cast(size_t, buflen))); } return result; } offile_off_t DcmFileProducer::skip(offile_off_t skiplen) { offile_off_t result = 0; if (status_.good() && file_.open() && skiplen) { offile_off_t pos = file_.ftell(); result = (size_ - pos < skiplen) ? (size_ - pos) : skiplen; if (file_.fseek(result, SEEK_CUR)) { OFString s("(unknown error code)"); file_.getLastErrorString(s); status_ = makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str()); } } return result; } void DcmFileProducer::putback(offile_off_t num) { if (status_.good() && file_.open() && num) { offile_off_t pos = file_.ftell(); if (num <= pos) { if (file_.fseek(-num, SEEK_CUR)) { OFString s("(unknown error code)"); file_.getLastErrorString(s); status_ = makeOFCondition(OFM_dcmdata, 18, OF_error, s.c_str()); } } else status_ = EC_PutbackFailed; // tried to putback before start of file } } /* ======================================================================= */ DcmInputFileStreamFactory::DcmInputFileStreamFactory(const OFFilename &filename, offile_off_t offset) : DcmInputStreamFactory() , filename_(filename) , offset_(offset) { } DcmInputFileStreamFactory::DcmInputFileStreamFactory(const DcmInputFileStreamFactory& arg) : DcmInputStreamFactory(arg) , filename_(arg.filename_) , offset_(arg.offset_) { } DcmInputFileStreamFactory::~DcmInputFileStreamFactory() { } DcmInputStream *DcmInputFileStreamFactory::create() const { return new DcmInputFileStream(filename_, offset_); } /* ======================================================================= */ DcmInputFileStream::DcmInputFileStream(const OFFilename &filename, offile_off_t offset) : DcmInputStream(&producer_) // safe because DcmInputStream only stores pointer , producer_(filename, offset) , filename_(filename) { } DcmInputFileStream::~DcmInputFileStream() { } DcmInputStreamFactory *DcmInputFileStream::newFactory() const { DcmInputStreamFactory *result = NULL; if (currentProducer() == &producer_) { // no filter installed, can create factory object result = new DcmInputFileStreamFactory(filename_, tell()); } return result; } /* ======================================================================= */ DcmInputStream *DcmTempFileHandler::create() const { return new DcmInputFileStream(filename_, 0); } DcmTempFileHandler::DcmTempFileHandler(const OFFilename &filename) #ifdef WITH_THREADS : refCount_(1), mutex_(), filename_(filename) #else : refCount_(1), filename_(filename) #endif { } DcmTempFileHandler::~DcmTempFileHandler() { OFStandard::deleteFile(filename_); } DcmTempFileHandler *DcmTempFileHandler::newInstance(const OFFilename &filename) { return new DcmTempFileHandler(filename); } void DcmTempFileHandler::increaseRefCount() { #ifdef WITH_THREADS mutex_.lock(); #endif ++refCount_; #ifdef WITH_THREADS mutex_.unlock(); #endif } void DcmTempFileHandler::decreaseRefCount() { #ifdef WITH_THREADS mutex_.lock(); #endif size_t result = --refCount_; #ifdef WITH_THREADS mutex_.unlock(); #endif if (result == 0) delete this; } /* ======================================================================= */ DcmInputTempFileStreamFactory::DcmInputTempFileStreamFactory(DcmTempFileHandler *handler) : DcmInputStreamFactory() , fileHandler_(handler) { fileHandler_->increaseRefCount(); } DcmInputTempFileStreamFactory::DcmInputTempFileStreamFactory(const DcmInputTempFileStreamFactory &arg) : DcmInputStreamFactory(arg) , fileHandler_(arg.fileHandler_) { fileHandler_->increaseRefCount(); } DcmInputTempFileStreamFactory::~DcmInputTempFileStreamFactory() { fileHandler_->decreaseRefCount(); } DcmInputStream *DcmInputTempFileStreamFactory::create() const { return fileHandler_->create(); } DcmInputStreamFactory *DcmInputTempFileStreamFactory::clone() const { return new DcmInputTempFileStreamFactory(*this); }