/*============================================================================ MetaIO Copyright 2000-2010 Insight Software Consortium Distributed under the OSI-approved BSD License (the "License"); see accompanying file Copyright.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ #include "metaImage.h" #include // for std::min & std::max #include // for memcpy #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x0580) # include #endif #if defined(_WIN32) # include #endif // support for access #ifndef _WIN32 # include # include /* sigprocmask */ # include # include # include # include # include # include #endif namespace { void openReadStream(std::ifstream & inputStream, const std::string & fname) { #ifdef __sgi inputStream.open(fname, std::ios::in); #else inputStream.open(fname, std::ios::in | std::ios::binary); #endif } void openWriteStream(std::ofstream & outputStream, const std::string & fname, bool append) { // Some older sgi compilers have a error in the ofstream constructor // that requires a file to exist for output #ifdef __sgi { std::ofstream tFile(fname, std::ios::out); tFile.close(); } #endif if (!append) { #ifdef __sgi outputStream.open(fname, std::ios::out); #else outputStream.open(fname, std::ios::binary | std::ios::out); #endif } else { #ifdef __sgi outputStream.open(fname, std::ios::app | std::ios::out); #else outputStream.open(fname, std::ios::binary | std::ios::app | std::ios::out); #endif } } } // end anonymous namespace #if (METAIO_USE_NAMESPACE) namespace METAIO_NAMESPACE { #endif // 1 Gigabyte is the maximum chunk to read/write in on function call static const std::streamoff MaxIOChunk = 1024 * 1024 * 1024; // // MetaImage Constructors // MetaImage::MetaImage() : MetaObject() { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; m_CompressionTable->buffer = nullptr; MetaImage::Clear(); } // MetaImage::MetaImage(const char * _headerName) : MetaObject() { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; m_CompressionTable->buffer = nullptr; MetaImage::Clear(); Read(_headerName); } // MetaImage::MetaImage(MetaImage * _im) : MetaObject() { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; m_CompressionTable->buffer = nullptr; MetaImage::Clear(); InitializeEssential(_im->NDims(), _im->DimSize(), _im->ElementSpacing(), _im->ElementType(), _im->ElementNumberOfChannels(), _im->ElementData(), false); MetaImage::CopyInfo(_im); } // void MetaImage::InitHelper(int _nDims, const int * _dimSize, const double * _elementSpacing, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData) { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->buffer = nullptr; m_CompressionTable->compressedStream = nullptr; Clear(); if (_elementData == nullptr) { InitializeEssential(_nDims, _dimSize, _elementSpacing, _elementType, _elementNumberOfChannels, nullptr, true); } else { InitializeEssential(_nDims, _dimSize, _elementSpacing, _elementType, _elementNumberOfChannels, _elementData, false); } } // MetaImage::MetaImage(int _nDims, const int * _dimSize, const float * _elementSpacing, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData) : MetaObject() { // Only consider at most 10 element of spacing: // See MetaObject::InitializeEssential(_nDims) double tmpElementSpacing[10]; int ndims = std::max(std::min(_nDims, 10), 0); for (int i = 0; i < ndims; ++i) { tmpElementSpacing[i] = static_cast(_elementSpacing[i]); } InitHelper(_nDims, _dimSize, tmpElementSpacing, _elementType, _elementNumberOfChannels, _elementData); } // MetaImage::MetaImage(int _nDims, const int * _dimSize, const double * _elementSpacing, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData) : MetaObject() { InitHelper(_nDims, _dimSize, _elementSpacing, _elementType, _elementNumberOfChannels, _elementData); } // MetaImage::MetaImage(int _x, int _y, double _elementSpacingX, double _elementSpacingY, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData) : MetaObject() { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; m_CompressionTable->buffer = nullptr; MetaImage::Clear(); int ds[2]; ds[0] = _x; ds[1] = _y; double es[2]; es[0] = _elementSpacingX; es[1] = _elementSpacingY; if (_elementData == nullptr) { InitializeEssential(2, ds, es, _elementType, _elementNumberOfChannels, nullptr, true); } else { InitializeEssential(2, ds, es, _elementType, _elementNumberOfChannels, _elementData, false); } } // MetaImage::MetaImage(int _x, int _y, int _z, double _elementSpacingX, double _elementSpacingY, double _elementSpacingZ, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData) : MetaObject() { META_DEBUG_PRINT( "MetaImage()" ); m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; m_CompressionTable->buffer = nullptr; MetaImage::Clear(); int ds[3]; ds[0] = _x; ds[1] = _y; ds[2] = _z; double es[3]; es[0] = _elementSpacingX; es[1] = _elementSpacingY; es[2] = _elementSpacingZ; if (_elementData == nullptr) { InitializeEssential(3, ds, es, _elementType, _elementNumberOfChannels, nullptr, true); } else { InitializeEssential(3, ds, es, _elementType, _elementNumberOfChannels, _elementData, false); } } // MetaImage::~MetaImage() { MetaImage::M_ResetValues(); } // void MetaImage::PrintInfo() const { int i; MetaObject::PrintInfo(); std::string s; MET_ImageModalityToString(m_Modality, s); std::cout << "Modality = " << s << std::endl; std::cout << "DimSize = "; for (i = 0; i < m_NDims; i++) { std::cout << m_DimSize[i] << " "; } std::cout << std::endl; std::cout << "SubQuantity = "; for (i = 0; i < m_NDims; i++) { std::cout << m_SubQuantity[i] << " "; } std::cout << std::endl; std::cout << "Quantity = " << m_Quantity << std::endl; std::cout << "HeaderSize = " << m_HeaderSize << std::endl; std::cout << "SequenceID = "; for (i = 0; i < m_NDims; i++) { std::cout << m_SequenceID[i] << " "; } std::cout << std::endl; std::cout << "ElementSizeValid = " << static_cast(m_ElementSizeValid) << std::endl; std::cout << "ElementSize = "; for (i = 0; i < m_NDims; i++) { std::cout << m_ElementSize[i] << " "; } std::cout << std::endl; char str[22]; MET_TypeToString(m_ElementType, str); std::cout << "ElementType = " << str << std::endl; std::cout << "ElementNumberOfChannels = " << m_ElementNumberOfChannels << std::endl; if (m_ElementMinMaxValid) { std::cout << "Min and Max are valid" << std::endl; std::cout << " Min = " << m_ElementMin << std::endl; std::cout << " Max = " << m_ElementMax << std::endl; } else { std::cout << "Min and Max are not valid" << std::endl; } std::cout << "ElementToIntensityFunctionSlope = " << m_ElementToIntensityFunctionSlope << std::endl; std::cout << "ElementToIntensityFunctionOffset = " << m_ElementToIntensityFunctionOffset << std::endl; std::cout << "AutoFreeElementData = " << ((m_AutoFreeElementData) ? "True" : "False") << std::endl; std::cout << "ElementData = " << ((m_ElementData == nullptr) ? "NULL" : "Valid") << std::endl; std::cout << "ElementDataFileName = " << m_ElementDataFileName << std::endl; } void MetaImage::CopyInfo(const MetaObject * _object) { MetaObject::CopyInfo(_object); if (_object) { const MetaImage * im; try { im = dynamic_cast(_object); } catch (...) { return; } if (im) { Modality(im->Modality()); HeaderSize(im->HeaderSize()); SequenceID(im->SequenceID()); ElementSizeValid(im->ElementSizeValid()); if (im->ElementSizeValid()) { ElementSize(im->ElementSize()); } ElementMinMaxValid(im->ElementMinMaxValid()); if (im->ElementMinMaxValid()) { ElementMin(im->ElementMin()); ElementMax(im->ElementMax()); } ElementToIntensityFunctionSlope(im->ElementToIntensityFunctionSlope()); ElementToIntensityFunctionOffset(im->ElementToIntensityFunctionOffset()); } } } /** Clear function */ void MetaImage::Clear() { META_DEBUG_PRINT( "MetaImage: Clear" ); m_Modality = MET_MOD_UNKNOWN; m_DimSize[0] = 0; m_SubQuantity[0] = 0; m_Quantity = 0; m_HeaderSize = 0; memset(m_SequenceID, 0, sizeof(m_SequenceID)); m_ElementSizeValid = false; memset(m_ElementSize, 0, sizeof(m_ElementSize)); m_ElementType = MET_NONE; m_ElementNumberOfChannels = 1; m_ElementMinMaxValid = false; m_ElementMin = 0; m_ElementMax = 0; m_ElementToIntensityFunctionSlope = 1; m_ElementToIntensityFunctionOffset = 0; m_AutoFreeElementData = true; m_ElementData = nullptr; m_ElementDataFileName = ""; MetaObject::Clear(); strcpy(m_ObjectTypeName, "Image"); // Change the default for this object m_BinaryData = true; if (m_CompressionTable) { if (m_CompressionTable->compressedStream) { inflateEnd(m_CompressionTable->compressedStream); delete m_CompressionTable->compressedStream; delete[] m_CompressionTable->buffer; m_CompressionTable->buffer = nullptr; } m_CompressionTable->compressedStream = nullptr; m_CompressionTable->offsetList.clear(); } else { m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->compressedStream = nullptr; } } bool MetaImage::InitializeEssential(int _nDims, const int * _dimSize, const float * _elementSpacing, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData, bool _allocElementMemory) { // Only consider at most 10 element of spacing: // See MetaObject::InitializeEssential(_nDims) double tmpElementSpacing[10]; int ndims = std::max(std::min(_nDims, 10), 0); for (int i = 0; i < ndims; ++i) { tmpElementSpacing[i] = static_cast(_elementSpacing[i]); } return InitializeEssential( _nDims, _dimSize, tmpElementSpacing, _elementType, _elementNumberOfChannels, _elementData, _allocElementMemory); } bool MetaImage::InitializeEssential(int _nDims, const int * _dimSize, const double * _elementSpacing, MET_ValueEnumType _elementType, int _elementNumberOfChannels, void * _elementData, bool _allocElementMemory) { META_DEBUG_PRINT( "MetaImage: Initialize" ); MetaObject::InitializeEssential(_nDims); int i; if (!m_CompressionTable) { m_CompressionTable = new MET_CompressionTableType; m_CompressionTable->buffer = nullptr; m_CompressionTable->compressedStream = nullptr; } m_SubQuantity[0] = 1; m_Quantity = 1; m_ElementSizeValid = false; for (i = 0; i < m_NDims; i++) { m_DimSize[i] = _dimSize[i]; m_Quantity *= _dimSize[i]; if (i > 0) { m_SubQuantity[i] = m_SubQuantity[i - 1] * m_DimSize[i - 1]; } m_ElementSpacing[i] = _elementSpacing[i]; if (m_ElementSize[i] == 0) { m_ElementSize[i] = m_ElementSpacing[i]; } else { m_ElementSizeValid = true; } } m_ElementType = _elementType; m_ElementNumberOfChannels = _elementNumberOfChannels; if (_elementData != nullptr) { m_AutoFreeElementData = false; m_ElementData = _elementData; } else if (_allocElementMemory) { m_AutoFreeElementData = true; MET_SizeOfType(m_ElementType, &i); m_ElementData = new char[static_cast(m_Quantity * m_ElementNumberOfChannels * i)]; if (m_ElementData == nullptr) { std::cerr << "MetaImage:: M_Allocate:: Insufficient memory" << std::endl; return false; } } else { m_AutoFreeElementData = true; m_ElementData = nullptr; } return true; } int MetaImage::HeaderSize() const { return m_HeaderSize; } void MetaImage::HeaderSize(int _headerSize) { m_HeaderSize = _headerSize; } MET_ImageModalityEnumType MetaImage::Modality() const { return m_Modality; } void MetaImage::Modality(MET_ImageModalityEnumType _modality) { m_Modality = _modality; } const int * MetaImage::DimSize() const { return m_DimSize; } int MetaImage::DimSize(int _i) const { return m_DimSize[_i]; } std::streamoff MetaImage::Quantity() const { return m_Quantity; } const std::streamoff * MetaImage::SubQuantity() const { return m_SubQuantity; } std::streamoff MetaImage::SubQuantity(int _i) const { return m_SubQuantity[_i]; } const float * MetaImage::SequenceID() const { return m_SequenceID; } float MetaImage::SequenceID(int _i) const { return m_SequenceID[_i]; } void MetaImage::SequenceID(const float * _sequenceID) { memcpy(m_SequenceID, _sequenceID, m_NDims * sizeof(float)); } void MetaImage::SequenceID(int _i, float _value) { m_SequenceID[_i] = _value; } bool MetaImage::ElementSizeValid() const { return m_ElementSizeValid; } void MetaImage::ElementSizeValid(bool _elementSizeValid) { m_ElementSizeValid = _elementSizeValid; } const double * MetaImage::ElementSize() const { return m_ElementSize; } double MetaImage::ElementSize(int _i) const { return m_ElementSize[_i]; } void MetaImage::ElementSize(const double * _elementSize) { memcpy(m_ElementSize, _elementSize, m_NDims * sizeof(*m_ElementSize)); m_ElementSizeValid = true; } void MetaImage::ElementSize(const float * _elementSize) { for (int i = 0; i < m_NDims; ++i) { m_ElementSize[i] = static_cast(_elementSize[i]); } m_ElementSizeValid = true; } void MetaImage::ElementSize(int _i, double _value) { m_ElementSize[_i] = _value; m_ElementSizeValid = true; } MET_ValueEnumType MetaImage::ElementType() const { return m_ElementType; } void MetaImage::ElementType(MET_ValueEnumType _elementType) { m_ElementType = _elementType; } int MetaImage::ElementNumberOfChannels() const { return m_ElementNumberOfChannels; } void MetaImage::ElementNumberOfChannels(int _elementNumberOfChannels) { m_ElementNumberOfChannels = _elementNumberOfChannels; } void MetaImage::ElementByteOrderSwap(std::streamoff _quantity) { // use the user provided value if provided or the internal ivar std::streamoff quantity = _quantity ? _quantity : m_Quantity; META_DEBUG_PRINT( "MetaImage: ElementByteOrderSwap" ); int eSize; MET_SizeOfType(m_ElementType, &eSize); switch (eSize) { default: case 0: case 1: { break; } case 2: { for (size_t i = 0; i < static_cast(quantity * m_ElementNumberOfChannels); i++) { (static_cast(m_ElementData))[i] = MET_ByteOrderSwapShort((static_cast(m_ElementData))[i]); } break; } case 4: { for (size_t i = 0; i < static_cast(quantity * m_ElementNumberOfChannels); i++) { (static_cast(m_ElementData))[i] = MET_ByteOrderSwapLong((static_cast(m_ElementData))[i]); } break; } case 8: { char * data = static_cast(m_ElementData); for (size_t i = 0; i < static_cast(quantity * m_ElementNumberOfChannels); i++) { MET_ByteOrderSwap8(data); data += 8; } break; } } m_BinaryDataByteOrderMSB = !m_BinaryDataByteOrderMSB; } bool MetaImage::ElementByteOrderFix(std::streamoff _quantity) { if (m_BinaryDataByteOrderMSB != MET_SystemByteOrderMSB()) { ElementByteOrderSwap(_quantity); return true; } return true; } bool MetaImage::ElementMinMaxValid() const { return m_ElementMinMaxValid; } void MetaImage::ElementMinMaxValid(bool _elementMinMaxValid) { m_ElementMinMaxValid = _elementMinMaxValid; } void MetaImage::ElementMinMaxRecalc() { double tf; if (m_ElementData == nullptr) { return; } ElementByteOrderFix(); MET_ValueToDouble(m_ElementType, m_ElementData, 0, &tf); m_ElementMin = tf; m_ElementMax = tf; for (size_t i = 1; i < static_cast(m_Quantity * m_ElementNumberOfChannels); i++) { MET_ValueToDouble(m_ElementType, m_ElementData, i, &tf); if (tf < m_ElementMin) { m_ElementMin = tf; } else if (tf > m_ElementMax) { m_ElementMax = tf; } } m_ElementMinMaxValid = true; } double MetaImage::ElementMin() const { return m_ElementMin; } void MetaImage::ElementMin(double _elementMin) { m_ElementMin = _elementMin; } double MetaImage::ElementMax() const { return m_ElementMax; } void MetaImage::ElementMax(double _elementMax) { m_ElementMax = _elementMax; } double MetaImage::ElementToIntensityFunctionSlope() const { return m_ElementToIntensityFunctionSlope; } void MetaImage::ElementToIntensityFunctionSlope(double _elementToIntensityFunctionSlope) { m_ElementToIntensityFunctionSlope = _elementToIntensityFunctionSlope; } double MetaImage::ElementToIntensityFunctionOffset() const { return m_ElementToIntensityFunctionOffset; } void MetaImage::ElementToIntensityFunctionOffset(double _elementOffset) { m_ElementToIntensityFunctionOffset = _elementOffset; } bool MetaImage::AutoFreeElementData() const { return m_AutoFreeElementData; } void MetaImage::AutoFreeElementData(bool _autoFreeElementData) { m_AutoFreeElementData = _autoFreeElementData; } const char * MetaImage::ElementDataFileName() const { return m_ElementDataFileName.c_str(); } void MetaImage::ElementDataFileName(const char * _elementDataFileName) { m_ElementDataFileName = _elementDataFileName; } void * MetaImage::ElementData() { return m_ElementData; } double MetaImage::ElementData(std::streamoff _i) const { double tf = 0; MET_ValueToDouble(m_ElementType, m_ElementData, _i, &tf); return tf; } bool MetaImage::ElementData(std::streamoff _i, double _v) { if (_i < m_Quantity) { MET_DoubleToValue(_v, m_ElementType, m_ElementData, _i); return true; } return false; } void MetaImage::ElementData(void * _elementData, bool _autoFreeElementData) { if (m_AutoFreeElementData) { delete[]static_cast(m_ElementData); } m_ElementData = _elementData; m_AutoFreeElementData = _autoFreeElementData; } bool MetaImage::ConvertElementDataTo(MET_ValueEnumType _elementType, double _toMin, double _toMax) { int eSize; MET_SizeOfType(_elementType, &eSize); void * newElementData = new char[static_cast(m_Quantity * m_ElementNumberOfChannels * eSize)]; ElementByteOrderFix(); if (!ElementMinMaxValid()) { ElementMinMaxRecalc(); } for (size_t i = 0; i < static_cast(m_Quantity * m_ElementNumberOfChannels); i++) { MET_ValueToValue( m_ElementType, m_ElementData, i, _elementType, newElementData, m_ElementMin, m_ElementMax, _toMin, _toMax); } if (m_AutoFreeElementData) { delete[]static_cast(m_ElementData); } m_ElementData = newElementData; m_ElementType = _elementType; m_ElementMinMaxValid = true; m_ElementMin = _toMin; m_ElementMax = _toMax; m_AutoFreeElementData = true; return true; } bool MetaImage::ConvertElementDataToIntensityData(MET_ValueEnumType _elementType) { ElementByteOrderFix(); if (!ElementMinMaxValid()) { ElementMinMaxRecalc(); } double toMin = m_ElementMin + m_ElementToIntensityFunctionOffset; double toMax = (m_ElementMax - m_ElementMin) * m_ElementToIntensityFunctionSlope + m_ElementMin; return ConvertElementDataTo(_elementType, toMin, toMax); } bool MetaImage::ConvertIntensityDataToElementData(MET_ValueEnumType _elementType) { ElementByteOrderFix(); if (!ElementMinMaxValid()) { ElementMinMaxRecalc(); } double toMin = m_ElementMin - m_ElementToIntensityFunctionOffset; double toMax = (m_ElementMax - m_ElementMin) / m_ElementToIntensityFunctionSlope + toMin; return ConvertElementDataTo(_elementType, toMin, toMax); } // return true if the file exists bool MetaImage::M_FileExists(const char * filename) { #ifdef _MSC_VER # define access _access #endif #ifndef R_OK # define R_OK 04 #endif if (access(filename, R_OK) != 0) { return false; } else { return true; } } bool MetaImage::FileIsFullPath(const char * in_name) { #if defined(_WIN32) || defined(__CYGWIN__) // On Windows, the name must be at least two characters long. if (strlen(in_name) < 2) { return false; } if (in_name[1] == ':') { return true; } if (in_name[0] == '\\') { return true; } #else // On UNIX, the name must be at least one character long. if (strlen(in_name) < 1) { return false; } #endif #if !defined(_WIN32) if (in_name[0] == '~') { return true; } #endif // On UNIX, the name must begin in a '/'. // On Windows, if the name begins in a '/', then it is a full // network path. if (in_name[0] == '/') { return true; } return false; } // Return the value of a tag std::string MetaImage::M_GetTagValue(const std::string & buffer, const char * tag) { size_t stringPos = buffer.find(tag); if (stringPos == std::string::npos) { return ""; } size_t pos2 = buffer.find('=', stringPos); if (pos2 == std::string::npos) { pos2 = buffer.find(':', stringPos); } if (pos2 == std::string::npos) { return ""; } // Get the element data filename std::string value; bool firstspace = true; size_t index = pos2 + 1; while (index < buffer.size() && buffer[index] != '\r' && buffer[index] != '\n') { if (buffer[index] != ' ') { firstspace = false; } if (!firstspace) { value += buffer[index]; } index++; } return value; } bool MetaImage::CanRead(const char * _headerName) { // First check the extension std::string fname = _headerName; if (fname.empty()) { return false; } bool extensionFound = false; std::string::size_type stringPos = fname.rfind(".mhd"); if ((stringPos != std::string::npos) && (stringPos == fname.length() - 4)) { extensionFound = true; } stringPos = fname.rfind(".mha"); if ((stringPos != std::string::npos) && (stringPos == fname.length() - 4)) { extensionFound = true; } if (!extensionFound) { return false; } // Now check the file content std::ifstream inputStream; openReadStream(inputStream, fname); if (inputStream.fail()) { return false; } char * buf = new char[8001]; inputStream.read(buf, 8000); auto fileSize = static_cast(inputStream.gcount()); buf[fileSize] = 0; std::string header(buf); header.resize(fileSize); delete[] buf; inputStream.close(); stringPos = header.find("NDims"); if (stringPos == std::string::npos) { return false; } std::string elementDataFileName = M_GetTagValue(header, "ElementDataFile"); return true; } bool MetaImage::Read(const char * _headerName, bool _readElements, void * _buffer) { MetaObject::M_Destroy(); Clear(); M_SetupReadFields(); if (_headerName != nullptr) { m_FileName = _headerName; } M_PrepareNewReadStream(); auto * tmpReadStream = new std::ifstream; openReadStream(*tmpReadStream, m_FileName); if (!tmpReadStream->is_open()) { delete tmpReadStream; return false; } if (!this->ReadStream(0, tmpReadStream, _readElements, _buffer)) { tmpReadStream->close(); delete tmpReadStream; return false; } tmpReadStream->close(); delete tmpReadStream; return true; } bool MetaImage::CanReadStream(std::ifstream * _stream) { if (!strncmp(MET_ReadType(*_stream).c_str(), "Image", 5)) { return true; } return false; } bool MetaImage::ReadStream(int _nDims, std::ifstream * _stream, bool _readElements, void * _buffer) { if (!MetaObject::ReadStream(_nDims, _stream)) { std::cerr << "MetaImage: Read: Cannot parse file" << std::endl; return false; } if (_readElements) { if (_buffer == nullptr) { InitializeEssential( m_NDims, m_DimSize, m_ElementSpacing, m_ElementType, m_ElementNumberOfChannels, nullptr, true); } else { InitializeEssential( m_NDims, m_DimSize, m_ElementSpacing, m_ElementType, m_ElementNumberOfChannels, _buffer, false); } int i; size_t j; bool usePath; std::string pathName; std::string fName; usePath = MET_GetFilePath(m_FileName, pathName); if ("Local" == m_ElementDataFileName || "LOCAL" == m_ElementDataFileName || "local" == m_ElementDataFileName) { M_ReadElements(_stream, m_ElementData, m_Quantity); } else if ("LIST" == m_ElementDataFileName.substr(0, 4)) { int fileImageDim = m_NDims - 1; int nWrds; char ** wrds; MET_StringToWordArray(m_ElementDataFileName.c_str(), &nWrds, &wrds); if (nWrds > 1) { fileImageDim = static_cast(atof(wrds[1])); } for (i = 0; i < nWrds; i++) { delete[] wrds[i]; } delete[] wrds; if ((fileImageDim == 0) || (fileImageDim > m_NDims)) { // if optional file dimension size is not given or is larger than // overall dimension then default to a size of m_NDims - 1. fileImageDim = m_NDims - 1; } std::string s; auto * readStreamTemp = new std::ifstream; int elementSize; MET_SizeOfType(m_ElementType, &elementSize); elementSize *= m_ElementNumberOfChannels; int totalFiles = 1; for (i = m_NDims; i > fileImageDim; i--) { totalFiles *= m_DimSize[i - 1]; } for (i = 0; i < totalFiles && !_stream->eof(); i++) { std::getline(*_stream, s); if (!_stream->eof()) { j = s.length() - 1; while (j > 0 && (isspace(s[j]) || !isprint(s[j]))) { s[j--] = '\0'; } if (usePath && !FileIsFullPath(s.c_str())) { fName = pathName + s; } else { fName = s; } openReadStream(*readStreamTemp, fName); if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: Read: cannot open slice" << std::endl; continue; } M_ReadElements(readStreamTemp, &((static_cast(m_ElementData))[i * m_SubQuantity[fileImageDim] * elementSize]), m_SubQuantity[fileImageDim]); readStreamTemp->close(); } } delete readStreamTemp; } else if (m_ElementDataFileName.find('%') != std::string::npos) { int elementSize; MET_SizeOfType(m_ElementType, &elementSize); elementSize *= m_ElementNumberOfChannels; int nWrds; char ** wrds; int minV = 1; int maxV = m_DimSize[m_NDims - 1]; int stepV = 1; std::string s; auto * readStreamTemp = new std::ifstream; MET_StringToWordArray(m_ElementDataFileName.c_str(), &nWrds, &wrds); if (nWrds >= 2) { minV = static_cast(atof(wrds[1])); maxV = minV + m_DimSize[m_NDims - 1] - 1; } if (nWrds >= 3) { maxV = static_cast(atof(wrds[2])); stepV = (maxV - minV) / (m_DimSize[m_NDims - 1]); } if (nWrds >= 4) { stepV = static_cast(atof(wrds[3])); } if (nWrds >= 5) { // In this case, the filename must have had spaces in the // name. The filename was parsed into multiple pieces by the // MET_StringToWordArray, which parses based on spaces. // Thus, we need to reconstruct the filename in this case. // The last three wrds must be numbers. If they are not, we give an error. for (i = nWrds - 3; i < nWrds; i++) { for (j = 0; j < strlen(wrds[i]); j++) { if (!isdigit(wrds[i][j])) { std::cerr << "MetaImage: Read: Last three arguments must be numbers!" << std::endl; continue; } } } stepV = static_cast(atof(wrds[nWrds - 1])); maxV = static_cast(atof(wrds[nWrds - 2])); minV = static_cast(atof(wrds[nWrds - 3])); for (i = 1; i < nWrds - 3; i++) { std::strncat(wrds[0], " ", METAIO_MAX_WORD_SIZE); std::strncat(wrds[0], wrds[i], METAIO_MAX_WORD_SIZE); } } // If the specified size of the third dimension is less than the size // specified by the regular expression, we should only read a volume with the specified // size. Otherwise, the code will crash when trying to fill m_ElementData more than it can hold. // Therefore, we modify maxV to ensure that the images spanned by minV:stepV:maxV are less than or equal // to the size in the last dimension. int numberOfImages = 1 + (maxV - minV) / stepV; if (numberOfImages > m_DimSize[m_NDims - 1]) { maxV = (m_DimSize[m_NDims - 1] - 1) * stepV + minV; } int cnt = 0; for (i = minV; i <= maxV; i += stepV) { s = string_format(wrds[0], i); if (usePath && !FileIsFullPath(s.c_str())) { fName = pathName + s; } else { fName = s; } openReadStream(*readStreamTemp, fName); if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: Read: cannot construct file" << std::endl; continue; } M_ReadElements(readStreamTemp, &((static_cast(m_ElementData))[cnt * m_SubQuantity[m_NDims - 1] * elementSize]), m_SubQuantity[m_NDims - 1]); cnt++; readStreamTemp->close(); } delete readStreamTemp; for (i = 0; i < nWrds; i++) { delete[] wrds[i]; } delete[] wrds; } else { if (usePath && !FileIsFullPath(m_ElementDataFileName.c_str())) { fName = pathName + m_ElementDataFileName; } else { fName = m_ElementDataFileName; } auto * readStreamTemp = new std::ifstream; const char * extensions[] = { "", ".gz", ".Z", nullptr }; for (unsigned ii = 0; extensions[ii] != nullptr; ii++) { std::string tempFName(fName); tempFName += extensions[ii]; openReadStream(*readStreamTemp, tempFName); if (readStreamTemp->is_open()) { if (ii > 0) { this->CompressedData(true); this->BinaryData(true); } break; } } if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: Read: Cannot open data file" << std::endl; if (m_ReadStream) { m_ReadStream->close(); } return false; } M_ReadElements(readStreamTemp, m_ElementData, m_Quantity); readStreamTemp->close(); delete readStreamTemp; } } return true; } bool MetaImage::Write(const char * _headName, const char * _dataName, bool _writeElements, const void * _constElementData, bool _append) { if (_headName != nullptr) { FileName(_headName); } bool userDataFileName = true; if (_dataName == nullptr && m_ElementDataFileName.empty()) { userDataFileName = false; int sPtr = 0; MET_GetFileSuffixPtr(m_FileName, &sPtr); if (!strcmp(&m_FileName[sPtr], "mha")) { ElementDataFileName("LOCAL"); } else { if (!_append) { MET_SetFileSuffix(m_FileName, "mhd"); } m_ElementDataFileName = m_FileName; if (m_CompressedData) { MET_SetFileSuffix(m_ElementDataFileName, "zraw"); } else { MET_SetFileSuffix(m_ElementDataFileName, "raw"); } } } else if (_dataName != nullptr) { userDataFileName = false; ElementDataFileName(_dataName); } // make sure suffix is valid if (!_append) { if (m_ElementDataFileName == "LOCAL") { MET_SetFileSuffix(m_FileName, "mha"); } else { MET_SetFileSuffix(m_FileName, "mhd"); } } std::string pathName; bool usePath = MET_GetFilePath(m_FileName, pathName); if (usePath) { std::string elementPathName; MET_GetFilePath(m_ElementDataFileName, elementPathName); if (pathName == elementPathName) { elementPathName = m_ElementDataFileName.substr(pathName.length()); m_ElementDataFileName = elementPathName; } } auto * tmpWriteStream = new std::ofstream; openWriteStream(*tmpWriteStream, m_FileName, _append); if (!tmpWriteStream->is_open()) { if (!userDataFileName) { ElementDataFileName(""); } delete tmpWriteStream; return false; } bool result = MetaImage::WriteStream(tmpWriteStream, _writeElements, _constElementData); if (!userDataFileName) { ElementDataFileName(""); } tmpWriteStream->close(); delete tmpWriteStream; return result; } bool MetaImage::WriteStream(std::ofstream * _stream, bool _writeElements, const void * _constElementData) { if (m_WriteStream != nullptr) { std::cerr << "MetaArray: WriteStream: two files open?" << std::endl; delete m_WriteStream; } m_WriteStream = _stream; unsigned char * compressedElementData = nullptr; if (m_BinaryData && m_CompressedData && m_ElementDataFileName.find('%') == std::string::npos) // compressed & !slice/file { int elementSize; MET_SizeOfType(m_ElementType, &elementSize); int elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; if (_constElementData == nullptr) { compressedElementData = MET_PerformCompression(static_cast(m_ElementData), m_Quantity * elementNumberOfBytes, &m_CompressedDataSize, m_CompressionLevel); } else { compressedElementData = MET_PerformCompression(static_cast(_constElementData), m_Quantity * elementNumberOfBytes, &m_CompressedDataSize, m_CompressionLevel); } } M_SetupWriteFields(); M_Write(); if (_writeElements) { if (m_BinaryData && m_CompressedData && m_ElementDataFileName.find('%') == std::string::npos) // compressed & !slice/file { M_WriteElements(m_WriteStream, compressedElementData, m_CompressedDataSize); delete[] compressedElementData; m_CompressedDataSize = 0; } else { if (_constElementData == nullptr) { M_WriteElements(m_WriteStream, m_ElementData, m_Quantity); } else { M_WriteElements(m_WriteStream, _constElementData, m_Quantity); } } } m_WriteStream = nullptr; return true; } /** Write a portion of an image */ bool MetaImage::WriteROI(int * _indexMin, int * _indexMax, const char * _headName, const char * _dataName, bool _writeElements, const void * _constElementData, bool _append) { if (_headName != nullptr) { FileName(_headName); } if (!_writeElements) { return false; } // Check if the file exists if (M_FileExists(_headName)) { char * elementData = const_cast(static_cast(_constElementData)); if (elementData == nullptr) { elementData = static_cast(m_ElementData); } if (elementData == nullptr) { std::cerr << "Element data is NULL" << std::endl; return false; } // Find the start of the data auto * readStream = new std::ifstream; readStream->open(m_FileName, std::ios::binary | std::ios::in); // File must be readable if (!MetaObject::ReadStream(m_NDims, readStream)) { std::cerr << "MetaImage: Read: Cannot parse file" << std::endl; delete readStream; return false; } // File must not be compressed if (m_CompressedData) { std::cerr << "MetaImage cannot insert ROI into a compressed file." << std::endl; readStream->close(); delete readStream; return false; } InitializeEssential(m_NDims, m_DimSize, m_ElementSpacing, m_ElementType, m_ElementNumberOfChannels, nullptr, false); // no memory allocation std::string filename = ElementDataFileName(); std::streampos dataPos = 0; // local file if (filename == "LOCAL") { filename = m_FileName; dataPos = readStream->tellg(); } else if (filename == "LIST" || strstr(filename.c_str(), "%")) { std::cerr << "MetaImage cannot insert ROI into a list of files." << std::endl; readStream->close(); delete readStream; return false; } readStream->close(); delete readStream; // Write the region if (!M_FileExists(filename.c_str())) { std::string pathName; MET_GetFilePath(_headName, pathName); filename = pathName + filename; } auto * tmpWriteStream = new std::ofstream; tmpWriteStream->open(filename.c_str(), std::ios::binary | std::ios::in | std::ios::out); if (!tmpWriteStream->is_open()) { std::cerr << "Cannot open ROI file: " << filename.c_str() << std::endl; delete tmpWriteStream; return false; } int elementSize; MET_SizeOfType(m_ElementType, &elementSize); int elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; // seek to the end and write one byte to allocate the entire file size std::streamoff seekoff = m_Quantity * elementNumberOfBytes; tmpWriteStream->seekp(0, std::ios::end); if (tmpWriteStream->tellp() != (dataPos + seekoff)) { seekoff = seekoff - 1; tmpWriteStream->seekp(dataPos + seekoff, std::ios::beg); const char zerobyte = 0; tmpWriteStream->write(&zerobyte, 1); } if (!elementData) { std::cerr << "Element data is NULL" << std::endl; delete tmpWriteStream; return false; } M_WriteElementsROI(tmpWriteStream, elementData, dataPos, _indexMin, _indexMax); tmpWriteStream->close(); delete tmpWriteStream; } else // the file doesn't exist { if (m_CompressedData) { std::cerr << "MetaImage cannot write an ROI using compression." << std::endl; return false; } // Get the data filename right... bool userDataFileName = true; if (_dataName == nullptr && m_ElementDataFileName.empty()) { userDataFileName = false; int sPtr = 0; MET_GetFileSuffixPtr(m_FileName, &sPtr); if (!strcmp(&m_FileName[sPtr], "mha")) { ElementDataFileName("LOCAL"); } else { if (!_append) { MET_SetFileSuffix(m_FileName, "mhd"); } m_ElementDataFileName = m_FileName; if (m_CompressedData) { MET_SetFileSuffix(m_ElementDataFileName, "zraw"); } else { MET_SetFileSuffix(m_ElementDataFileName, "raw"); } } } else if (_dataName != nullptr) { userDataFileName = false; ElementDataFileName(_dataName); } if (m_ElementDataFileName == "LIST" || m_ElementDataFileName.find('%') != std::string::npos) { std::cerr << "MetaImage cannot insert ROI into a list of files." << std::endl; return false; } // make sure the header suffix is valid, unless forcing to match an // existing file via the append bool argument. if (!_append) { if (m_ElementDataFileName == "LOCAL") { MET_SetFileSuffix(m_FileName, "mha"); } else { MET_SetFileSuffix(m_FileName, "mhd"); } } std::string pathName; bool usePath = MET_GetFilePath(m_FileName, pathName); if (usePath) { std::string elementPathName; MET_GetFilePath(m_ElementDataFileName, elementPathName); if (pathName == elementPathName) { elementPathName = m_ElementDataFileName.substr(pathName.length()); m_ElementDataFileName = elementPathName; } } auto * tmpWriteStream = new std::ofstream; openWriteStream(*tmpWriteStream, m_FileName, _append); if (!tmpWriteStream->is_open()) { if (!userDataFileName) { ElementDataFileName(""); } delete tmpWriteStream; return false; } // Write the ROI header file char * elementData = const_cast(static_cast(_constElementData)); if (elementData == nullptr) { elementData = static_cast(m_ElementData); } m_WriteStream = tmpWriteStream; M_SetupWriteFields(); M_Write(); std::streampos dataPos = m_WriteStream->tellp(); // If data is in a separate file, set dataPos and point to that file. // ( we've already verified the name isn't LIST and doesn't // contain % ) if (m_ElementDataFileName != "LOCAL") { m_WriteStream = nullptr; tmpWriteStream->close(); dataPos = 0; std::string dataFileName; if (usePath && !FileIsFullPath(m_ElementDataFileName.c_str())) { dataFileName = pathName + m_ElementDataFileName; } else { dataFileName = m_ElementDataFileName; } openWriteStream(*tmpWriteStream, dataFileName, _append); m_WriteStream = tmpWriteStream; } int elementSize; MET_SizeOfType(m_ElementType, &elementSize); int elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; // write the last byte in the file to allocate it std::streamoff seekoff = m_Quantity * elementNumberOfBytes; seekoff -= 1; m_WriteStream->seekp(seekoff, std::ios::cur); const char zerobyte = 0; m_WriteStream->write(&zerobyte, 1); M_WriteElementsROI(m_WriteStream, elementData, dataPos, _indexMin, _indexMax); m_WriteStream = nullptr; if (!userDataFileName) { ElementDataFileName(""); } tmpWriteStream->close(); delete tmpWriteStream; } return true; } bool MetaImage::M_WriteElementsROI(std::ofstream * _fstream, const void * _data, std::streampos _dataPos, const int * _indexMin, const int * _indexMax) { const char * data = static_cast(_data); int elementSize; MET_SizeOfType(m_ElementType, &elementSize); const int elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; // Write the IO region line by line int * currentIndex = new int[m_NDims]; for (int i = 0; i < m_NDims; i++) { currentIndex[i] = _indexMin[i]; } // Optimize the size of the buffer to written depending on the // region shape // This calculate the number of continuous bytes in the file // which can be written std::streamoff elementsToWrite = 1; int movingDirection = 0; do { elementsToWrite *= _indexMax[movingDirection] - _indexMin[movingDirection] + 1; ++movingDirection; } while (movingDirection < m_NDims && _indexMin[movingDirection - 1] == 0 && _indexMax[movingDirection - 1] == m_DimSize[movingDirection - 1] - 1); // write line by line bool done = false; while (!done) { // Seek to the right position std::streamoff seekoff = _dataPos; for (int i = 0; i < m_NDims; i++) { seekoff += m_SubQuantity[i] * currentIndex[i] * elementNumberOfBytes; } _fstream->seekp(seekoff, std::ios::beg); M_WriteElementData(_fstream, data, elementsToWrite); data += elementsToWrite * elementNumberOfBytes; // check if there is only one write needed if (movingDirection >= m_NDims) { break; } ++currentIndex[movingDirection]; // Check if we are still in the region for (int j = movingDirection; j < m_NDims; j++) { if (currentIndex[j] > _indexMax[j]) { if (j == m_NDims - 1) { done = true; break; } else { currentIndex[j] = _indexMin[j]; currentIndex[j + 1]++; } } } } // end writing loop delete[] currentIndex; return true; } bool MetaImage::Append(const char * _headName) { META_DEBUG_PRINT( "MetaImage: Append" ); return this->Write(_headName, nullptr, true, nullptr, true); } void MetaImage::M_ResetValues() { if (m_AutoFreeElementData && m_ElementData != nullptr) { delete[]static_cast(m_ElementData); } m_ElementData = nullptr; if (m_CompressionTable && m_CompressionTable->compressedStream) { inflateEnd(m_CompressionTable->compressedStream); delete m_CompressionTable->compressedStream; delete[] m_CompressionTable->buffer; m_CompressionTable->buffer = nullptr; } delete m_CompressionTable; m_CompressionTable = nullptr; MetaObject::M_Destroy(); } void MetaImage::M_SetupReadFields() { META_DEBUG_PRINT( "MetaImage: M_SetupReadFields" ); MetaObject::M_SetupReadFields(); MET_FieldRecordType * mF; int nDimsRecNum = MET_GetFieldRecordNumber("NDims", &m_Fields); mF = new MET_FieldRecordType; MET_InitReadField(mF, "DimSize", MET_INT_ARRAY, true, nDimsRecNum); mF->required = true; m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "HeaderSize", MET_INT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "Modality", MET_STRING, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ImagePosition", MET_FLOAT_ARRAY, false, nDimsRecNum); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "SequenceID", MET_INT_ARRAY, false, nDimsRecNum); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementMin", MET_FLOAT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementMax", MET_FLOAT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementNumberOfChannels", MET_INT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementSize", MET_FLOAT_ARRAY, false, nDimsRecNum); m_Fields.push_back(mF); mF = new MET_FieldRecordType; // Set but not used... MET_InitReadField(mF, "ElementNBits", MET_INT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; // Used by ConvertElementToIntensity funcs MET_InitReadField(mF, "ElementToIntensityFunctionSlope", MET_FLOAT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; // Used by ConvertElementToIntensity funcs MET_InitReadField(mF, "ElementToIntensityFunctionOffset", MET_FLOAT, false); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementType", MET_STRING, true); mF->required = true; m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitReadField(mF, "ElementDataFile", MET_STRING, true); mF->required = true; mF->terminateRead = true; m_Fields.push_back(mF); } void MetaImage::M_SetupWriteFields() { MetaObject::M_SetupWriteFields(); MET_FieldRecordType * mF; mF = new MET_FieldRecordType; MET_InitWriteField(mF, "DimSize", MET_INT_ARRAY, static_cast(m_NDims), m_DimSize); m_Fields.push_back(mF); char s[22]; if (m_HeaderSize > 0 || m_HeaderSize == -1) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "HeaderSize", MET_INT); m_Fields.push_back(mF); } int i; if (m_Modality != MET_MOD_UNKNOWN) { mF = new MET_FieldRecordType; strcpy(s, MET_ValueTypeName[m_Modality]); MET_InitWriteField(mF, "Modality", MET_STRING, strlen(s), s); m_Fields.push_back(mF); } i = MET_GetFieldRecordNumber("AnatomicalOrientation", &m_Fields); if (i < 0) { const char * str = AnatomicalOrientationAcronym(); mF = new MET_FieldRecordType; MET_InitWriteField(mF, "AnatomicalOrientation", MET_STRING, strlen(str), str); m_Fields.push_back(mF); } bool valid = false; for (i = 0; i < 4; i++) { if (m_SequenceID[i] != 0) { valid = true; break; } } if (valid) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "SequenceID", MET_FLOAT_ARRAY, static_cast(m_NDims), m_SequenceID); m_Fields.push_back(mF); } if (m_ElementMinMaxValid) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementMin", MET_FLOAT, m_ElementMin); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementMax", MET_FLOAT, m_ElementMax); m_Fields.push_back(mF); } if (m_ElementNumberOfChannels > 1) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementNumberOfChannels", MET_INT, m_ElementNumberOfChannels); m_Fields.push_back(mF); } if (m_ElementSizeValid) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementSize", MET_FLOAT_ARRAY, static_cast(m_NDims), m_ElementSize); m_Fields.push_back(mF); } if (m_ElementToIntensityFunctionSlope != 1 || m_ElementToIntensityFunctionOffset != 0) { mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementToIntensityFunctionSlope", MET_FLOAT, m_ElementToIntensityFunctionSlope); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementToIntensityFunctionOffset", MET_FLOAT, m_ElementToIntensityFunctionOffset); m_Fields.push_back(mF); } mF = new MET_FieldRecordType; MET_TypeToString(m_ElementType, s); MET_InitWriteField(mF, "ElementType", MET_STRING, strlen(s), s); m_Fields.push_back(mF); mF = new MET_FieldRecordType; MET_InitWriteField(mF, "ElementDataFile", MET_STRING, m_ElementDataFileName.length(), m_ElementDataFileName.c_str()); mF->terminateRead = true; m_Fields.push_back(mF); } bool MetaImage::M_Read() { META_DEBUG_PRINT( "MetaImage: M_Read: Loading Header" ); if (!MetaObject::M_Read()) { std::cerr << "MetaImage: M_Read: Error parsing file" << std::endl; return false; } META_DEBUG_PRINT( "MetaImage: M_Read: Parsing Header" ); MET_FieldRecordType * mF; META_DEBUG_PRINT( "metaImage: M_Read: elementSpacing[" << 0 << "] = " << m_ElementSpacing[0] ); mF = MET_GetFieldRecord("DimSize", &m_Fields); if (mF && mF->defined) { int i; for (i = 0; i < m_NDims; i++) { m_DimSize[i] = static_cast(mF->value[i]); } } mF = MET_GetFieldRecord("HeaderSize", &m_Fields); if (mF && mF->defined) { m_HeaderSize = static_cast(mF->value[0]); } mF = MET_GetFieldRecord("Modality", &m_Fields); if (mF && mF->defined) { std::string temp(reinterpret_cast(mF->value)); MET_StringToImageModality(temp, &m_Modality); } mF = MET_GetFieldRecord("SequenceID", &m_Fields); if (mF && mF->defined) { int i; for (i = 0; i < m_NDims; i++) { m_SequenceID[i] = static_cast(mF->value[i]); } } mF = MET_GetFieldRecord("ImagePosition", &m_Fields); if (mF && mF->defined) { int i; for (i = 0; i < m_NDims; i++) { m_Offset[i] = mF->value[i]; } } mF = MET_GetFieldRecord("ElementMin", &m_Fields); if (mF && mF->defined) { m_ElementMin = mF->value[0]; } mF = MET_GetFieldRecord("ElementMax", &m_Fields); if (mF && mF->defined) { m_ElementMax = mF->value[0]; } mF = MET_GetFieldRecord("ElementNumberOfChannels", &m_Fields); if (mF && mF->defined) { m_ElementNumberOfChannels = static_cast(mF->value[0]); } mF = MET_GetFieldRecord("ElementSize", &m_Fields); if (mF && mF->defined) { m_ElementSizeValid = true; int i; for (i = 0; i < m_NDims; i++) { m_ElementSize[i] = mF->value[i]; } mF = MET_GetFieldRecord("ElementSpacing", &m_Fields); if (mF && !mF->defined) { for (i = 0; i < m_NDims; i++) { m_ElementSpacing[i] = m_ElementSize[i]; } } } else { int i; m_ElementSizeValid = false; for (i = 0; i < m_NDims; i++) { m_ElementSize[i] = m_ElementSpacing[i]; } } m_ElementToIntensityFunctionSlope = 1; m_ElementToIntensityFunctionOffset = 0; mF = MET_GetFieldRecord("ElementToIntensityFunctionSlope", &m_Fields); if (mF && mF->defined) { m_ElementToIntensityFunctionSlope = mF->value[0]; } mF = MET_GetFieldRecord("ElementToIntensityFunctionOffset", &m_Fields); if (mF && mF->defined) { m_ElementToIntensityFunctionOffset = mF->value[0]; } mF = MET_GetFieldRecord("ElementType", &m_Fields); if (mF && mF->defined) { MET_StringToType(reinterpret_cast(mF->value), &m_ElementType); } mF = MET_GetFieldRecord("ElementDataFile", &m_Fields); if (mF && mF->defined) { m_ElementDataFileName = reinterpret_cast(mF->value); } return true; } bool MetaImage::M_ReadElements(std::ifstream * _fstream, void * _data, std::streamoff _dataQuantity) { META_DEBUG_PRINT( "MetaImage: M_ReadElements" ); if (m_HeaderSize > 0) { _fstream->seekg(m_HeaderSize, std::ios::beg); if (!_fstream->good()) { std::cerr << "MetaImage: Read: header not read correctly" << std::endl; return false; } } int elementSize; MET_SizeOfType(m_ElementType, &elementSize); std::streamoff readSize = _dataQuantity * m_ElementNumberOfChannels * elementSize; META_DEBUG_PRINT( "MetaImage: M_ReadElements: ReadSize = " << readSize ); if (m_HeaderSize == -1) { META_DEBUG_PRINT( "MetaImage: M_ReadElements: Skipping header" ); _fstream->seekg(-readSize, std::ios::end); } // If compressed we inflate if (m_BinaryData && m_CompressedData) { // if m_CompressedDataSize is not defined we assume the size of the // file is the size of the compressed data bool compressedDataDeterminedFromFile = false; if (m_CompressedDataSize == 0) { compressedDataDeterminedFromFile = true; _fstream->seekg(0, std::ios::end); m_CompressedDataSize = _fstream->tellg(); _fstream->seekg(0, std::ios::beg); } auto * compr = new unsigned char[static_cast(m_CompressedDataSize)]; M_ReadElementData(_fstream, compr, m_CompressedDataSize); MET_PerformUncompression(compr, m_CompressedDataSize, static_cast(_data), readSize); if (compressedDataDeterminedFromFile) { m_CompressedDataSize = 0; } delete[] compr; } else // if not compressed { if (!m_BinaryData) { M_ReadElementData(_fstream, _data, _dataQuantity); } else { if (!M_ReadElementData(_fstream, _data, _dataQuantity)) { return false; } } } return true; } bool MetaImage::M_WriteElements(std::ofstream * _fstream, const void * _data, std::streamoff _dataQuantity) { if (m_ElementDataFileName == "LOCAL") { MetaImage::M_WriteElementData(_fstream, _data, _dataQuantity); } else // write the data in a separate file { std::string dataFileName; std::string pathName; bool usePath = MET_GetFilePath(m_FileName, pathName); if (usePath && !FileIsFullPath(m_ElementDataFileName.c_str())) { dataFileName = pathName + m_ElementDataFileName; } else { dataFileName = m_ElementDataFileName; } if (dataFileName.find('%') != std::string::npos) // write slice by slice { int i; std::string fName; int elementSize; MET_SizeOfType(m_ElementType, &elementSize); std::streamoff elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; std::streamoff sliceNumberOfBytes = m_SubQuantity[m_NDims - 1] * elementNumberOfBytes; auto * writeStreamTemp = new std::ofstream; for (i = 1; i <= m_DimSize[m_NDims - 1]; i++) { fName = string_format(dataFileName, i); openWriteStream(*writeStreamTemp, fName, false); if (!m_CompressedData) { // BUG? This looks wrong to me as the third parameter should // contain the number of elements/quantity, not number of bytes -BCL MetaImage::M_WriteElementData( writeStreamTemp, &((static_cast(_data))[(i - 1) * sliceNumberOfBytes]), sliceNumberOfBytes); } else { unsigned char * compressedData = nullptr; std::streamoff compressedDataSize = 0; // Compress the data slice by slice compressedData = MET_PerformCompression(&((static_cast(_data))[(i - 1) * sliceNumberOfBytes]), sliceNumberOfBytes, &compressedDataSize, m_CompressionLevel); // Write the compressed data MetaImage::M_WriteElementData(writeStreamTemp, compressedData, compressedDataSize); delete[] compressedData; } writeStreamTemp->close(); } delete writeStreamTemp; } else // write the image in one unique other file { auto * writeStreamTemp = new std::ofstream; openWriteStream(*writeStreamTemp, dataFileName, false); MetaImage::M_WriteElementData(writeStreamTemp, _data, _dataQuantity); writeStreamTemp->close(); delete writeStreamTemp; } } return true; } bool MetaImage::M_WriteElementData(std::ofstream * _fstream, const void * _data, std::streamoff _dataQuantity) { if (!m_BinaryData) { double tf; for (std::streamoff i = 0; i < _dataQuantity; i++) { MET_ValueToDouble(m_ElementType, _data, i, &tf); if ((i + 1) / 10 == (i + 1.0) / 10.0) { (*_fstream) << tf << std::endl; } else { (*_fstream) << tf << " "; } } } else { if (m_CompressedData) { // the data is written in writes no bigger then MaxIOChunk std::streamoff bytesRemaining = _dataQuantity; while (bytesRemaining) { std::streamoff chunkToWrite = bytesRemaining > MaxIOChunk ? MaxIOChunk : bytesRemaining; _fstream->write(static_cast(_data), static_cast(chunkToWrite)); _data = static_cast(_data) + chunkToWrite; // <- Note: data is changed bytesRemaining -= chunkToWrite; } } else { int elementSize; MET_SizeOfType(m_ElementType, &elementSize); std::streamoff elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; // the data is written in writes no bigger then MaxIOChunk std::streamoff bytesRemaining = _dataQuantity * elementNumberOfBytes; while (bytesRemaining) { std::streamoff chunkToWrite = bytesRemaining > MaxIOChunk ? MaxIOChunk : bytesRemaining; _fstream->write(static_cast(_data), static_cast(chunkToWrite)); _data = static_cast(_data) + chunkToWrite; // <- Note: _data is changed bytesRemaining -= chunkToWrite; } } } // check if the io stream did not fail in the process of writing if (_fstream->fail()) { std::cerr << "MetaImage: M_WriteElementsData: file stream is fail after write" << std::endl; return false; } return true; } /** Streaming related functions */ bool MetaImage::ReadROI(int * _indexMin, int * _indexMax, const char * _headerName, bool _readElements, void * _buffer, unsigned int subSamplingFactor) { MetaObject::M_Destroy(); Clear(); M_SetupReadFields(); if (_headerName != nullptr) { m_FileName = _headerName; } M_PrepareNewReadStream(); auto * tmpReadStream = new std::ifstream; openReadStream(*tmpReadStream, m_FileName); if (!tmpReadStream->is_open()) { delete tmpReadStream; return false; } if (!this->ReadROIStream(_indexMin, _indexMax, 0, tmpReadStream, _readElements, _buffer, subSamplingFactor)) { tmpReadStream->close(); delete tmpReadStream; return false; } tmpReadStream->close(); delete tmpReadStream; return true; } /** Read the ROI Stream */ bool MetaImage::ReadROIStream(int * _indexMin, int * _indexMax, int _nDims, std::ifstream * _stream, bool _readElements, void * _buffer, unsigned int subSamplingFactor) { if (!MetaObject::ReadStream(_nDims, _stream)) { std::cerr << "MetaImage: Read: Cannot parse file" << std::endl; return false; } if (_readElements) { if (_buffer == nullptr) { InitializeEssential( m_NDims, m_DimSize, m_ElementSpacing, m_ElementType, m_ElementNumberOfChannels, nullptr, true); } else { InitializeEssential( m_NDims, m_DimSize, m_ElementSpacing, m_ElementType, m_ElementNumberOfChannels, _buffer, false); } // Streaming related. We need to update some of the fields std::streamoff quantity = 1; int i; size_t j; for (i = 0; i < m_NDims; i++) { quantity *= (_indexMax[i] - _indexMin[i] + 1); } bool usePath; std::string pathName; std::string fName; usePath = MET_GetFilePath(m_FileName, pathName); if ("Local" == m_ElementDataFileName || "LOCAL" == m_ElementDataFileName || "local" == m_ElementDataFileName) { M_ReadElementsROI(_stream, m_ElementData, quantity, _indexMin, _indexMax, subSamplingFactor, m_Quantity); } else if ("LIST" == m_ElementDataFileName.substr(0, 4)) { int nWrds; char ** wrds; MET_StringToWordArray(m_ElementDataFileName.c_str(), &nWrds, &wrds); for (i = 0; i < nWrds; i++) { delete[] wrds[i]; } delete[] wrds; char s[1024]; auto * readStreamTemp = new std::ifstream; int elementSize; MET_SizeOfType(m_ElementType, &elementSize); elementSize *= m_ElementNumberOfChannels; int minV = _indexMin[m_NDims - 1]; int maxV = minV + (_indexMax[m_NDims - 1] - _indexMin[m_NDims - 1]); int cnt = 0; // Read the previous lines for (i = 0; i < minV; i++) { _stream->getline(s, 1024); } for (i = minV; i <= maxV; i += 1) { _stream->getline(s, 1024); if (!_stream->eof()) { j = strlen(s) - 1; while (j > 0 && (isspace(s[j]) || !isprint(s[j]))) { s[j--] = '\0'; } if (usePath && !FileIsFullPath(s)) { fName = pathName + s; } else { fName = s; } openReadStream(*readStreamTemp, fName); if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: Read: cannot open slice" << std::endl; continue; } // read only one slice int * indexMin = new int[m_NDims]; int * indexMax = new int[m_NDims]; quantity = 1; for (int k = 0; k < m_NDims - 1; k++) { quantity *= _indexMax[k] - _indexMin[k] + 1; indexMin[k] = _indexMin[k]; indexMax[k] = _indexMax[k]; } indexMin[m_NDims - 1] = 0; indexMax[m_NDims - 1] = 0; M_ReadElementsROI(readStreamTemp, &((static_cast(m_ElementData))[cnt * quantity * elementSize]), quantity, indexMin, indexMax, subSamplingFactor, m_SubQuantity[m_NDims - 1]); cnt++; readStreamTemp->close(); } } delete readStreamTemp; } else if (m_ElementDataFileName.find('%') != std::string::npos) { int elementSize; MET_SizeOfType(m_ElementType, &elementSize); elementSize *= m_ElementNumberOfChannels; int nWrds; char ** wrds; int minV = 1; int maxV; int stepV = 1; std::string s; auto * readStreamTemp = new std::ifstream; MET_StringToWordArray(m_ElementDataFileName.c_str(), &nWrds, &wrds); if (nWrds >= 2) { minV = static_cast(atof(wrds[1])); } if (nWrds >= 3) { maxV = static_cast(atof(wrds[2])); stepV = (maxV - minV) / (m_DimSize[m_NDims - 1]); } if (nWrds >= 4) { stepV = static_cast(atof(wrds[3])); } if (nWrds >= 5) { // In this case, the filename must have had spaces in the // name. The filename was parsed into multiple pieces by the // MET_StringToWordArray, which parses based on spaces. // Thus, we need to reconstruct the filename in this case. // The last three wrds must be numbers. If they are not, we give an error. for (i = nWrds - 3; i < nWrds; i++) { for (j = 0; j < strlen(wrds[i]); j++) { if (!isdigit(wrds[i][j])) { std::cerr << "MetaImage: Read: Last three arguments must be numbers!" << std::endl; continue; } } } stepV = static_cast(atof(wrds[nWrds - 1])); minV = static_cast(atof(wrds[nWrds - 3])); for (i = 1; i < nWrds - 3; i++) { std::strncat(wrds[0], " ", METAIO_MAX_WORD_SIZE); std::strncat(wrds[0], wrds[i], METAIO_MAX_WORD_SIZE); } } int cnt = 0; // Uses the _indexMin and _indexMax minV += _indexMin[m_NDims - 1]; maxV = minV + (_indexMax[m_NDims - 1] - _indexMin[m_NDims - 1]) * stepV; for (i = minV; i <= maxV; i += stepV) { s = string_format(wrds[0], i); if (usePath && !FileIsFullPath(s.c_str())) { fName = pathName + s; } else { fName = s; } openReadStream(*readStreamTemp, fName); if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: Read: cannot construct file" << std::endl; continue; } // read only one slice int * indexMin = new int[m_NDims]; int * indexMax = new int[m_NDims]; quantity = 1; for (int k = 0; k < m_NDims - 1; k++) { quantity *= _indexMax[k] - _indexMin[k] + 1; indexMin[k] = _indexMin[k]; indexMax[k] = _indexMax[k]; } indexMin[m_NDims - 1] = 0; indexMax[m_NDims - 1] = 0; M_ReadElementsROI(readStreamTemp, &((static_cast(m_ElementData))[cnt * quantity * elementSize]), quantity, indexMin, indexMax, subSamplingFactor, m_SubQuantity[m_NDims - 1]); cnt++; delete[] indexMin; delete[] indexMax; readStreamTemp->close(); } for (i = 0; i < nWrds; i++) { delete[] wrds[i]; } delete[] wrds; delete readStreamTemp; } else { if (usePath && !FileIsFullPath(m_ElementDataFileName.c_str())) { fName = pathName + m_ElementDataFileName; } else { fName = m_ElementDataFileName; } auto * readStreamTemp = new std::ifstream; const char * extensions[] = { "", ".gz", ".Z", nullptr }; for (unsigned ii = 0; extensions[ii] != nullptr; ii++) { std::string tempFName(fName); tempFName += extensions[ii]; openReadStream(*readStreamTemp, tempFName); if (readStreamTemp->is_open()) { if (ii > 0) { this->CompressedData(true); this->BinaryData(true); } break; } } if (!readStreamTemp->is_open()) { std::cerr << "MetaImage: ReadROI: Cannot open data file" << std::endl; if (m_ReadStream) { m_ReadStream->close(); } delete readStreamTemp; return false; } M_ReadElementsROI(readStreamTemp, m_ElementData, quantity, _indexMin, _indexMax, subSamplingFactor, m_Quantity); readStreamTemp->close(); delete readStreamTemp; } } return true; } /** Read an ROI */ bool MetaImage::M_ReadElementsROI(std::ifstream * _fstream, void * _data, std::streamoff _dataQuantity, int * _indexMin, int * _indexMax, unsigned int subSamplingFactor, std::streamoff _totalDataQuantity) { if (_totalDataQuantity == 0) { _totalDataQuantity = _dataQuantity; } for (int dim = 0; dim < m_NDims; dim++) { _indexMin[dim] *= subSamplingFactor; _indexMax[dim] *= subSamplingFactor; } META_DEBUG_PRINT( "MetaImage: M_ReadElementsROI" ); if (m_HeaderSize > 0) { _fstream->seekg(m_HeaderSize, std::ios::beg); if (!_fstream->good()) { std::cerr << "MetaImage: M_ReadElementsROI: header not read correctly" << std::endl; return false; } } int elementSize; MET_SizeOfType(m_ElementType, &elementSize); std::streamoff readSize = _dataQuantity * m_ElementNumberOfChannels * elementSize; int elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; META_DEBUG_PRINT( "MetaImage: M_ReadElementsROI: ReadSize = " << readSize ); if (m_HeaderSize == -1) { META_DEBUG_PRINT( "MetaImage: M_ReadElementsROI: Skipping header" ); std::streamoff headSize = _totalDataQuantity * m_ElementNumberOfChannels * elementSize; _fstream->seekg(-headSize, std::ios::end); } std::streampos dataPos = _fstream->tellg(); std::streamoff i; // If compressed we inflate if (m_BinaryData && m_CompressedData) { // if m_CompressedDataSize is not defined we assume the size of the // file is the size of the compressed data if (m_CompressedDataSize == 0) { _fstream->seekg(0, std::ios::end); m_CompressedDataSize = _fstream->tellg(); _fstream->seekg(0, std::ios::beg); } auto * data = static_cast(_data); // Initialize the index int * currentIndex = new int[m_NDims]; for (i = 0; i < m_NDims; i++) { currentIndex[i] = _indexMin[i]; } // Optimize the size of the buffer to read depending on the // region shape // This calculate the number of continuous bytes in the file // which can be read std::streamoff elementsToRead = 1; int movingDirection = 0; do { elementsToRead *= _indexMax[movingDirection] - _indexMin[movingDirection] + 1; ++movingDirection; } while (subSamplingFactor == 1 && movingDirection < m_NDims && _indexMin[movingDirection - 1] == 0 && _indexMax[movingDirection - 1] == m_DimSize[movingDirection - 1] - 1); std::streamoff bytesToRead = elementsToRead * elementNumberOfBytes; std::streamoff gc = 0; bool done = false; while (!done) { // Seek to the right position std::streamoff seekoff = 0; for (i = 0; i < m_NDims; i++) { seekoff += m_SubQuantity[i] * elementNumberOfBytes * currentIndex[i]; } if (subSamplingFactor > 1) { auto * subdata = new unsigned char[static_cast(bytesToRead)]; std::streamoff rOff = MET_UncompressStream(_fstream, seekoff, subdata, bytesToRead, m_CompressedDataSize, m_CompressionTable); // if there was a read error if (rOff == -1) { delete[] currentIndex; return false; } for (std::streamoff p = 0; p < bytesToRead; p += (subSamplingFactor * m_ElementNumberOfChannels * elementSize)) { for (int s = 0; s < m_ElementNumberOfChannels * elementSize; s++) { *data = subdata[p + s]; gc++; data++; } } delete[] subdata; } else { std::streamoff rOff = MET_UncompressStream(_fstream, seekoff, data, bytesToRead, m_CompressedDataSize, m_CompressionTable); if (rOff == -1) { delete[] currentIndex; return false; } data += bytesToRead; gc += rOff; } if (gc == readSize) { break; } // Go forward if (m_NDims == 1) { break; } currentIndex[movingDirection] += subSamplingFactor; // Check if we are still in the region for (i = 1; i < m_NDims; i++) { if (currentIndex[i] > _indexMax[i]) { if (i == m_NDims - 1) { done = true; break; } else { currentIndex[i] = _indexMin[i]; currentIndex[i + 1] += subSamplingFactor; } } } } if (gc != readSize) { std::cerr << "MetaImage: M_ReadElementsROI: data not read completely" << std::endl; std::cerr << " ideal = " << readSize << " : actual = " << gc << std::endl; delete[] currentIndex; return false; } delete[] currentIndex; } else // if not compressed { double tf = 0; MET_SizeOfType(m_ElementType, &elementSize); char * data = static_cast(_data); // Initialize the index int * currentIndex = new int[m_NDims]; for (i = 0; i < m_NDims; i++) { currentIndex[i] = _indexMin[i]; } // Optimize the size of the buffer to read depending on the // region shape // This calculate the number of continuous bytes in the file // which can be read std::streamoff elementsToRead = 1; int movingDirection = 0; do { elementsToRead *= _indexMax[movingDirection] - _indexMin[movingDirection] + 1; ++movingDirection; } while (subSamplingFactor == 1 && movingDirection < m_NDims && _indexMin[movingDirection - 1] == 0 && _indexMax[movingDirection - 1] == m_DimSize[movingDirection - 1] - 1); // readLine *= m_ElementNumberOfChannels*elementSize; std::streamoff gc = 0; bool done = false; while (!done) { // Seek to the right position std::streamoff seekoff = 0; for (i = 0; i < m_NDims; i++) { seekoff += m_SubQuantity[i] * m_ElementNumberOfChannels * elementSize * currentIndex[i]; } _fstream->seekg(dataPos + seekoff, std::ios::beg); // Read a line if (subSamplingFactor > 1) { if (!m_BinaryData) // Not binary data { for (i = 0; i < elementsToRead; i += subSamplingFactor) { *_fstream >> tf; MET_DoubleToValue(tf, m_ElementType, _data, i); for (unsigned int j = 0; j < subSamplingFactor; j++) { _fstream->get(); } } } else // Binary data { char * subdata = new char[static_cast(elementsToRead * elementNumberOfBytes)]; _fstream->read(subdata, size_t(elementsToRead * elementNumberOfBytes)); for (std::streamoff p = 0; p < elementsToRead * elementNumberOfBytes; p += (subSamplingFactor * elementNumberOfBytes)) { for (int s = 0; s < elementNumberOfBytes; s++) { *data = subdata[p + s]; gc++; data++; } } delete[] subdata; } } else { if (!m_BinaryData) // Not binary data { // anyone using ROI reading of ASCII?? // does this work? what about incrementing data? // what about data sizes and random access of file? std::streamoff blockSize = elementsToRead * m_ElementNumberOfChannels * elementSize; M_ReadElementData(_fstream, data, static_cast(blockSize)); gc += blockSize; } else // binary data { M_ReadElementData(_fstream, data, elementsToRead); gc += elementsToRead * elementNumberOfBytes; data += elementsToRead * elementNumberOfBytes; } } // I don't think this check is really needed -BCL if (gc == readSize) { break; } // check if there is only one read needed if (movingDirection >= m_NDims) { break; } // Go forward currentIndex[movingDirection] += subSamplingFactor; // Check if we are still in the region for (i = movingDirection; i < m_NDims; i++) { if (currentIndex[i] > _indexMax[i]) { if (i == m_NDims - 1) { done = true; break; } else { currentIndex[i] = _indexMin[i]; currentIndex[i + 1] += subSamplingFactor; } } } } delete[] currentIndex; if (gc != readSize) { std::cerr << "MetaImage: M_ReadElementsROI: data not read completely" << std::endl; std::cerr << " ideal = " << readSize << " : actual = " << gc << std::endl; return false; } } return true; } bool MetaImage::M_ReadElementData(std::ifstream * _fstream, void * _data, std::streamoff _dataQuantity) { // NOTE: this method is different from WriteElementData std::streamoff gc = 0; if (!m_BinaryData) { double tf = 0; for (int i = 0; i < _dataQuantity; i++) { *_fstream >> tf; MET_DoubleToValue(tf, m_ElementType, _data, i); _fstream->get(); ++gc; } } else { if (m_CompressedData) { // the data is read with calls no bigger then MaxIOChunk std::streamoff bytesRemaining = _dataQuantity; while (bytesRemaining) { std::streamoff chunkToRead = bytesRemaining > MaxIOChunk ? MaxIOChunk : bytesRemaining; _fstream->read(static_cast(_data), static_cast(chunkToRead)); _data = static_cast(_data) + chunkToRead; bytesRemaining -= chunkToRead; std::streamsize numberOfBytesRead = _fstream->gcount(); gc += numberOfBytesRead; } } else { int elementSize; MET_SizeOfType(m_ElementType, &elementSize); std::streamoff elementNumberOfBytes = elementSize * m_ElementNumberOfChannels; // the data is read with calls no bigger than MaxIOChunk std::streamoff bytesRemaining = _dataQuantity * elementNumberOfBytes; while (bytesRemaining) { std::streamoff chunkToRead = bytesRemaining > MaxIOChunk ? MaxIOChunk : bytesRemaining; _fstream->read(static_cast(_data), static_cast(chunkToRead)); _data = static_cast(_data) + chunkToRead; bytesRemaining -= chunkToRead; std::streamsize numberOfBytesRead = _fstream->gcount(); gc += numberOfBytesRead; } // convert to number of bytes so that it'll match gc's units _dataQuantity *= elementNumberOfBytes; } } // check that we actually read the correct number of bytes if (gc != _dataQuantity) { std::cerr << "MetaImage: M_ReadElementsData: data not read completely" << std::endl; std::cerr << " ideal = " << _dataQuantity << " : actual = " << gc << std::endl; return false; } // check if the io stream did not fail in the process of reading if (_fstream->fail()) { std::cerr << "MetaImage: M_ReadElementsData: file stream is fail after read" << std::endl; return false; } return true; } #if (METAIO_USE_NAMESPACE) } #endif