<commit_before>/*=========================================================================

  Program:   MetaIO
  Module:    metaImage.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "metaImage.h"

#include <stdio.h>
#include <ctype.h>
#include <string>
#include <string.h> // for memcpy
#include <stdlib.h> // for atoi
#include <math.h>

#if defined (__BORLANDC__) && (__BORLANDC__ >= 0x0580)
#include <mem.h>
#endif

#if defined(_WIN32)
# include <io.h>
#endif

// support for access
#ifndef _WIN32
#include <limits.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <pwd.h>
#include <termios.h>
#include <signal.h>    /* sigprocmask */
#endif

#if (METAIO_USE_NAMESPACE)
namespace METAIO_NAMESPACE {
#endif


//
// MetaImage Constructors
//
MetaImage::
MetaImage()
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();
  }

//
MetaImage::
MetaImage(const char *_headerName)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  Read(_headerName);
  }

//
MetaImage::
MetaImage(MetaImage *_im)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  InitializeEssential(_im->NDims(),
                      _im->DimSize(),
                      _im->ElementSpacing(),
                      _im->ElementType(),
                      _im->ElementNumberOfChannels(),
                      _im->ElementData(),
                      false);
  CopyInfo(_im);
  }

//
MetaImage::
MetaImage(int _nDims,
          const int * _dimSize,
          const float * _elementSpacing,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels,
          void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->buffer = NULL;
  m_CompressionTable->compressedStream = NULL;
  Clear();

  if(_elementData == NULL)
    {
    InitializeEssential(_nDims,
                        _dimSize,
                        _elementSpacing,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL, true);
    }
  else
    {
    InitializeEssential(_nDims,
                        _dimSize,
                        _elementSpacing,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData, false);
    }

  }

//
MetaImage::
MetaImage(int _x, int _y,
          float _elementSpacingX, float _elementSpacingY,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels, void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  int ds[2];
  ds[0] = _x;
  ds[1] = _y;

  float es[2];
  es[0] = _elementSpacingX;
  es[1] = _elementSpacingY;

  if(_elementData == NULL)
    {
    InitializeEssential(2,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL,
                        true);
    }
  else
    {
    InitializeEssential(2,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData,
                        false);
    }
  }

//
MetaImage::
MetaImage(int _x, int _y, int _z,
          float _elementSpacingX,
          float _elementSpacingY,
          float _elementSpacingZ,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels,
          void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  int ds[3];
  ds[0] = _x;
  ds[1] = _y;
  ds[2] = _z;

  float es[3];
  es[0] = _elementSpacingX;
  es[1] = _elementSpacingY;
  es[2] = _elementSpacingZ;

  if(_elementData == NULL)
    {
    InitializeEssential(3,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL,
                        true);
    }
  else
    {
    InitializeEssential(3,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData,
                        false);
    }
  }

//
MetaImage::
~MetaImage()
  {
  M_Destroy();
  }

//
void MetaImage::
PrintInfo() const
  {
  int i;

  MetaObject::PrintInfo();

  char s[255];
  MET_ImageModalityToString(m_Modality, s);
  METAIO_STREAM::cout << "Modality = " << s << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "DimSize = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_DimSize[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "SubQuantity = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_SubQuantity[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "Quantity = " << m_Quantity << METAIO_STREAM::endl;


  METAIO_STREAM::cout << "HeaderSize = " << m_HeaderSize << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "SequenceID = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_SequenceID[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementSizeValid = " << (int)m_ElementSizeValid
            << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "ElementSize = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_ElementSize[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  char str[255];
  MET_TypeToString(m_ElementType, str);
  METAIO_STREAM::cout << "ElementType = " << str << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementNumberOfChannels = "
                      << m_ElementNumberOfChannels << METAIO_STREAM::endl;

  if(m_ElementMinMaxValid)
    {
    METAIO_STREAM::cout << "Min and Max are valid" << METAIO_STREAM::endl;
    METAIO_STREAM::cout << "   Min = " << m_ElementMin << METAIO_STREAM::endl;
    METAIO_STREAM::cout << "   Max = " << m_ElementMax << METAIO_STREAM::endl;
    }
  else
    {
    METAIO_STREAM::cout << "Min and Max are not valid" << METAIO_STREAM::endl;
    }

  METAIO_STREAM::cout << "ElementToIntensityFunctionSlope = "
                      << m_ElementToIntensityFunctionSlope
                      << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "ElementToIntensityFunctionOffset = "
                      << m_ElementToIntensityFunctionOffset
                      << METAIO_STREAM::endl;


  METAIO_STREAM::cout << "AutoFreeElementData = "
                      << ((m_AutoFreeElementData)?"True":"False")
                      << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementData = "
                      << ((m_ElementData==NULL)?"NULL":"Valid")
                      << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementDataFileName = "
                      << m_ElementDataFileName << METAIO_STREAM::endl;

  }

void MetaImage::
CopyInfo(const MetaObject * _object)
  {
  MetaObject::CopyInfo(_object);

  if(_object)
    {
    const MetaImage * im;
    try
      {
      im = (const MetaImage *)(_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(void)
{
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: Clear" << METAIO_STREAM::endl;
    }

  m_Modality = MET_MOD_UNKNOWN;

  m_DimSize[0] = 0;
  m_SubQuantity[0] = 0;
  m_Quantity = 0;

  m_HeaderSize = 0;

  memset(m_SequenceID, 0, 4*sizeof(float));

  m_ElementSizeValid = false;
  memset(m_ElementSize, 0, 10*sizeof(float));

  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 = NULL;

  strcpy(m_ElementDataFileName, "");

  MetaObject::Clear();

  // 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 = NULL;
      }
    m_CompressionTable->compressedStream = NULL;
    m_CompressionTable->offsetList.clear();
    }
  else
    {
    m_CompressionTable = new MET_CompressionTableType;
    m_CompressionTable->compressedStream = NULL;
    }

}

bool MetaImage::
InitializeEssential(int _nDims,
                    const int * _dimSize,
                    const float * _elementSpacing,
                    MET_ValueEnumType _elementType,
                    int _elementNumberOfChannels,
                    void * _elementData,
                    bool _allocElementMemory)
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: Initialize" << METAIO_STREAM::endl;
    }

  MetaObject::InitializeEssential(_nDims);

  int i;
  if(!m_CompressionTable)
    {
    m_CompressionTable = new MET_CompressionTableType;
    m_CompressionTable->buffer = NULL;
    m_CompressionTable->compressedStream = NULL;
    }
  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 != NULL)
    {
    m_AutoFreeElementData = false;
    m_ElementData = (void *)_elementData;
    }
  else if(_allocElementMemory)
    {
    m_AutoFreeElementData = true;
    MET_SizeOfType(m_ElementType, &i);
    m_ElementData = new char[m_Quantity*m_ElementNumberOfChannels*i];
    if(m_ElementData == NULL)
      {
      METAIO_STREAM::cerr << "MetaImage:: M_Allocate:: Insufficient memory"
                          << METAIO_STREAM::endl;
      return false;
      }
    }
  else
    {
    m_AutoFreeElementData = true;
    m_ElementData = NULL;
    }

  return true;
  }


//
//
//
int MetaImage::
HeaderSize(void) const
  {
  return m_HeaderSize;
  }

void MetaImage::
HeaderSize(int _headerSize)
  {
  m_HeaderSize = _headerSize;
  }

//
//
//
MET_ImageModalityEnumType MetaImage::
Modality(void) const
  {
  return m_Modality;
  }

void MetaImage::
Modality(MET_ImageModalityEnumType _modality)
  {
  m_Modality = _modality;
  }

//
//
//
const int * MetaImage::
DimSize(void) const
  {
  return m_DimSize;
  }

int MetaImage::
DimSize(int _i) const
  {
  return m_DimSize[_i];
  }

//
//
//
int MetaImage::
Quantity(void) const
  {
  return m_Quantity;
  }

//
//
//
const int * MetaImage::
SubQuantity(void) const
  {
  return m_SubQuantity;
  }

int MetaImage::
SubQuantity(int _i) const
  {
  return m_SubQuantity[_i];
  }

//
//
//
const float * MetaImage::
SequenceID(void) 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(void) const
  {
  return m_ElementSizeValid;
  }

void MetaImage::
ElementSizeValid(bool _elementSizeValid)
  {
  m_ElementSizeValid = _elementSizeValid;
  }

const float * MetaImage::
ElementSize(void) const
  {
  return m_ElementSize;
  }

float MetaImage::
ElementSize(int _i) const
  {
  return m_ElementSize[_i];
  }

void MetaImage::
ElementSize(const float *_elementSize)
  {
  memcpy(m_ElementSize, _elementSize, m_NDims*sizeof(float));
  m_ElementSizeValid = true;
  }

void MetaImage::
ElementSize(int _i, float _value)
  {
  m_ElementSize[_i] = _value;
  m_ElementSizeValid = true;
  }

//
//
//
MET_ValueEnumType MetaImage::
ElementType(void) const
  {
  return m_ElementType;
  }

void MetaImage::
ElementType(MET_ValueEnumType _elementType)
  {
  m_ElementType = _elementType;
  }

//
//
//
int MetaImage::
ElementNumberOfChannels(void) const
  {
  return m_ElementNumberOfChannels;
  }

void MetaImage::
ElementNumberOfChannels(int _elementNumberOfChannels)
  {
  m_ElementNumberOfChannels = _elementNumberOfChannels;
  }

//
//
//
void MetaImage::
ElementByteOrderSwap(void)
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: ElementByteOrderSwap"
                        << METAIO_STREAM::endl;
    }

  int eSize;
  MET_SizeOfType(m_ElementType, &eSize);
  switch(eSize)
    {
    default:
    case 0:
    case 1:
      {
      break;
      }
    case 2:
      {
      int i;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        ((MET_USHORT_TYPE *)m_ElementData)[i] =
              MET_ByteOrderSwapShort(((MET_USHORT_TYPE *)m_ElementData)[i]);
        }
      break;
      }
    case 4:
      {
      int i;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        ((MET_UINT_TYPE *)m_ElementData)[i] =
              MET_ByteOrderSwapLong(((MET_UINT_TYPE *)m_ElementData)[i]);
        }
      break;
      }
    case 8:
      {
      int i;
      char* data = (char*)m_ElementData;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        MET_ByteOrderSwap8(data);
        data += 8;
        }
      break;
      }
    }
  m_BinaryDataByteOrderMSB = !m_BinaryDataByteOrderMSB;
  }

bool MetaImage::
ElementByteOrderFix(void)
  {
  if(m_BinaryDataByteOrderMSB != MET_SystemByteOrderMSB())
    {
    ElementByteOrderSwap();
    return true;
    }
  return true;
  }

//
//
//
bool MetaImage::
ElementMinMaxValid(void) const
  {
  return m_ElementMinMaxValid;
  }

void MetaImage::
ElementMinMaxValid(bool _elementMinMaxValid)
  {
  m_ElementMinMaxValid = _elementMinMaxValid;
  }

void MetaImage::
ElementMinMaxRecalc(void)
  {
  int i;
  double tf;

  if(m_ElementData == NULL)
    return;

  ElementByteOrderFix();

  MET_ValueToDouble(m_ElementType, m_ElementData, 0, &tf);
  m_ElementMin = tf;
  m_ElementMax = tf;
  for(i=1; i<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(void) const
  {
  return m_ElementMin;
  }

void MetaImage::
ElementMin(double _elementMin)
  {
  m_ElementMin = _elementMin;
  }

double MetaImage::
ElementMax(void) const
  {
  return m_ElementMax;
  }

void MetaImage::
ElementMax(double _elementMax)
  {
  m_ElementMax = _elementMax;
  }

//
//
//
double MetaImage::
ElementToIntensityFunctionSlope(void) const
  {
  return m_ElementToIntensityFunctionSlope;
  }

void MetaImage::
ElementToIntensityFunctionSlope(double _elementToIntensityFunctionSlope)
  {
  m_ElementToIntensityFunctionSlope = _elementToIntensityFunctionSlope;
  }

double MetaImage::
ElementToIntensityFunctionOffset(void) const
  {
  return m_ElementToIntensityFunctionOffset;
  }

void MetaImage::
ElementToIntensityFunctionOffset(double _elementOffset)
  {
  m_ElementToIntensityFunctionOffset = _elementOffset;
  }

//
//
//
bool MetaImage::
AutoFreeElementData(void) const
  {
  return m_AutoFreeElementData;
  }

void MetaImage::
AutoFreeElementData(bool _autoFreeElementData)
  {
  m_AutoFreeElementData = _autoFreeElementData;
  }

//
//
//
const char * MetaImage::
ElementDataFileName(void) const
  {
  return m_ElementDataFileName;
  }

void MetaImage::
ElementDataFileName(const char * _elementDataFileName)
  {
  strcpy(m_ElementDataFileName, _elementDataFileName);
  }

//
//
//
void * MetaImage::
ElementData(void)
  {
  return m_ElementData;
  }

double MetaImage::
ElementData(int _i) const
  {
  double tf = 0;
  MET_ValueToDouble(m_ElementType, m_ElementData, _i, &tf);

  return tf;
  }

bool MetaImage::
ElementData(int _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 [] (char *)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[m_Quantity*m_ElementNumberOfChannels*eSize];

  ElementByteOrderFix();
  if(!ElementMinMaxValid())
    {
    ElementMinMaxRecalc();
    }

  int i;
  for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
    {
    MET_ValueToValue(m_ElementType, m_ElementData, i, _elementType,
                     newElementData, m_ElementMin, m_ElementMax,
                     _toMin, _toMax);
    }

  if(m_AutoFreeElementData)
    {
    delete [] (char *)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) const
{
#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;
    }
}

// Return the value of a tag
METAIO_STL::string MetaImage::M_GetTagValue(const METAIO_STL::string & buffer, const char* tag) const
{
  long int stringPos = buffer.find(tag);
  if( stringPos == (long int)METAIO_STL::string::npos )
    {
    return "";
    }

  long int pos2 = buffer.find("=",stringPos);
  if(pos2 == (long int)METAIO_STL::string::npos )
    {
    pos2 = buffer.find(":",stringPos);
    }

  if(pos2 == (long int)METAIO_STL::string::npos )
    {
    return "";
    }

  long int posend = buffer.find('\r',pos2);
  if(posend == (long int)METAIO_STL::string::npos )
    {
    posend = buffer.find('\n',pos2);
    }

  // Get the element data filename
  METAIO_STL::string value = "";
  bool firstspace = true;
  unsigned int 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) const
  {
  // First check the extension
  METAIO_STL::string fname = _headerName;
  if(  fname == "" )
    {
    return false;
    }

  bool extensionFound = false;

  METAIO_STL::string::size_type stringPos = fname.rfind(".mhd");
  if ((stringPos != METAIO_STL::string::npos)
      && (stringPos == fname.length() - 4))
    {
    extensionFound = true;
    }

  stringPos = fname.rfind(".mha");
  if ((stringPos != METAIO_STL::string::npos)
      && (stringPos == fname.length() - 4))
    {
    extensionFound = true;
    }

  if( !extensionFound )
    {
    return false;
    }

  int i=0;

  // Now check the file content
  METAIO_STREAM::ifstream inputStream;

#ifdef __sgi
  inputStream.open( fname.c_str(), METAIO_STREAM::ios::in );
#else
  inputStream.open( fname.c_str(), METAIO_STREAM::ios::in |
                                   METAIO_STREAM::ios::binary );
#endif

  if( inputStream.fail() )
    {
    return false;
    }

  bool usePath;
  char pathName[255];
  usePath = MET_GetFilePath(_headerName, pathName);

  char* buf = new char[8001];
  inputStream.read(buf,8000);
  unsigned long fileSize = inputStream.gcount();
  buf[fileSize] = 0;
  METAIO_STL::string header(buf);
  header.resize(fileSize);
  delete [] buf;
  inputStream.close();

  stringPos = header.find("NDims");
  if( stringPos == METAIO_STL::string::npos )
    {
    return false;
    }

  METAIO_STL::string elementDataFileName = M_GetTagValue(header,"ElementDataFile");

  char* fName = new char[512];

  if(!strcmp("Local", elementDataFileName.c_str()) ||
       !strcmp("LOCAL", elementDataFileName.c_str()) ||
       !strcmp("local", elementDataFileName.c_str()))
      {
      }
  else if(!strncmp("LIST", elementDataFileName.c_str(),4))
      {
      /*int fileImageDim = m_NDims - 1;
      int nWrds;
      char **wrds;
      MET_StringToWordArray(elementDataFileName.c_str(), &nWrds, &wrds);
      if(nWrds > 1)
        {
        fileImageDim = (int)atof(wrds[1]);
        }
      for(i=0; i<nWrds; i++)
        {
        delete [] wrds[i++];
        }
      if ( (fileImageDim == 0) || (fileImageDim > m_NDims) )
        {
        // if optional file dimension size is not give or is larger than
        // overall dimension then default to a size of m_NDims - 1.
        fileImageDim = m_NDims-1;
        }
      char s[1024];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::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++)
        {
        _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)
            {
            sprintf(fName, "%s%s", pathName, s);
            }
          else
            {
            strcpy(fName, s);
            }

          if(!this->M_FileExists(fName))
            {
            METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.";
            return false;
            }
          }
        }*/
      }
    else if(strstr(elementDataFileName.c_str(), "%"))
      {
      // Need the dimsize and the element spacing
      METAIO_STL::string nDimsString = M_GetTagValue(header,"NDims");
      METAIO_STL::string dimSizeString = M_GetTagValue(header,"DimSize");

      int nDims = atoi(nDimsString.c_str());

      int* dimSize = new int[nDims];
      char** pntVal = NULL;
      MET_StringToWordArray(dimSizeString.c_str(), &nDims, &pntVal);

      for(i=0;i<nDims;i++)
        {
        dimSize[i] = atoi(pntVal[i]);
        }

      int nWrds;
      char **wrds;
      int minV = 1;
      int maxV = dimSize[nDims-1];
      int stepV = 1;
      char s[255];
      MET_StringToWordArray(elementDataFileName.c_str(), &nWrds, &wrds);
      if(nWrds >= 2)
        {
        minV = (int)atof(wrds[1]);
        maxV = minV + dimSize[nDims-1] - 1;
        }
      if(nWrds >= 3)
        {
        maxV = (int)atof(wrds[2]);
        stepV = (maxV-minV)/(dimSize[nDims-1]);
        }
      if(nWrds >= 4)
        {
        stepV = (int)atof(wrds[3]);
        }
      for(i=minV; i<=maxV; i += stepV)
        {
        sprintf(s, wrds[0], i);
        if(usePath)
          {
          sprintf(fName, "%s%s", pathName, s);
          }
        else
          {
          strcpy(fName, s);
          }

        if(!M_FileExists(fName))
          {
          METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.\n";
          delete [] fName;
          delete [] dimSize;
          return false;
          }
        }
      delete [] dimSize;
      }
    else
      {
      if(usePath)
        {
        sprintf(fName, "%s%s", pathName, elementDataFileName.c_str());
        }
      else
        {
        strcpy(fName, elementDataFileName.c_str());
        }
      if(!M_FileExists(fName))
        {
        METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.\n";
        delete [] fName;
        return false;
        }
      }

  delete [] fName;
  return true;
  }

bool MetaImage::
Read(const char *_headerName, bool _readElements, void * _buffer)
  {
  M_Destroy();

  Clear();

  M_SetupReadFields();

  if(_headerName != NULL)
    {
    strcpy(m_FileName, _headerName);
    }

  M_PrepareNewReadStream();

  METAIO_STREAM::ifstream * tmpReadStream = new METAIO_STREAM::ifstream;

#ifdef __sgi
  tmpReadStream->open(m_FileName, METAIO_STREAM::ios::in);
#else
  tmpReadStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                  METAIO_STREAM::ios::in);
#endif

  if(!tmpReadStream->rdbuf()->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(METAIO_STREAM::ifstream * _stream) const
  {
  if(!strncmp(MET_ReadType(*_stream).c_str(), "Image", 5))
    {
    return true;
    }
  return false;
  }

bool MetaImage::
ReadStream(int _nDims,
           METAIO_STREAM::ifstream * _stream,
           bool _readElements,
           void * _buffer)
  {
  if(!MetaObject::ReadStream(_nDims, _stream))
    {
    METAIO_STREAM::cerr << "MetaImage: Read: Cannot parse file"
                        << METAIO_STREAM::endl;
    return false;
    }

  if(_readElements)
    {
    if(_buffer == NULL)
      {
      InitializeEssential(m_NDims,
                          m_DimSize,
                          m_ElementSpacing,
                          m_ElementType,
                          m_ElementNumberOfChannels,
                          NULL, true);
      }
    else
      {
      InitializeEssential(m_NDims,
                          m_DimSize,
                          m_ElementSpacing,
                          m_ElementType,
                          m_ElementNumberOfChannels,
                          _buffer, false);
      }

    int i, j;
    bool usePath;
    char pathName[255];
    char fName[255];
    usePath = MET_GetFilePath(m_FileName, pathName);

    if(!strcmp("Local", m_ElementDataFileName) ||
       !strcmp("LOCAL", m_ElementDataFileName) ||
       !strcmp("local", m_ElementDataFileName))
      {
      M_ReadElements(_stream, m_ElementData, m_Quantity);
      }
    else if(!strncmp("LIST", m_ElementDataFileName,4))
      {
      int fileImageDim = m_NDims - 1;
      int nWrds;
      char **wrds;
      MET_StringToWordArray(m_ElementDataFileName, &nWrds, &wrds);
      if(nWrds > 1)
        {
        fileImageDim = (int)atof(wrds[1]);
        }
      for(i=0; i<nWrds; i++)
        {
        delete [] wrds[i++];
        }
      if ( (fileImageDim == 0) || (fileImageDim > m_NDims) )
        {
        // if optional file dimension size is not give or is larger than
        // overall dimension then default to a size of m_NDims - 1.
        fileImageDim = m_NDims-1;
        }
      char s[1024];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::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++)
        {
        _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)
            {
            sprintf(fName, "%s%s", pathName, s);
            }
          else
            {
            strcpy(fName, s);
            }

#ifdef __sgi
          readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
          readStreamTemp->open(fName, METAIO_STREAM::ios::binary |
                                      METAIO_STREAM::ios::in);
#endif
          if(!readStreamTemp->rdbuf()->is_open())
            {
            METAIO_STREAM::cerr << "MetaImage: Read: cannot open slice"
                                << METAIO_STREAM::endl;
            continue;
            }
          M_ReadElements(readStreamTemp,
                       &(((char *)m_ElementData)[i*m_SubQuantity[fileImageDim]*
                                                 elementSize]),
                       m_SubQuantity[fileImageDim]);
          readStreamTemp->close();
          }
        }
      delete readStreamTemp;
      }
    else if(strstr(m_ElementDataFileName, "%"))
      {
      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;
      char s[255];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::ifstream;
      MET_StringToWordArray(m_ElementDataFileName, &nWrds, &wrds);
      if(nWrds >= 2)
        {
        minV = (int)atof(wrds[1]);
        maxV = minV + m_DimSize[m_NDims-1] - 1;
        }
      if(nWrds >= 3)
        {
        maxV = (int)atof(wrds[2]);
        stepV = (maxV-minV)/(m_DimSize[m_NDims-1]);
        }
      if(nWrds >= 4)
        {
        stepV = (int)atof(wrds[3]);
        }
      int cnt = 0;
      for(i=minV; i<=maxV; i += stepV)
        {
        sprintf(s, wrds[0], i);
        if(usePath)
          {
          sprintf(fName, "%s%s", pathName, s);
          }
        else
          {
          strcpy(fName, s);
          }
#ifdef __sgi
        readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
        readStreamTemp->open(fName, METAIO_STREAM::ios::binary
                                    | METAIO_STREAM::ios::in);
#endif
        if(!readStreamTemp->rdbuf()->is_open())
          {
          METAIO_STREAM::cerr << "MetaImage: Read: cannot construct file"
                              << METAIO_STREAM::endl;
          continue;
          }

        M_ReadElements(readStreamTemp,
                       &(((char *)m_ElementData)[cnt*m_SubQuantity[m_NDims-1]*
                                                 elementSize]),
                       m_SubQuantity[m_NDims-1]);
        cnt++;

        readStreamTemp->close();
        }
      delete readStreamTemp;
      }
    else
      {
      if(usePath)
        {
        sprintf(fName, "%s%s", pathName, m_ElementDataFileName);
        }
      else
        {
        strcpy(fName, m_ElementDataFileName);
        }

      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::ifstream;

#ifdef __sgi
      readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
      readStreamTemp->open(fName, METAIO_STREAM::ios::binary |
                                  METAIO_STREAM::ios::in);
#endif

      if(!readStreamTemp->rdbuf()->is_open())
        {
        METAIO_STREAM::cerr << "MetaImage: Read: Cannot open data file"
                            << METAIO_STREAM::endl;
        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 != NULL)
    {
    FileName(_headName);
    }

  bool userDataFileName = true;
  if(_dataName == NULL && strlen(m_ElementDataFileName)==0)
    {
    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");
        }
      strcpy(m_ElementDataFileName, m_FileName);
      if(m_CompressedData)
        {
        MET_SetFileSuffix(m_ElementDataFileName, "zraw");
        }
      else
        {
        MET_SetFileSuffix(m_ElementDataFileName, "raw");
        }
      }
    }
  else if(_dataName != NULL)
    {
    userDataFileName = false;
    ElementDataFileName(_dataName);
    }

  // make sure suffix is valid
  if(!_append)
    {
    if(!strcmp(m_ElementDataFileName, "LOCAL"))
      {
      MET_SetFileSuffix(m_FileName, "mha");
      }
     else
      {
      MET_SetFileSuffix(m_FileName, "mhd");
      }
    }

  char pathName[255];
  bool usePath = MET_GetFilePath(m_FileName, pathName);
  if(usePath)
    {
    char elementPathName[255];
    MET_GetFilePath(m_ElementDataFileName, elementPathName);
    if(!strcmp(pathName, elementPathName))
      {
      strcpy(elementPathName, &m_ElementDataFileName[strlen(pathName)]);
      strcpy(m_ElementDataFileName, elementPathName);
      }
    }

  METAIO_STREAM::ofstream * tmpWriteStream = new METAIO_STREAM::ofstream;

// Some older sgi compilers have a error in the ofstream constructor
// that requires a file to exist for output
#ifdef __sgi
  {
  METAIO_STREAM::ofstream tFile(m_FileName, METAIO_STREAM::ios::out);
  tFile.close();
  }
#endif

  if(!_append)
    {
#ifdef __sgi
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::out);
#else
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                     METAIO_STREAM::ios::out);
#endif
    }
  else
    {
#ifdef __sgi
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::app |
                                     METAIO_STREAM::ios::out);
#else
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                     METAIO_STREAM::ios::app |
                                     METAIO_STREAM::ios::out);
#endif
    }

  if(!tmpWriteStream->rdbuf()->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(METAIO_STREAM::ofstream * _stream,
            bool _writeElements,
            const void * _constElementData)
  {
  if(m_WriteStream != NULL)
    {
    METAIO_STREAM::cerr << "MetaArray: WriteStream: two files open?"
                        << METAIO_STREAM::endl;
    delete m_WriteStream;
    }

  m_WriteStream = _stream;

  unsigned char * compressedElementData = NULL;
  if(m_BinaryData && m_CompressedData && !strstr(m_ElementDataFileName, "%"))
    // compressed & !slice/file
    {
    int elementSize;
    MET_SizeOfType(m_ElementType, &elementSize);
    int elementNumberOfBytes = elementSize*m_ElementNumberOfChannels;

    if(_constElementData == NULL)
      {
      compressedElementData = MET_PerformCompression(
                                  (const unsigned char *)m_ElementData,
                                  m_Quantity * elementNumberOfBytes,
                                  & m_CompressedDataSize );
      }
    else
      {
      compressedElementData = MET_PerformCompression(
                                  (const unsigned char *)_constElementData,
                                  m_Quantity * elementNumberOfBytes,
                                  & m_CompressedDataSize );
      }
    }

  M_SetupWriteFields();

  M_Write();

  if(_writeElements)
    {
    if(m_BinaryData && m_CompressedData && !strstr(m_ElementDataFileName, "%"))
      // compressed & !slice/file
      {
      M_WriteElements(m_WriteStream,
                      compressedElementData,
                      m_CompressedDataSize);

      delete [] compressedElementData;
      m_CompressedDataSize = 0;
      }
    else
      {
      if(_constElementData == NULL)
        {
        M_WriteElements(m_WriteStream,
                        m_ElementData,
                        m_Quantity);
        }
      else
        {
        M_WriteElements(m_WriteStream,
                        _constElementData,
                        m_Quantity);
        }
      }
    }

  m_WriteStream = NULL;

  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
                         )
{   
   int i=0;
      
   if(_headName != NULL) 
    {
    FileName(_headName);
    }

  bool result = false;

  // Check if the file exists
  if(M_FileExists(_headName))
    {
    char* elementData = const_cast<char*>(static_cast<const char*>(_constElementData));
    if(elementData == NULL)
      {
      elementData = (char*)m_ElementData;
      }
     
    // Find the start of the data
    METAIO_STREAM::ifstream * readStream = new METAIO_STREAM::ifstream;
    readStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                 METAIO_STREAM::ios::in);
    if(!MetaObject::ReadStream(m_NDims, readStream))
      {
      METAIO_STREAM::cerr << "MetaImage: Read: Cannot parse file"
                        << METAIO_STREAM::endl;
      return false;
      }

    InitializeEssential(m_NDims,
                        m_DimSize,
                        m_ElementSpacing,
                        m_ElementType,
                        m_ElementNumberOfChannels,
                        NULL, false); // no memory allocation
  
   
   std::string  filename = ElementDataFileName();
   unsigned long dataPos = 0;
   
   // local file
   if(filename == "LOCAL")
     {
     filename = m_FileName;
     dataPos = readStream->tellg();
     }
   
   readStream->close();
   delete readStream;

   // Write the region
   if(!M_FileExists(filename.c_str()))
     {
     char pathName[255];
     MET_GetFilePath(_headName, pathName);
     filename = pathName+filename; 
     }
   
   METAIO_STREAM::ofstream * tmpWriteStream = new METAIO_STREAM::ofstream;
   tmpWriteStream->open(filename.c_str(), METAIO_STREAM::ios::binary |
                                          METAIO_STREAM::ios::in |
                                          METAIO_STREAM::ios::out);
   
   if(!tmpWriteStream->is_open())
      {
      std::cerr << "Cannot open file: " << filename.c_str() << std::endl;
      delete tmpWriteStream;
      return false;
      }
    
     int* currentIndex = new int[m_NDims];
     for(i=0;i<m_NDims;i++)
        {
        currentIndex[i] = _indexMin[i];
        }
     
     if(!elementData)
       {
       std::cerr << "Element data is NULL" << std::endl;
       return false;
       }
      
     int elementSize;
     MET_SizeOfType(m_ElementType, &elementSize);    
     int elementNumberOfBytes = elementSize*m_ElementNumberOfChannels;
                
    // This should probably go in a function 
    bool done = false;
    while(!done)
      {
      // Seek to the right position
      unsigned long seekpos = dataPos;
      for(i=0;i<m_NDims;i++)
        {
        seekpos += m_SubQuantity[i]*currentIndex[i]*elementNumberOfBytes;
        }
      
      // Add zeros to the image if the data is missing. 
      // Maybe this should refer to a function to avoid
      // taking all the memory like we did before.
      tmpWriteStream->seekp(0,METAIO_STREAM::ios::end);  
      size_t endfile = tmpWriteStream->tellp();
      
      long padding = seekpos-endfile;
      if(padding>0)
        {
        std::cout << "Padding = " << padding << std::endl;
        unsigned char* zerobytes = new unsigned char[padding];
        memset(zerobytes,0,padding);
        tmpWriteStream->write((const char*)zerobytes,padding);  
        delete [] zerobytes;
        }
          
      // Write the line
      tmpWriteStream->seekp(seekpos,METAIO_STREAM::ios::beg);  
      long bytesToWrite = _indexMax[0]-_indexMin[0];
      tmpWriteStream->write((const char*)elementData,bytesToWrite*elementNumberOfBytes);  
      
      elementData += bytesToWrite*elementNumberOfBytes;
        
      if(m_NDims>1)
        {
        currentIndex[1]++;
        }
      else
        {
        done = true;
        }
          
      // 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]++;
            }
          }
        }
      } // end writing line by line loop

    tmpWriteStream->close();
    delete tmpWriteStream;    
    }
  else // the file doesn't exist
    {
    bool userDataFileName = true;
    if(_dataName == NULL && strlen(m_ElementDataFileName)==0)
      {
      userDataFileName = false;
      int sPtr = 0;
      MET_GetFileSuffixPtr(m_FileName, &sPtr);
      if(!strcmp(&m_FileName[sPtr], "mha"))<commit_msg>r184 jjomier | 2008-02-25T16:30:25.652077Z COMP: warnings and MLKs<commit_after>/*=========================================================================

  Program:   MetaIO
  Module:    metaImage.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "metaImage.h"

#include <stdio.h>
#include <ctype.h>
#include <string>
#include <string.h> // for memcpy
#include <stdlib.h> // for atoi
#include <math.h>

#if defined (__BORLANDC__) && (__BORLANDC__ >= 0x0580)
#include <mem.h>
#endif

#if defined(_WIN32)
# include <io.h>
#endif

// support for access
#ifndef _WIN32
#include <limits.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <pwd.h>
#include <termios.h>
#include <signal.h>    /* sigprocmask */
#endif

#if (METAIO_USE_NAMESPACE)
namespace METAIO_NAMESPACE {
#endif


//
// MetaImage Constructors
//
MetaImage::
MetaImage()
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();
  }

//
MetaImage::
MetaImage(const char *_headerName)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  Read(_headerName);
  }

//
MetaImage::
MetaImage(MetaImage *_im)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  InitializeEssential(_im->NDims(),
                      _im->DimSize(),
                      _im->ElementSpacing(),
                      _im->ElementType(),
                      _im->ElementNumberOfChannels(),
                      _im->ElementData(),
                      false);
  CopyInfo(_im);
  }

//
MetaImage::
MetaImage(int _nDims,
          const int * _dimSize,
          const float * _elementSpacing,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels,
          void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->buffer = NULL;
  m_CompressionTable->compressedStream = NULL;
  Clear();

  if(_elementData == NULL)
    {
    InitializeEssential(_nDims,
                        _dimSize,
                        _elementSpacing,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL, true);
    }
  else
    {
    InitializeEssential(_nDims,
                        _dimSize,
                        _elementSpacing,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData, false);
    }

  }

//
MetaImage::
MetaImage(int _x, int _y,
          float _elementSpacingX, float _elementSpacingY,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels, void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  int ds[2];
  ds[0] = _x;
  ds[1] = _y;

  float es[2];
  es[0] = _elementSpacingX;
  es[1] = _elementSpacingY;

  if(_elementData == NULL)
    {
    InitializeEssential(2,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL,
                        true);
    }
  else
    {
    InitializeEssential(2,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData,
                        false);
    }
  }

//
MetaImage::
MetaImage(int _x, int _y, int _z,
          float _elementSpacingX,
          float _elementSpacingY,
          float _elementSpacingZ,
          MET_ValueEnumType _elementType,
          int _elementNumberOfChannels,
          void *_elementData)
:MetaObject()
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage()" << METAIO_STREAM::endl;
    }

  m_CompressionTable = new MET_CompressionTableType;
  m_CompressionTable->compressedStream = NULL;
  m_CompressionTable->buffer = NULL;
  Clear();

  int ds[3];
  ds[0] = _x;
  ds[1] = _y;
  ds[2] = _z;

  float es[3];
  es[0] = _elementSpacingX;
  es[1] = _elementSpacingY;
  es[2] = _elementSpacingZ;

  if(_elementData == NULL)
    {
    InitializeEssential(3,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        NULL,
                        true);
    }
  else
    {
    InitializeEssential(3,
                        ds,
                        es,
                        _elementType,
                        _elementNumberOfChannels,
                        _elementData,
                        false);
    }
  }

//
MetaImage::
~MetaImage()
  {
  M_Destroy();
  }

//
void MetaImage::
PrintInfo() const
  {
  int i;

  MetaObject::PrintInfo();

  char s[255];
  MET_ImageModalityToString(m_Modality, s);
  METAIO_STREAM::cout << "Modality = " << s << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "DimSize = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_DimSize[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "SubQuantity = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_SubQuantity[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "Quantity = " << m_Quantity << METAIO_STREAM::endl;


  METAIO_STREAM::cout << "HeaderSize = " << m_HeaderSize << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "SequenceID = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_SequenceID[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementSizeValid = " << (int)m_ElementSizeValid
            << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "ElementSize = ";
  for(i=0; i<m_NDims; i++)
    {
    METAIO_STREAM::cout << m_ElementSize[i] << " ";
    }
  METAIO_STREAM::cout << METAIO_STREAM::endl;

  char str[255];
  MET_TypeToString(m_ElementType, str);
  METAIO_STREAM::cout << "ElementType = " << str << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementNumberOfChannels = "
                      << m_ElementNumberOfChannels << METAIO_STREAM::endl;

  if(m_ElementMinMaxValid)
    {
    METAIO_STREAM::cout << "Min and Max are valid" << METAIO_STREAM::endl;
    METAIO_STREAM::cout << "   Min = " << m_ElementMin << METAIO_STREAM::endl;
    METAIO_STREAM::cout << "   Max = " << m_ElementMax << METAIO_STREAM::endl;
    }
  else
    {
    METAIO_STREAM::cout << "Min and Max are not valid" << METAIO_STREAM::endl;
    }

  METAIO_STREAM::cout << "ElementToIntensityFunctionSlope = "
                      << m_ElementToIntensityFunctionSlope
                      << METAIO_STREAM::endl;
  METAIO_STREAM::cout << "ElementToIntensityFunctionOffset = "
                      << m_ElementToIntensityFunctionOffset
                      << METAIO_STREAM::endl;


  METAIO_STREAM::cout << "AutoFreeElementData = "
                      << ((m_AutoFreeElementData)?"True":"False")
                      << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementData = "
                      << ((m_ElementData==NULL)?"NULL":"Valid")
                      << METAIO_STREAM::endl;

  METAIO_STREAM::cout << "ElementDataFileName = "
                      << m_ElementDataFileName << METAIO_STREAM::endl;

  }

void MetaImage::
CopyInfo(const MetaObject * _object)
  {
  MetaObject::CopyInfo(_object);

  if(_object)
    {
    const MetaImage * im;
    try
      {
      im = (const MetaImage *)(_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(void)
{
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: Clear" << METAIO_STREAM::endl;
    }

  m_Modality = MET_MOD_UNKNOWN;

  m_DimSize[0] = 0;
  m_SubQuantity[0] = 0;
  m_Quantity = 0;

  m_HeaderSize = 0;

  memset(m_SequenceID, 0, 4*sizeof(float));

  m_ElementSizeValid = false;
  memset(m_ElementSize, 0, 10*sizeof(float));

  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 = NULL;

  strcpy(m_ElementDataFileName, "");

  MetaObject::Clear();

  // 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 = NULL;
      }
    m_CompressionTable->compressedStream = NULL;
    m_CompressionTable->offsetList.clear();
    }
  else
    {
    m_CompressionTable = new MET_CompressionTableType;
    m_CompressionTable->compressedStream = NULL;
    }

}

bool MetaImage::
InitializeEssential(int _nDims,
                    const int * _dimSize,
                    const float * _elementSpacing,
                    MET_ValueEnumType _elementType,
                    int _elementNumberOfChannels,
                    void * _elementData,
                    bool _allocElementMemory)
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: Initialize" << METAIO_STREAM::endl;
    }

  MetaObject::InitializeEssential(_nDims);

  int i;
  if(!m_CompressionTable)
    {
    m_CompressionTable = new MET_CompressionTableType;
    m_CompressionTable->buffer = NULL;
    m_CompressionTable->compressedStream = NULL;
    }
  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 != NULL)
    {
    m_AutoFreeElementData = false;
    m_ElementData = (void *)_elementData;
    }
  else if(_allocElementMemory)
    {
    m_AutoFreeElementData = true;
    MET_SizeOfType(m_ElementType, &i);
    m_ElementData = new char[m_Quantity*m_ElementNumberOfChannels*i];
    if(m_ElementData == NULL)
      {
      METAIO_STREAM::cerr << "MetaImage:: M_Allocate:: Insufficient memory"
                          << METAIO_STREAM::endl;
      return false;
      }
    }
  else
    {
    m_AutoFreeElementData = true;
    m_ElementData = NULL;
    }

  return true;
  }


//
//
//
int MetaImage::
HeaderSize(void) const
  {
  return m_HeaderSize;
  }

void MetaImage::
HeaderSize(int _headerSize)
  {
  m_HeaderSize = _headerSize;
  }

//
//
//
MET_ImageModalityEnumType MetaImage::
Modality(void) const
  {
  return m_Modality;
  }

void MetaImage::
Modality(MET_ImageModalityEnumType _modality)
  {
  m_Modality = _modality;
  }

//
//
//
const int * MetaImage::
DimSize(void) const
  {
  return m_DimSize;
  }

int MetaImage::
DimSize(int _i) const
  {
  return m_DimSize[_i];
  }

//
//
//
int MetaImage::
Quantity(void) const
  {
  return m_Quantity;
  }

//
//
//
const int * MetaImage::
SubQuantity(void) const
  {
  return m_SubQuantity;
  }

int MetaImage::
SubQuantity(int _i) const
  {
  return m_SubQuantity[_i];
  }

//
//
//
const float * MetaImage::
SequenceID(void) 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(void) const
  {
  return m_ElementSizeValid;
  }

void MetaImage::
ElementSizeValid(bool _elementSizeValid)
  {
  m_ElementSizeValid = _elementSizeValid;
  }

const float * MetaImage::
ElementSize(void) const
  {
  return m_ElementSize;
  }

float MetaImage::
ElementSize(int _i) const
  {
  return m_ElementSize[_i];
  }

void MetaImage::
ElementSize(const float *_elementSize)
  {
  memcpy(m_ElementSize, _elementSize, m_NDims*sizeof(float));
  m_ElementSizeValid = true;
  }

void MetaImage::
ElementSize(int _i, float _value)
  {
  m_ElementSize[_i] = _value;
  m_ElementSizeValid = true;
  }

//
//
//
MET_ValueEnumType MetaImage::
ElementType(void) const
  {
  return m_ElementType;
  }

void MetaImage::
ElementType(MET_ValueEnumType _elementType)
  {
  m_ElementType = _elementType;
  }

//
//
//
int MetaImage::
ElementNumberOfChannels(void) const
  {
  return m_ElementNumberOfChannels;
  }

void MetaImage::
ElementNumberOfChannels(int _elementNumberOfChannels)
  {
  m_ElementNumberOfChannels = _elementNumberOfChannels;
  }

//
//
//
void MetaImage::
ElementByteOrderSwap(void)
  {
  if(META_DEBUG)
    {
    METAIO_STREAM::cout << "MetaImage: ElementByteOrderSwap"
                        << METAIO_STREAM::endl;
    }

  int eSize;
  MET_SizeOfType(m_ElementType, &eSize);
  switch(eSize)
    {
    default:
    case 0:
    case 1:
      {
      break;
      }
    case 2:
      {
      int i;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        ((MET_USHORT_TYPE *)m_ElementData)[i] =
              MET_ByteOrderSwapShort(((MET_USHORT_TYPE *)m_ElementData)[i]);
        }
      break;
      }
    case 4:
      {
      int i;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        ((MET_UINT_TYPE *)m_ElementData)[i] =
              MET_ByteOrderSwapLong(((MET_UINT_TYPE *)m_ElementData)[i]);
        }
      break;
      }
    case 8:
      {
      int i;
      char* data = (char*)m_ElementData;
      for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
        {
        MET_ByteOrderSwap8(data);
        data += 8;
        }
      break;
      }
    }
  m_BinaryDataByteOrderMSB = !m_BinaryDataByteOrderMSB;
  }

bool MetaImage::
ElementByteOrderFix(void)
  {
  if(m_BinaryDataByteOrderMSB != MET_SystemByteOrderMSB())
    {
    ElementByteOrderSwap();
    return true;
    }
  return true;
  }

//
//
//
bool MetaImage::
ElementMinMaxValid(void) const
  {
  return m_ElementMinMaxValid;
  }

void MetaImage::
ElementMinMaxValid(bool _elementMinMaxValid)
  {
  m_ElementMinMaxValid = _elementMinMaxValid;
  }

void MetaImage::
ElementMinMaxRecalc(void)
  {
  int i;
  double tf;

  if(m_ElementData == NULL)
    return;

  ElementByteOrderFix();

  MET_ValueToDouble(m_ElementType, m_ElementData, 0, &tf);
  m_ElementMin = tf;
  m_ElementMax = tf;
  for(i=1; i<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(void) const
  {
  return m_ElementMin;
  }

void MetaImage::
ElementMin(double _elementMin)
  {
  m_ElementMin = _elementMin;
  }

double MetaImage::
ElementMax(void) const
  {
  return m_ElementMax;
  }

void MetaImage::
ElementMax(double _elementMax)
  {
  m_ElementMax = _elementMax;
  }

//
//
//
double MetaImage::
ElementToIntensityFunctionSlope(void) const
  {
  return m_ElementToIntensityFunctionSlope;
  }

void MetaImage::
ElementToIntensityFunctionSlope(double _elementToIntensityFunctionSlope)
  {
  m_ElementToIntensityFunctionSlope = _elementToIntensityFunctionSlope;
  }

double MetaImage::
ElementToIntensityFunctionOffset(void) const
  {
  return m_ElementToIntensityFunctionOffset;
  }

void MetaImage::
ElementToIntensityFunctionOffset(double _elementOffset)
  {
  m_ElementToIntensityFunctionOffset = _elementOffset;
  }

//
//
//
bool MetaImage::
AutoFreeElementData(void) const
  {
  return m_AutoFreeElementData;
  }

void MetaImage::
AutoFreeElementData(bool _autoFreeElementData)
  {
  m_AutoFreeElementData = _autoFreeElementData;
  }

//
//
//
const char * MetaImage::
ElementDataFileName(void) const
  {
  return m_ElementDataFileName;
  }

void MetaImage::
ElementDataFileName(const char * _elementDataFileName)
  {
  strcpy(m_ElementDataFileName, _elementDataFileName);
  }

//
//
//
void * MetaImage::
ElementData(void)
  {
  return m_ElementData;
  }

double MetaImage::
ElementData(int _i) const
  {
  double tf = 0;
  MET_ValueToDouble(m_ElementType, m_ElementData, _i, &tf);

  return tf;
  }

bool MetaImage::
ElementData(int _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 [] (char *)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[m_Quantity*m_ElementNumberOfChannels*eSize];

  ElementByteOrderFix();
  if(!ElementMinMaxValid())
    {
    ElementMinMaxRecalc();
    }

  int i;
  for(i=0; i<m_Quantity*m_ElementNumberOfChannels; i++)
    {
    MET_ValueToValue(m_ElementType, m_ElementData, i, _elementType,
                     newElementData, m_ElementMin, m_ElementMax,
                     _toMin, _toMax);
    }

  if(m_AutoFreeElementData)
    {
    delete [] (char *)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) const
{
#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;
    }
}

// Return the value of a tag
METAIO_STL::string MetaImage::M_GetTagValue(const METAIO_STL::string & buffer, const char* tag) const
{
  long int stringPos = buffer.find(tag);
  if( stringPos == (long int)METAIO_STL::string::npos )
    {
    return "";
    }

  long int pos2 = buffer.find("=",stringPos);
  if(pos2 == (long int)METAIO_STL::string::npos )
    {
    pos2 = buffer.find(":",stringPos);
    }

  if(pos2 == (long int)METAIO_STL::string::npos )
    {
    return "";
    }

  long int posend = buffer.find('\r',pos2);
  if(posend == (long int)METAIO_STL::string::npos )
    {
    posend = buffer.find('\n',pos2);
    }

  // Get the element data filename
  METAIO_STL::string value = "";
  bool firstspace = true;
  unsigned int 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) const
  {
  // First check the extension
  METAIO_STL::string fname = _headerName;
  if(  fname == "" )
    {
    return false;
    }

  bool extensionFound = false;

  METAIO_STL::string::size_type stringPos = fname.rfind(".mhd");
  if ((stringPos != METAIO_STL::string::npos)
      && (stringPos == fname.length() - 4))
    {
    extensionFound = true;
    }

  stringPos = fname.rfind(".mha");
  if ((stringPos != METAIO_STL::string::npos)
      && (stringPos == fname.length() - 4))
    {
    extensionFound = true;
    }

  if( !extensionFound )
    {
    return false;
    }

  int i=0;

  // Now check the file content
  METAIO_STREAM::ifstream inputStream;

#ifdef __sgi
  inputStream.open( fname.c_str(), METAIO_STREAM::ios::in );
#else
  inputStream.open( fname.c_str(), METAIO_STREAM::ios::in |
                                   METAIO_STREAM::ios::binary );
#endif

  if( inputStream.fail() )
    {
    return false;
    }

  bool usePath;
  char pathName[255];
  usePath = MET_GetFilePath(_headerName, pathName);

  char* buf = new char[8001];
  inputStream.read(buf,8000);
  unsigned long fileSize = inputStream.gcount();
  buf[fileSize] = 0;
  METAIO_STL::string header(buf);
  header.resize(fileSize);
  delete [] buf;
  inputStream.close();

  stringPos = header.find("NDims");
  if( stringPos == METAIO_STL::string::npos )
    {
    return false;
    }

  METAIO_STL::string elementDataFileName = M_GetTagValue(header,"ElementDataFile");

  char* fName = new char[512];

  if(!strcmp("Local", elementDataFileName.c_str()) ||
       !strcmp("LOCAL", elementDataFileName.c_str()) ||
       !strcmp("local", elementDataFileName.c_str()))
      {
      }
  else if(!strncmp("LIST", elementDataFileName.c_str(),4))
      {
      /*int fileImageDim = m_NDims - 1;
      int nWrds;
      char **wrds;
      MET_StringToWordArray(elementDataFileName.c_str(), &nWrds, &wrds);
      if(nWrds > 1)
        {
        fileImageDim = (int)atof(wrds[1]);
        }
      for(i=0; i<nWrds; i++)
        {
        delete [] wrds[i++];
        }
      if ( (fileImageDim == 0) || (fileImageDim > m_NDims) )
        {
        // if optional file dimension size is not give or is larger than
        // overall dimension then default to a size of m_NDims - 1.
        fileImageDim = m_NDims-1;
        }
      char s[1024];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::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++)
        {
        _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)
            {
            sprintf(fName, "%s%s", pathName, s);
            }
          else
            {
            strcpy(fName, s);
            }

          if(!this->M_FileExists(fName))
            {
            METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.";
            return false;
            }
          }
        }*/
      }
    else if(strstr(elementDataFileName.c_str(), "%"))
      {
      // Need the dimsize and the element spacing
      METAIO_STL::string nDimsString = M_GetTagValue(header,"NDims");
      METAIO_STL::string dimSizeString = M_GetTagValue(header,"DimSize");

      int nDims = atoi(nDimsString.c_str());

      int* dimSize = new int[nDims];
      char** pntVal = NULL;
      MET_StringToWordArray(dimSizeString.c_str(), &nDims, &pntVal);

      for(i=0;i<nDims;i++)
        {
        dimSize[i] = atoi(pntVal[i]);
        }

      int nWrds;
      char **wrds;
      int minV = 1;
      int maxV = dimSize[nDims-1];
      int stepV = 1;
      char s[255];
      MET_StringToWordArray(elementDataFileName.c_str(), &nWrds, &wrds);
      if(nWrds >= 2)
        {
        minV = (int)atof(wrds[1]);
        maxV = minV + dimSize[nDims-1] - 1;
        }
      if(nWrds >= 3)
        {
        maxV = (int)atof(wrds[2]);
        stepV = (maxV-minV)/(dimSize[nDims-1]);
        }
      if(nWrds >= 4)
        {
        stepV = (int)atof(wrds[3]);
        }
      for(i=minV; i<=maxV; i += stepV)
        {
        sprintf(s, wrds[0], i);
        if(usePath)
          {
          sprintf(fName, "%s%s", pathName, s);
          }
        else
          {
          strcpy(fName, s);
          }

        if(!M_FileExists(fName))
          {
          METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.\n";
          delete [] fName;
          delete [] dimSize;
          return false;
          }
        }
      delete [] dimSize;
      }
    else
      {
      if(usePath)
        {
        sprintf(fName, "%s%s", pathName, elementDataFileName.c_str());
        }
      else
        {
        strcpy(fName, elementDataFileName.c_str());
        }
      if(!M_FileExists(fName))
        {
        METAIO_STREAM::cout << fName << " cannot be opened. Make sure the file exists.\n";
        delete [] fName;
        return false;
        }
      }

  delete [] fName;
  return true;
  }

bool MetaImage::
Read(const char *_headerName, bool _readElements, void * _buffer)
  {
  M_Destroy();

  Clear();

  M_SetupReadFields();

  if(_headerName != NULL)
    {
    strcpy(m_FileName, _headerName);
    }

  M_PrepareNewReadStream();

  METAIO_STREAM::ifstream * tmpReadStream = new METAIO_STREAM::ifstream;

#ifdef __sgi
  tmpReadStream->open(m_FileName, METAIO_STREAM::ios::in);
#else
  tmpReadStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                  METAIO_STREAM::ios::in);
#endif

  if(!tmpReadStream->rdbuf()->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(METAIO_STREAM::ifstream * _stream) const
  {
  if(!strncmp(MET_ReadType(*_stream).c_str(), "Image", 5))
    {
    return true;
    }
  return false;
  }

bool MetaImage::
ReadStream(int _nDims,
           METAIO_STREAM::ifstream * _stream,
           bool _readElements,
           void * _buffer)
  {
  if(!MetaObject::ReadStream(_nDims, _stream))
    {
    METAIO_STREAM::cerr << "MetaImage: Read: Cannot parse file"
                        << METAIO_STREAM::endl;
    return false;
    }

  if(_readElements)
    {
    if(_buffer == NULL)
      {
      InitializeEssential(m_NDims,
                          m_DimSize,
                          m_ElementSpacing,
                          m_ElementType,
                          m_ElementNumberOfChannels,
                          NULL, true);
      }
    else
      {
      InitializeEssential(m_NDims,
                          m_DimSize,
                          m_ElementSpacing,
                          m_ElementType,
                          m_ElementNumberOfChannels,
                          _buffer, false);
      }

    int i, j;
    bool usePath;
    char pathName[255];
    char fName[255];
    usePath = MET_GetFilePath(m_FileName, pathName);

    if(!strcmp("Local", m_ElementDataFileName) ||
       !strcmp("LOCAL", m_ElementDataFileName) ||
       !strcmp("local", m_ElementDataFileName))
      {
      M_ReadElements(_stream, m_ElementData, m_Quantity);
      }
    else if(!strncmp("LIST", m_ElementDataFileName,4))
      {
      int fileImageDim = m_NDims - 1;
      int nWrds;
      char **wrds;
      MET_StringToWordArray(m_ElementDataFileName, &nWrds, &wrds);
      if(nWrds > 1)
        {
        fileImageDim = (int)atof(wrds[1]);
        }
      for(i=0; i<nWrds; i++)
        {
        delete [] wrds[i++];
        }
      if ( (fileImageDim == 0) || (fileImageDim > m_NDims) )
        {
        // if optional file dimension size is not give or is larger than
        // overall dimension then default to a size of m_NDims - 1.
        fileImageDim = m_NDims-1;
        }
      char s[1024];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::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++)
        {
        _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)
            {
            sprintf(fName, "%s%s", pathName, s);
            }
          else
            {
            strcpy(fName, s);
            }

#ifdef __sgi
          readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
          readStreamTemp->open(fName, METAIO_STREAM::ios::binary |
                                      METAIO_STREAM::ios::in);
#endif
          if(!readStreamTemp->rdbuf()->is_open())
            {
            METAIO_STREAM::cerr << "MetaImage: Read: cannot open slice"
                                << METAIO_STREAM::endl;
            continue;
            }
          M_ReadElements(readStreamTemp,
                       &(((char *)m_ElementData)[i*m_SubQuantity[fileImageDim]*
                                                 elementSize]),
                       m_SubQuantity[fileImageDim]);
          readStreamTemp->close();
          }
        }
      delete readStreamTemp;
      }
    else if(strstr(m_ElementDataFileName, "%"))
      {
      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;
      char s[255];
      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::ifstream;
      MET_StringToWordArray(m_ElementDataFileName, &nWrds, &wrds);
      if(nWrds >= 2)
        {
        minV = (int)atof(wrds[1]);
        maxV = minV + m_DimSize[m_NDims-1] - 1;
        }
      if(nWrds >= 3)
        {
        maxV = (int)atof(wrds[2]);
        stepV = (maxV-minV)/(m_DimSize[m_NDims-1]);
        }
      if(nWrds >= 4)
        {
        stepV = (int)atof(wrds[3]);
        }
      int cnt = 0;
      for(i=minV; i<=maxV; i += stepV)
        {
        sprintf(s, wrds[0], i);
        if(usePath)
          {
          sprintf(fName, "%s%s", pathName, s);
          }
        else
          {
          strcpy(fName, s);
          }
#ifdef __sgi
        readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
        readStreamTemp->open(fName, METAIO_STREAM::ios::binary
                                    | METAIO_STREAM::ios::in);
#endif
        if(!readStreamTemp->rdbuf()->is_open())
          {
          METAIO_STREAM::cerr << "MetaImage: Read: cannot construct file"
                              << METAIO_STREAM::endl;
          continue;
          }

        M_ReadElements(readStreamTemp,
                       &(((char *)m_ElementData)[cnt*m_SubQuantity[m_NDims-1]*
                                                 elementSize]),
                       m_SubQuantity[m_NDims-1]);
        cnt++;

        readStreamTemp->close();
        }
      delete readStreamTemp;
      }
    else
      {
      if(usePath)
        {
        sprintf(fName, "%s%s", pathName, m_ElementDataFileName);
        }
      else
        {
        strcpy(fName, m_ElementDataFileName);
        }

      METAIO_STREAM::ifstream* readStreamTemp = new METAIO_STREAM::ifstream;

#ifdef __sgi
      readStreamTemp->open(fName, METAIO_STREAM::ios::in);
#else
      readStreamTemp->open(fName, METAIO_STREAM::ios::binary |
                                  METAIO_STREAM::ios::in);
#endif

      if(!readStreamTemp->rdbuf()->is_open())
        {
        METAIO_STREAM::cerr << "MetaImage: Read: Cannot open data file"
                            << METAIO_STREAM::endl;
        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 != NULL)
    {
    FileName(_headName);
    }

  bool userDataFileName = true;
  if(_dataName == NULL && strlen(m_ElementDataFileName)==0)
    {
    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");
        }
      strcpy(m_ElementDataFileName, m_FileName);
      if(m_CompressedData)
        {
        MET_SetFileSuffix(m_ElementDataFileName, "zraw");
        }
      else
        {
        MET_SetFileSuffix(m_ElementDataFileName, "raw");
        }
      }
    }
  else if(_dataName != NULL)
    {
    userDataFileName = false;
    ElementDataFileName(_dataName);
    }

  // make sure suffix is valid
  if(!_append)
    {
    if(!strcmp(m_ElementDataFileName, "LOCAL"))
      {
      MET_SetFileSuffix(m_FileName, "mha");
      }
     else
      {
      MET_SetFileSuffix(m_FileName, "mhd");
      }
    }

  char pathName[255];
  bool usePath = MET_GetFilePath(m_FileName, pathName);
  if(usePath)
    {
    char elementPathName[255];
    MET_GetFilePath(m_ElementDataFileName, elementPathName);
    if(!strcmp(pathName, elementPathName))
      {
      strcpy(elementPathName, &m_ElementDataFileName[strlen(pathName)]);
      strcpy(m_ElementDataFileName, elementPathName);
      }
    }

  METAIO_STREAM::ofstream * tmpWriteStream = new METAIO_STREAM::ofstream;

// Some older sgi compilers have a error in the ofstream constructor
// that requires a file to exist for output
#ifdef __sgi
  {
  METAIO_STREAM::ofstream tFile(m_FileName, METAIO_STREAM::ios::out);
  tFile.close();
  }
#endif

  if(!_append)
    {
#ifdef __sgi
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::out);
#else
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                     METAIO_STREAM::ios::out);
#endif
    }
  else
    {
#ifdef __sgi
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::app |
                                     METAIO_STREAM::ios::out);
#else
    tmpWriteStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                     METAIO_STREAM::ios::app |
                                     METAIO_STREAM::ios::out);
#endif
    }

  if(!tmpWriteStream->rdbuf()->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(METAIO_STREAM::ofstream * _stream,
            bool _writeElements,
            const void * _constElementData)
  {
  if(m_WriteStream != NULL)
    {
    METAIO_STREAM::cerr << "MetaArray: WriteStream: two files open?"
                        << METAIO_STREAM::endl;
    delete m_WriteStream;
    }

  m_WriteStream = _stream;

  unsigned char * compressedElementData = NULL;
  if(m_BinaryData && m_CompressedData && !strstr(m_ElementDataFileName, "%"))
    // compressed & !slice/file
    {
    int elementSize;
    MET_SizeOfType(m_ElementType, &elementSize);
    int elementNumberOfBytes = elementSize*m_ElementNumberOfChannels;

    if(_constElementData == NULL)
      {
      compressedElementData = MET_PerformCompression(
                                  (const unsigned char *)m_ElementData,
                                  m_Quantity * elementNumberOfBytes,
                                  & m_CompressedDataSize );
      }
    else
      {
      compressedElementData = MET_PerformCompression(
                                  (const unsigned char *)_constElementData,
                                  m_Quantity * elementNumberOfBytes,
                                  & m_CompressedDataSize );
      }
    }

  M_SetupWriteFields();

  M_Write();

  if(_writeElements)
    {
    if(m_BinaryData && m_CompressedData && !strstr(m_ElementDataFileName, "%"))
      // compressed & !slice/file
      {
      M_WriteElements(m_WriteStream,
                      compressedElementData,
                      m_CompressedDataSize);

      delete [] compressedElementData;
      m_CompressedDataSize = 0;
      }
    else
      {
      if(_constElementData == NULL)
        {
        M_WriteElements(m_WriteStream,
                        m_ElementData,
                        m_Quantity);
        }
      else
        {
        M_WriteElements(m_WriteStream,
                        _constElementData,
                        m_Quantity);
        }
      }
    }

  m_WriteStream = NULL;

  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
                         )
{   
  int i=0;
      
  if(_headName != NULL) 
    {
    FileName(_headName);
    }

  if(!_writeElements)
    {
    return false;
    }

  bool result = false;

  // Check if the file exists
  if(M_FileExists(_headName))
    {
    char* elementData = const_cast<char*>(static_cast<const char*>(_constElementData));
    if(elementData == NULL)
      {
      elementData = (char*)m_ElementData;
      }
     
    // Find the start of the data
    METAIO_STREAM::ifstream * readStream = new METAIO_STREAM::ifstream;
    readStream->open(m_FileName, METAIO_STREAM::ios::binary |
                                 METAIO_STREAM::ios::in);
    if(!MetaObject::ReadStream(m_NDims, readStream))
      {
      METAIO_STREAM::cerr << "MetaImage: Read: Cannot parse file"
                        << METAIO_STREAM::endl;
      delete readStream;
      return false;
      }

    InitializeEssential(m_NDims,
                        m_DimSize,
                        m_ElementSpacing,
                        m_ElementType,
                        m_ElementNumberOfChannels,
                        NULL, false); // no memory allocation
  
   
   std::string  filename = ElementDataFileName();
   unsigned long dataPos = 0;
   
   // local file
   if(filename == "LOCAL")
     {
     filename = m_FileName;
     dataPos = readStream->tellg();
     }
   
   readStream->close();
   delete readStream;

   // Write the region
   if(!M_FileExists(filename.c_str()))
     {
     char pathName[255];
     MET_GetFilePath(_headName, pathName);
     filename = pathName+filename; 
     }
   
   METAIO_STREAM::ofstream * tmpWriteStream = new METAIO_STREAM::ofstream;
   tmpWriteStream->open(filename.c_str(), METAIO_STREAM::ios::binary |
                                          METAIO_STREAM::ios::in |
                                          METAIO_STREAM::ios::out);
   
   if(!tmpWriteStream->is_open())
      {
      std::cerr << "Cannot open file: " << filename.c_str() << std::endl;
      delete tmpWriteStream;
      return false;
      }
    
    int* currentIndex = new int[m_NDims];
    for(i=0;i<m_NDims;i++)
      {
      currentIndex[i] = _indexMin[i];
      }
     
    if(!elementData)
      {
      std::cerr << "Element data is NULL" << std::endl;
      delete tmpWriteStream;
      return false;
      }
      
    int elementSize;
    MET_SizeOfType(m_ElementType, &elementSize);    
    int elementNumberOfBytes = elementSize*m_ElementNumberOfChannels;
                
    // This should probably go in a function 
    bool done = false;
    while(!done)
      {
      // Seek to the right position
      unsigned long seekpos = dataPos;
      for(i=0;i<m_NDims;i++)
        {
        seekpos += m_SubQuantity[i]*currentIndex[i]*elementNumberOfBytes;
        }
      
      // Add zeros to the image if the data is missing. 
      // Maybe this should refer to a function to avoid
      // taking all the memory like we did before.
      tmpWriteStream->seekp(0,METAIO_STREAM::ios::end);  
      size_t endfile = tmpWriteStream->tellp();
      
      long padding = seekpos-endfile;
      if(padding>0)
        {
        unsigned char* zerobytes = new unsigned char[padding];
        memset(zerobytes,0,padding);
        tmpWriteStream->write((const char*)zerobytes,padding);  
        delete [] zerobytes;
        }
          
      // Write the line
      tmpWriteStream->seekp(seekpos,METAIO_STREAM::ios::beg);  
      long bytesToWrite = _indexMax[0]-_indexMin[0];
      tmpWriteStream->write((const char*)elementData,bytesToWrite*elementNumberOfBytes);  
      
      elementData += bytesToWrite*elementNumberOfBytes;
        
      if(m_NDims>1)
        {
        currentIndex[1]++;
        }
      else
        {
        done = true;
        }
          
      // 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]++;
            }
          }
        }
      } // end writing line by line loop

    delete [] currentIndex;
    
    tmpWriteStream->close();
    delete tmpWriteStream;    
    }
  else // the file doesn't exist
    {
    bool userDataFileName = true;
    if(_dataName == NULL && strlen(m_ElementDataFileName)==0)
      {
      userDataFileName = false;
      int sPtr = 0;
      MET_GetFileSuffixPtr(m_FileName, &sPtr);
      if(!strcmp(&m_FileName[sPtr], "mha"))
{'fraction_non_alphanumeric': 0.1192017259978425, 'fraction_numerical': 0.005202714850773103, 'mean_word_length': 2.2092679408582763, 'pattern_counts': {'":': 6, '<': 499, '<?xml version=': 0, '>': 255, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 56, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3496825', 'n_tokens_mistral': 30199, 'n_tokens_neox': 28954, 'n_words': 5058}