/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * filename: m-matrix.c                                                    *
 *                                                                         *
 * UTIL C-source: Medical Image Conversion Utility                         *
 *                                                                         *
 * purpose      : CTI source for handling ECAT 6.4 files                   *
 *                                                                         *
 * project      : (X)MedCon by Erik Nolf                                   *
 *                                                                         *
 * Notes        : Source code addapted from CTI PET Systems, Inc.          *
 *                Original code 2.6 10/19/93  Copyright 1989-1993          *
 *                                                                         *
 *                Changed code for swapping & the use of our data types    *
 *                with machine independency as target                      *
 *                                                                         *
 *                Put "mdc" prefix on functions and structs to prevent     *
 *                naming conflicts with other tools based on CTI code      *
 *                                                                         *
 *                Added functions for ECAT 7 reading support               *
 *                                                                         *
 * Original CTI Authors listed:                                            *
 *   E. Phearson                                                           *
 *   L. Davis                                                              *
 *   Yaorong                                                               *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 */

/*
   Copyright (C) 1997-2026 by Erik Nolf

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any later
   version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
   Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   59 Place - Suite 330, Boston, MA 02111-1307, USA.  */

/****************************************************************************
                              H E A D E R S
****************************************************************************/

#include "m-depend.h"

#include <stdio.h>
#ifdef LIBMDC_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef LIBMDC_HAVE_STRING_H
#include <string.h>
#endif
#ifdef LIBMDC_HAVE_STRINGS_H
#ifndef _WIN32
#include <strings.h>
#endif
#endif

#include "medcon.h"

/***************************************************************************
                              D E F I N E S
***************************************************************************/

struct ExpMatDir {
        int matnum;
        int strtblk;
        int endblk;
        int matstat;
        float anatloc;
};

/****************************************************************************
                            F U N C T I O N S
****************************************************************************/


/*********************************************************/
FILE *mdc_mat_open(char *fname, char *fmode)
{
  FILE *fptr;

  fptr = fopen(fname, fmode);
  return (fptr);

}
/*********************************************************/
void mdc_mat_close(FILE *fptr)
{
  MdcCloseFile( fptr);
}
/*********************************************************/
Int32 mdc_mat_rblk(FILE *fptr, Int32 blkno, Uint8 *bufr, Int32 nblks)
{
  int r;
  fseeko( fptr, (off_t)(blkno-1)*MdcMatBLKSIZE, 0);
  r = fread( bufr, 1, (unsigned)(nblks*MdcMatBLKSIZE), fptr);
  if (r != (nblks*MdcMatBLKSIZE)) return(-1);

  return (0);
}
/*********************************************************/
Int32 mdc_mat_list(FILE *fptr, struct Mdc_MatDir mlist[], Int32 lmax)
{
  Int32 blk, num_entry, num_stored, i;
  Int32 nxtblk, matnum, strtblk, endblk, matstat;
  Int32 dirbufr[MdcMatBLKSIZE/4];
  Uint8 bytebufr[MdcMatBLKSIZE];

  blk = MdcMatFirstDirBlk;
  num_entry = 0;
  num_stored = 0;
  while(1) {
    mdc_mat_rblk( fptr, blk, bytebufr,1);
    if ( MdcHostBig() ) {
      MdcSWAB( (Uint8 *)bytebufr, (Uint8 *)dirbufr, MdcMatBLKSIZE);
      MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, MdcMatBLKSIZE/2);
    }else{
      memcpy(dirbufr, bytebufr, MdcMatBLKSIZE);
    }
    /* nfree  = dirbufr[0]; */
    nxtblk = dirbufr[1];
    /* prvblk = dirbufr[2]; */
    /* nused  = dirbufr[3]; */
    for (i=4; i<MdcMatBLKSIZE/4; i+=4)
    {  matnum  = dirbufr[i];
      strtblk = dirbufr[i+1];
      endblk  = dirbufr[i+2];
      matstat = dirbufr[i+3];
      if (matnum && num_stored < lmax)
      {  mlist[num_stored].matnum = matnum;
        mlist[num_stored].strtblk = strtblk;
        mlist[num_stored].endblk = endblk;
        mlist[num_stored].matstat = matstat;
        num_stored++;
      }
      if (matnum) num_entry++;
    }
    blk = nxtblk;
    if (blk == MdcMatFirstDirBlk) break;
  }

  return (num_entry);
}
/*********************************************************/
Int32 mdc_mat_list7(FILE *fptr, struct Mdc_MatDir mlist[], Int32 lmax)
{
  Int32 blk, num_entry, num_stored, i;
  Int32 nxtblk, matnum, strtblk, endblk, matstat;
  Int32 dirbufr[MdcMatBLKSIZE/4];
  Uint8 bytebufr[MdcMatBLKSIZE];

  blk = MdcMatFirstDirBlk;
  num_entry = 0;
  num_stored = 0;
  while(1) {
    mdc_mat_rblk( fptr, blk, bytebufr,1);
    if (! MdcHostBig() ) {
      MdcSWAB( (Uint8 *)bytebufr, (Uint8 *)dirbufr, MdcMatBLKSIZE);
      MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, MdcMatBLKSIZE/2);
    }else{
      memcpy(dirbufr, bytebufr, MdcMatBLKSIZE);
    }
    /* nfree  = dirbufr[0]; */
    nxtblk = dirbufr[1];
    /* prvblk = dirbufr[2]; */
    /* nused  = dirbufr[3]; */
    for (i=4; i<MdcMatBLKSIZE/4; i+=4)
    {  matnum  = dirbufr[i];
      strtblk = dirbufr[i+1];
      endblk  = dirbufr[i+2];
      matstat = dirbufr[i+3];
      if (matnum && num_stored < lmax)
      {  mlist[num_stored].matnum = matnum;
        mlist[num_stored].strtblk = strtblk;
        mlist[num_stored].endblk = endblk;
        mlist[num_stored].matstat = matstat;
        num_stored++;
      }
      if (matnum) num_entry++;
    }
    blk = nxtblk;
    if (blk == MdcMatFirstDirBlk) break;
  }

  return (num_entry);
}

/*********************************************************/
Int32 MdcSWAW(Uint16 from[], Uint16 to[], Int32 length)
{
  Uint16 temp;
  Int32 i;

  for (i=0;i<length; i+=2)
  {  temp = from[i+1];
    to[i+1]=from[i];
    to[i] = temp;
  }
  return 0;
}

/*********************************************************/
Int32 MdcSWAB(Uint8 from[], Uint8 to[], Int32 length)
{
  Uint16 temp;
  Int32 i;

  for (i=0;i<length; i+=2)
  {
    temp   = from[i+1];
    to[i+1]= from[i];
    to[i]  = temp;
  }
  return 0;
}


/********************************************************
  old version supporting 4096 planes, 256 planes, 4 data types
  Int32 mdc_mat_numcod( frame, plane, gate, data, bed)
  Int32 frame, plane, gate, data, bed;
  {
  return ((frame&0xFFF)|((bed&0xF)<<12)|((plane&0xFF)<<16)|
  ((gate&0x3F)<<24)|((data&0x3)<<30));
  }
 */
/********************************************************
  old version supporting 4096 planes, 256 planes, 4 data types
  mdc_mat_numdoc( matnum, matval)
  Int32 matnum; struct Mdc_Matval *matval;
  {
  matval->frame = matnum&0xFFF;
  matval->plane = (matnum>>16)&0xFF;
  matval->gate  = (matnum>>24)&0x3F;
  matval->data  = (matnum>>30)&0x3;
  matval->bed   = (matnum>>12)&0xF;
  return 0;
  }
 */
/********************************************************
  new version supporting 512 planes, 1024 planes, 8 data types */
Int32 mdc_mat_numcod(Int32 frame, Int32 plane, Int32 gate, Int32 data, Int32 bed)
{
  Int32 matnum8data16bed64gate1024plane512frame, loPlane, hiPlane = 0, loData, hiData = 0;

  hiPlane = (plane & 0x300);
  loPlane = (plane & 0xFF);
  loData = (data & 0x3);
  hiData = (data & 0x4);

  matnum8data16bed64gate1024plane512frame = ((frame & 0x1FF) | ((bed & 0xF) << 12) |
      ((loPlane << 16) | (hiPlane << 1)) | ((gate & 0x3F) << 24) | ((loData << 30) | (hiData << 9)));

  return (matnum8data16bed64gate1024plane512frame);
}
/********************************************************
  new version supporting 512 planes, 1024 planes, 8 data types */
Int32 mdc_mat_numdoc(Int32 matnum, struct Mdc_Matval *matval)
{
  Int32 loPlane, hiPlane = 0, loData, hiData = 0;

  matval->frame = matnum & 0x1FF;
  loPlane = (matnum >> 16) & 0xFF;
  hiPlane = (matnum >> 1) & 0x300;
  matval->plane = loPlane | hiPlane;
  matval->gate = (matnum >> 24) & 0x3F;
  loData = (matnum >> 30) & 0x3;
  hiData = (matnum >> 9) & 0x4;
  matval->data = loData | hiData;
  matval->bed = (matnum >> 12) & 0xF;
  return 0;
}
/*********************************************************/
Int32 mdc_mat_lookup(FILE *fptr, Int32 matnum, struct Mdc_MatDir *entry)
{

  Int32 blk, i;
  Int32 nxtblk, matnbr, strtblk, endblk, matstat;
  Int32 dirbufr[MdcMatBLKSIZE/4];
  Uint8 bytebufr[MdcMatBLKSIZE];

  blk = MdcMatFirstDirBlk;
  while(1) {
    mdc_mat_rblk( fptr, blk, bytebufr,1);
    if ( MdcHostBig() ) {
      MdcSWAB( (Uint8 *)bytebufr, (Uint8 *)dirbufr, MdcMatBLKSIZE);
      MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, MdcMatBLKSIZE/2);
    }else{
      memcpy(dirbufr, bytebufr, MdcMatBLKSIZE);
    }
    /* nfree  = dirbufr[0]; */
    nxtblk = dirbufr[1];
    /* prvblk = dirbufr[2]; */
    /* nused  = dirbufr[3]; */
    for (i=4; i<MdcMatBLKSIZE/4; i+=4)
    {  matnbr  = dirbufr[i];
      strtblk = dirbufr[i+1];
      endblk  = dirbufr[i+2];
      matstat = dirbufr[i+3];
      if (matnum == matnbr) {
        entry->matnum  = matnbr;
        entry->strtblk = strtblk;
        entry->endblk  = endblk;
        entry->matstat = matstat;
        return (1); }
    }
    blk = nxtblk;
    if (blk == MdcMatFirstDirBlk) break;
  }
  return (0);
}

/*********************************************************/
Int32 mdc_mat_lookup7(FILE *fptr, Int32 matnum, struct Mdc_MatDir *entry)
{

  Int32 blk, i;
  Int32 nxtblk, matnbr, strtblk, endblk, matstat;
  Int32 dirbufr[MdcMatBLKSIZE/4];
  Uint8 bytebufr[MdcMatBLKSIZE];

  blk = MdcMatFirstDirBlk;
  while(1) {
    mdc_mat_rblk( fptr, blk, bytebufr,1);
    if ( ! MdcHostBig() ) {
      MdcSWAB( (Uint8 *)bytebufr, (Uint8 *)dirbufr, MdcMatBLKSIZE);
      MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, MdcMatBLKSIZE/2);
    }else{
      memcpy(dirbufr, bytebufr, MdcMatBLKSIZE);
    }
    /* nfree  = dirbufr[0]; */
    nxtblk = dirbufr[1];
    /* prvblk = dirbufr[2]; */
    /* nused  = dirbufr[3]; */
    for (i=4; i<MdcMatBLKSIZE/4; i+=4)
    {  matnbr  = dirbufr[i];
      strtblk = dirbufr[i+1];
      endblk  = dirbufr[i+2];
      matstat = dirbufr[i+3];
      if (matnum == matnbr) {
        entry->matnum  = matnbr;
        entry->strtblk = strtblk;
        entry->endblk  = endblk;
        entry->matstat = matstat;
        return (1); }
    }
    blk = nxtblk;
    if (blk == MdcMatFirstDirBlk) break;
  }
  return (0);
}

/*********************************************************/
Int32 mdc_mat_read_main_header(FILE *fptr, Mdc_Main_header *h)
{
  Int16 b[256];
  char *bb;
  Int32 err, i;

  err = mdc_mat_rblk(fptr,1,(Uint8 *)b,1);/* read main header at block 1*/
  if (err) return(err);
  bb = (char *)b;
  strncpy( h->original_file_name, bb+28, 20);
  strncpy( h->node_id, bb+56, 10);
  strncpy( h->isotope_code, bb+78, 8);
  strncpy( h->radiopharmaceutical, bb+90, 32);
  strncpy( h->study_name, bb+162, 12);
  strncpy( h->patient_id, bb+174, 16);
  strncpy( h->patient_name, bb+190, 32);
  h->patient_sex = bb[222];
  strncpy( h->patient_age, bb+223, 10);
  strncpy( h->patient_height, bb+233, 10);
  strncpy( h->patient_weight, bb+243, 10);
  h->patient_dexterity = bb[253];
  strncpy( h->physician_name, bb+254, 32);
  strncpy( h->operator_name, bb+286, 32);
  strncpy( h->study_description, bb+318, 32);
  strncpy( h->facility_name, bb+356, 20);
  strncpy( h->user_process_code, bb+462, 10);
  if (MdcHostBig()) MdcSWAB( (Uint8 *)b, (Uint8 *)b, MdcMatBLKSIZE);
  h->sw_version = b[24];
  h->data_type = b[25];
  h->system_type = b[26];
  h->file_type = b[27];
  h->scan_start_day = b[33];
  h->scan_start_month = b[34];
  h->scan_start_year = b[35];
  h->scan_start_hour = b[36];
  h->scan_start_minute = b[37];
  h->scan_start_second = b[38];
  h->isotope_halflife=mdc_get_vax_float((Uint16 *)b, 43);
  h->gantry_tilt = mdc_get_vax_float((Uint16 *)b, 61);
  h->gantry_rotation = mdc_get_vax_float((Uint16 *)b, 63);
  h->bed_elevation = mdc_get_vax_float((Uint16 *)b, 65);
  h->rot_source_speed = b[67];
  h->wobble_speed = b[68];
  h->transm_source_type = b[69];
  h->axial_fov = mdc_get_vax_float((Uint16 *)b, 70);
  h->transaxial_fov = mdc_get_vax_float((Uint16 *)b, 72);
  h->transaxial_samp_mode = b[74];
  h->coin_samp_mode = b[75];
  h->axial_samp_mode = b[76];
  h->calibration_factor=mdc_get_vax_float((Uint16 *)b, 77);
  h->calibration_units = b[79];
  h->compression_code = b[80];
  h->acquisition_type = b[175];
  h->bed_type = b[176];
  h->septa_type = b[177];
  h->num_planes = b[188];
  h->num_frames = b[189];
  h->num_gates = b[190];
  h->num_bed_pos = b[191];
  h->init_bed_position=mdc_get_vax_float((Uint16 *)b, 192);
  for (i=0; i<15; i++)
    h->bed_offset[i] = mdc_get_vax_float((Uint16 *)b, 194+2*i);
  h->plane_separation = mdc_get_vax_float((Uint16 *)b, 224);
  h->lwr_sctr_thres = b[226];
  h->lwr_true_thres = b[227];
  h->upr_true_thres = b[228];
  h->collimator = mdc_get_vax_float((Uint16 *)b, 229);
  h->acquisition_mode = b[236];
  return (0);
}
/*********************************************************/
Int32 mdc_mat_read_matrix_data(FILE *fptr, Int32 blk, Int32 nblks, Int16 bufr[])
{
  Int32 error ;
  Mdc_Main_header h ;

  error = mdc_mat_read_main_header(fptr, &h) ;
  if(error)   return(error) ;
  error = mdc_mat_read_mat_data(fptr, blk, nblks,
      (Uint8 *)bufr, h.data_type) ;
  return (error);
}

/*********************************************************/
Int32 mdc_mat_read_main_header7(FILE *fptr, Mdc_Main_header7 *h)
{
  Int16 b[256];
  char *bb;
  Int32 err, i;

  err = mdc_mat_rblk(fptr,1,(Uint8 *)b,1);/* read main header at block 1*/
  if (err) return(err);
  bb = (char *)b;

  memcpy( h->magic_number        ,bb    ,14);
  memcpy( h->original_file_name  ,bb+14 ,32);
  memcpy(&h->sw_version          ,bb+46 , 2);  MdcSWAP(h->sw_version);
  memcpy(&h->system_type         ,bb+48 , 2);  MdcSWAP(h->system_type);
  memcpy(&h->file_type           ,bb+50 , 2);  MdcSWAP(h->file_type);
  memcpy( h->serial_number       ,bb+52 ,10);
  memcpy(&h->scan_start_time     ,bb+62 , 4);  MdcSWAP(h->scan_start_time);
  memcpy( h->isotope_name        ,bb+66 , 8);
  memcpy(&h->isotope_halflife    ,bb+74 , 4);  MdcSWAP(h->isotope_halflife);
  memcpy( h->radiopharmaceutical ,bb+78 ,32);
  memcpy(&h->gantry_tilt         ,bb+110, 4);  MdcSWAP(h->gantry_tilt);
  memcpy(&h->gantry_rotation     ,bb+114, 4);  MdcSWAP(h->gantry_rotation);
  memcpy(&h->bed_elevation       ,bb+118, 4);  MdcSWAP(h->bed_elevation);
  memcpy(&h->intrinsic_tilt      ,bb+122, 4);  MdcSWAP(h->intrinsic_tilt);
  memcpy(&h->wobble_speed        ,bb+126, 2);  MdcSWAP(h->wobble_speed);
  memcpy(&h->transm_source_type  ,bb+128, 2);  MdcSWAP(h->transm_source_type);
  memcpy(&h->distance_scanned    ,bb+130, 4);  MdcSWAP(h->distance_scanned);
  memcpy(&h->transaxial_fov      ,bb+134, 4);  MdcSWAP(h->transaxial_fov);
  memcpy(&h->angular_compression ,bb+138, 2);  MdcSWAP(h->angular_compression);
  memcpy(&h->coin_samp_mode      ,bb+140, 2);  MdcSWAP(h->coin_samp_mode);
  memcpy(&h->axial_samp_mode     ,bb+142, 2);  MdcSWAP(h->axial_samp_mode);
  memcpy(&h->ecat_calibration_factor,bb+144,4);
  MdcSWAP(h->ecat_calibration_factor);
  memcpy(&h->calibration_units   ,bb+148, 2);  MdcSWAP(h->calibration_units);
  memcpy(&h->calibration_units_label,bb+150,2);
  MdcSWAP(h->calibration_units_label);
  memcpy(&h->compression_code    ,bb+152, 2);  MdcSWAP(h->compression_code);
  memcpy( h->study_type          ,bb+154,12);
  memcpy( h->patient_id          ,bb+166,16);
  memcpy( h->patient_name        ,bb+182,32);
  memcpy( h->patient_sex         ,bb+214, 1);
  memcpy( h->patient_dexterity   ,bb+215, 1);
  memcpy(&h->patient_age         ,bb+216, 4);  MdcSWAP(h->patient_age);
  memcpy(&h->patient_height      ,bb+220, 4);  MdcSWAP(h->patient_height);
  memcpy(&h->patient_weight      ,bb+224, 4);  MdcSWAP(h->patient_weight);
  memcpy(&h->patient_birth_date  ,bb+228, 4);  MdcSWAP(h->patient_birth_date);
  memcpy( h->physician_name      ,bb+232,32);
  memcpy( h->operator_name       ,bb+264,32);
  memcpy( h->study_description   ,bb+296,32);
  memcpy(&h->acquisition_type    ,bb+328, 2);  MdcSWAP(h->acquisition_type);
  memcpy(&h->patient_orientation ,bb+330, 2);  MdcSWAP(h->patient_orientation);
  memcpy( h->facility_name       ,bb+332,20);
  memcpy(&h->num_planes          ,bb+352, 2);  MdcSWAP(h->num_planes);
  memcpy(&h->num_frames          ,bb+354, 2);  MdcSWAP(h->num_frames);
  memcpy(&h->num_gates           ,bb+356, 2);  MdcSWAP(h->num_gates);
  memcpy(&h->num_bed_pos         ,bb+358, 2);  MdcSWAP(h->num_bed_pos);
  memcpy(&h->init_bed_position   ,bb+360, 4);  MdcSWAP(h->init_bed_position);
  memcpy( h->bed_position        ,bb+364,60);
  for (i=0; i<15; i++) MdcSWAP(h->bed_position[i]);
  memcpy(&h->plane_separation    ,bb+424, 4);  MdcSWAP(h->plane_separation);
  memcpy(&h->lwr_sctr_thres      ,bb+428, 2);  MdcSWAP(h->lwr_sctr_thres);
  memcpy(&h->lwr_true_thres      ,bb+430, 2);  MdcSWAP(h->lwr_true_thres);
  memcpy(&h->upr_true_thres      ,bb+432, 2);  MdcSWAP(h->upr_true_thres);
  memcpy( h->user_process_code   ,bb+434,10);
  memcpy(&h->acquisition_mode    ,bb+444, 2);  MdcSWAP(h->acquisition_mode);
  memcpy(&h->bin_size            ,bb+446, 4);  MdcSWAP(h->bin_size);
  memcpy(&h->branching_fraction  ,bb+450, 4);  MdcSWAP(h->branching_fraction);
  memcpy(&h->dose_start_time     ,bb+454, 4);  MdcSWAP(h->dose_start_time);
  memcpy(&h->dosage              ,bb+458, 4);  MdcSWAP(h->dosage);
  memcpy(&h->well_counter_corr_factor,bb+462,4);
  MdcSWAP(h->well_counter_corr_factor);
  memcpy( h->data_units          ,bb+466,32);
  memcpy(&h->septa_state         ,bb+498, 2);  MdcSWAP(h->septa_state);
  memcpy( h->fill_cti            ,bb+500,12);

  return (0);
}

/*******************************************************************/
/*  May 90, PLuk - Now reads VAX or Sun matrix files.              */

Int32 mdc_mat_read_mat_data(FILE *fptr, Int32 strtblk, Int32 nblks, Uint8 *dptr, Int32 dtype)
{
  Int32 i, error;

  error = mdc_mat_rblk( fptr, strtblk, dptr, nblks);
  if (error) return(error);

  switch( dtype)
  {
    case 1: /* byte format...no translation necessary */
      break;
    case 2: /* Vax I*2 */
      if (MdcHostBig())
        MdcSWAB((Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      break;
    case 3: /* Vax I*4 */
      if (MdcHostBig()) {
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
        MdcSWAW( (Uint16 *)dptr, (Uint16 *)dptr, 256*nblks);
      }
      break;
    case 4: /* Vax R*4 */
      if (MdcHostBig())
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      for (i=0; i<nblks*128; i++)
        ((float *)dptr)[i] = mdc_get_vax_float((Uint16 *)dptr, i*2);
      break;
    case 5: /* IEEE R*4 */
      break;
    case 6: /* 68K I*2 */
      break;
    case 7: /* 68K I*4 */
      break;
    default:  /* something else...treat as Vax I*2 */
      if (MdcHostBig())
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      break;
  }
  return 0;
}

/*********************************************************/
Int32 mdc_mat_read_mat_data7(FILE *fptr, Int32 strtblk, Int32 nblks, Uint8 *dptr, Int32 dtype)
{
  Int32 i, error;

  error = mdc_mat_rblk( fptr, strtblk, dptr, nblks);
  if (error) return(error);

  switch( dtype)
  {
    case 1: /* byte format...no translation necessary */
      break;
    case 2: /* Vax I*2 */
      if (! MdcHostBig())
        MdcSWAB((Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      break;
    case 3: /* Vax I*4 */
      if (! MdcHostBig()) {
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
        MdcSWAW( (Uint16 *)dptr, (Uint16 *)dptr, 256*nblks);
      }
      break;
    case 4: /* Vax R*4 */
      if (! MdcHostBig())
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      for (i=0; i<nblks*128; i++)
        ((float *)dptr)[i] = mdc_get_vax_float( (Uint16 *)dptr, i/2);
      break;
    case 5: /* IEEE R*4 */
      break;
    case 6: /* 68K I*2 */
      break;
    case 7: /* 68K I*4 */
      break;
    default:  /* something else...treat as Vax I*2 */
      if (! MdcHostBig())
        MdcSWAB( (Uint8 *)dptr, (Uint8 *)dptr, 512*nblks);
      break;
  }
  return 0;
}

/*********************************************************/
Int32 mdc_mat_read_scan_subheader(FILE *fptr, Int32 blknum, Mdc_Scan_subheader *h)
{
  Int16 b[256];
  Int32 i, err;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)b, 1);
  if (err) return(err);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)b, (Uint8 *)b, MdcMatBLKSIZE);
  h->data_type = b[63];
  h->dimension_1 = b[66];
  h->dimension_2 = b[67];
  h->smoothing = b[68];
  h->processing_code = b[69];
  h->sample_distance = mdc_get_vax_float((Uint16 *)b, 73);
  h->isotope_halflife = mdc_get_vax_float((Uint16 *)b, 83);
  h->frame_duration_sec = b[85];
  h->gate_duration = mdc_get_vax_long((Uint16 *)b, 86);
  h->r_wave_offset = mdc_get_vax_long((Uint16 *)b, 88);
  h->scale_factor = mdc_get_vax_float((Uint16 *)b, 91);
  h->scan_min = b[96];
  h->scan_max = b[97];
  h->prompts = mdc_get_vax_long((Uint16 *)b, 98);
  h->delayed = mdc_get_vax_long((Uint16 *)b, 100);
  h->multiples = mdc_get_vax_long((Uint16 *)b, 102);
  h->net_trues = mdc_get_vax_long((Uint16 *)b, 104);
  for (i=0; i<16; i++)
  { h->cor_singles[i] = mdc_get_vax_float((Uint16 *)b, 158+2*i);
    h->uncor_singles[i] = mdc_get_vax_float((Uint16 *)b, 190+2*i);}
  h->tot_avg_cor = mdc_get_vax_float((Uint16 *)b, 222);
  h->tot_avg_uncor = mdc_get_vax_float((Uint16 *)b, 224);
  h->total_coin_rate = mdc_get_vax_long((Uint16 *)b, 226);
  h->frame_start_time = mdc_get_vax_long((Uint16 *)b, 228);
  h->frame_duration = mdc_get_vax_long((Uint16 *)b, 230);
  h->loss_correction_fctr = mdc_get_vax_float((Uint16 *)b, 232);
  for (i=0; i<8; i++)
    h->phy_planes[i] = mdc_get_vax_long((Uint16 *)b, 234+(2*i));
  return (0);
}
/*********************************************************/
Int32 mdc_mat_read_scan_subheader7(FILE *fptr, Int32 blknum, Mdc_Scan_subheader7 *h)
{
  Int16 b[256];
  Int32 err;
  char *bb;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)b, 1);
  if (err) return(err);
  bb = (char *)b;

  memcpy(&h->data_type             ,bb    , 2); MdcSWAP(h->data_type);
  memcpy(&h->num_dimensions        ,bb+  2, 2); MdcSWAP(h->num_dimensions);
  memcpy(&h->num_r_elements        ,bb+  4, 2); MdcSWAP(h->num_r_elements);
  memcpy(&h->num_angles            ,bb+  6, 2); MdcSWAP(h->num_angles);
  memcpy(&h->corrections_applied   ,bb+  8, 2); MdcSWAP(h->corrections_applied);
  memcpy(&h->num_z_elements        ,bb+ 10, 2); MdcSWAP(h->num_z_elements);
  memcpy(&h->ring_difference       ,bb+ 12, 2); MdcSWAP(h->ring_difference);
  memcpy(&h->x_resolution          ,bb+ 14, 4); MdcSWAP(h->x_resolution);
  memcpy(&h->y_resolution          ,bb+ 18, 4); MdcSWAP(h->y_resolution);
  memcpy(&h->z_resolution          ,bb+ 22, 4); MdcSWAP(h->z_resolution);
  memcpy(&h->w_resolution          ,bb+ 26, 4); MdcSWAP(h->w_resolution);

  return (0);
}
/*********************************************************/
Int32 mdc_mat_read_image_subheader(FILE *fptr, Int32 blknum, Mdc_Image_subheader *h)
{
  Int16 b[256];
  Int32 i, err;
  char *bb;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)b, 1);
  if (err) return(err);
  bb = (char *)b;
  strncpy( h->annotation, bb+420, 40);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)b, (Uint8 *)b, MdcMatBLKSIZE);
  h->data_type = b[63];
  h->num_dimensions = b[64];
  h->dimension_1 = b[66];
  h->dimension_2 = b[67];
  h->x_origin = mdc_get_vax_float((Uint16 *)b, 80);
  h->y_origin = mdc_get_vax_float((Uint16 *)b, 82);
  h->recon_scale = mdc_get_vax_float((Uint16 *)b, 84);
  h->quant_scale = mdc_get_vax_float((Uint16 *)b, 86);
  h->image_min = b[88];
  h->image_max = b[89];
  h->pixel_size = mdc_get_vax_float((Uint16 *)b, 92);
  h->slice_width = mdc_get_vax_float((Uint16 *)b, 94);
  h->frame_duration = mdc_get_vax_long((Uint16 *)b, 96);
  h->frame_start_time = mdc_get_vax_long((Uint16 *)b, 98);
  h->slice_location = b[100];
  h->recon_start_hour = b[101];
  h->recon_start_minute = b[102];
  h->recon_start_sec = b[103];
  h->gate_duration = mdc_get_vax_long((Uint16 *)b, 104);
  h->filter_code = b[118];
  h->scan_matrix_num = mdc_get_vax_long((Uint16 *)b, 119);
  h->norm_matrix_num = mdc_get_vax_long((Uint16 *)b, 121);
  h->atten_cor_matrix_num = mdc_get_vax_long((Uint16 *)b, 123);
  h->image_rotation = mdc_get_vax_float((Uint16 *)b, 148);
  h->plane_eff_corr_fctr = mdc_get_vax_float((Uint16 *)b, 150);
  h->decay_corr_fctr = mdc_get_vax_float((Uint16 *)b, 152);
  h->loss_corr_fctr = mdc_get_vax_float((Uint16 *)b, 154);
  h->intrinsic_tilt = mdc_get_vax_float((Uint16 *)b, 156);
  h->processing_code = b[188];
  h->quant_units = b[190];
  h->recon_start_day = b[191];
  h->recon_start_month = b[192];
  h->recon_start_year = b[193];
  h->ecat_calibration_fctr = mdc_get_vax_float((Uint16 *)b, 194);
  h->well_counter_cal_fctr = mdc_get_vax_float((Uint16 *)b, 196);
  for (i=0; i<6; i++)
    h->filter_params[i] = mdc_get_vax_float((Uint16 *)b, 198+2*i);
  return (0);
}
/*********************************************************/
Int32 mdc_mat_read_image_subheader7(FILE *fptr, Int32 blknum, Mdc_Image_subheader7 *h)
{
  Int16 b[256];
  Int32 i, err;
  char *bb;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)b, 1);
  if (err) return(err);
  bb = (char *)b;

  memcpy(&h->data_type              ,bb    , 2); MdcSWAP(h->data_type);
  memcpy(&h->num_dimensions         ,bb+  2, 2); MdcSWAP(h->num_dimensions);
  memcpy(&h->x_dimension            ,bb+  4, 2); MdcSWAP(h->x_dimension);
  memcpy(&h->y_dimension            ,bb+  6, 2); MdcSWAP(h->y_dimension);
  memcpy(&h->z_dimension            ,bb+  8, 2); MdcSWAP(h->z_dimension);
  memcpy(&h->x_offset               ,bb+ 10, 4); MdcSWAP(h->x_offset);
  memcpy(&h->y_offset               ,bb+ 14, 4); MdcSWAP(h->y_offset);
  memcpy(&h->z_offset               ,bb+ 18, 4); MdcSWAP(h->z_offset);
  memcpy(&h->recon_zoom             ,bb+ 22, 4); MdcSWAP(h->recon_zoom);
  memcpy(&h->scale_factor           ,bb+ 26, 4); MdcSWAP(h->scale_factor);
  memcpy(&h->image_min              ,bb+ 30, 2); MdcSWAP(h->image_min);
  memcpy(&h->image_max              ,bb+ 32, 2); MdcSWAP(h->image_max);
  memcpy(&h->x_pixel_size           ,bb+ 34, 4); MdcSWAP(h->x_pixel_size);
  memcpy(&h->y_pixel_size           ,bb+ 38, 4); MdcSWAP(h->y_pixel_size);
  memcpy(&h->z_pixel_size           ,bb+ 42, 4); MdcSWAP(h->z_pixel_size);
  memcpy(&h->frame_duration         ,bb+ 46, 4); MdcSWAP(h->frame_duration);
  memcpy(&h->frame_start_time       ,bb+ 50, 4); MdcSWAP(h->frame_start_time);
  memcpy(&h->filter_code            ,bb+ 54, 2); MdcSWAP(h->filter_code);
  memcpy(&h->x_resolution           ,bb+ 56, 4); MdcSWAP(h->x_resolution);
  memcpy(&h->y_resolution           ,bb+ 60, 4); MdcSWAP(h->y_resolution);
  memcpy(&h->z_resolution           ,bb+ 64, 4); MdcSWAP(h->z_resolution);
  memcpy(&h->num_r_elements         ,bb+ 68, 4); MdcSWAP(h->num_r_elements);
  memcpy(&h->num_angles             ,bb+ 72, 4); MdcSWAP(h->num_angles);
  memcpy(&h->z_rotation_angle       ,bb+ 76, 4); MdcSWAP(h->z_rotation_angle);
  memcpy(&h->decay_corr_fctr        ,bb+ 80, 4); MdcSWAP(h->decay_corr_fctr);
  memcpy(&h->processing_code        ,bb+ 84, 4); MdcSWAP(h->processing_code);
  memcpy(&h->gate_duration          ,bb+ 88, 4); MdcSWAP(h->gate_duration);
  memcpy(&h->r_wave_offset          ,bb+ 92, 4); MdcSWAP(h->r_wave_offset);
  memcpy(&h->num_accepted_beats     ,bb+ 96, 4); MdcSWAP(h->num_accepted_beats);
  memcpy(&h->filter_cutoff_frequency,bb+100, 4);
  MdcSWAP(h->filter_cutoff_frequency);
  memcpy(&h->filter_resolution      ,bb+104, 4); MdcSWAP(h->filter_resolution);
  memcpy(&h->filter_ramp_slope      ,bb+108, 4); MdcSWAP(h->filter_ramp_slope);
  memcpy(&h->filter_order           ,bb+112, 2); MdcSWAP(h->filter_order);
  memcpy(&h->filter_scatter_fraction,bb+114, 4);
  MdcSWAP(h->filter_scatter_fraction);
  memcpy(&h->filter_scatter_slope   ,bb+118, 4);
  MdcSWAP(h->filter_scatter_slope);
  memcpy( h->annotation             ,bb+122,40);
  memcpy(&h->mt_1_1                 ,bb+162, 4); MdcSWAP(h->mt_1_1);
  memcpy(&h->mt_1_2                 ,bb+166, 4); MdcSWAP(h->mt_1_2);
  memcpy(&h->mt_1_3                 ,bb+170, 4); MdcSWAP(h->mt_1_3);
  memcpy(&h->mt_2_1                 ,bb+174, 4); MdcSWAP(h->mt_2_1);
  memcpy(&h->mt_2_2                 ,bb+178, 4); MdcSWAP(h->mt_2_2);
  memcpy(&h->mt_2_3                 ,bb+182, 4); MdcSWAP(h->mt_2_3);
  memcpy(&h->mt_3_1                 ,bb+186, 4); MdcSWAP(h->mt_3_1);
  memcpy(&h->mt_3_2                 ,bb+190, 4); MdcSWAP(h->mt_3_2);
  memcpy(&h->mt_3_3                 ,bb+194, 4); MdcSWAP(h->mt_3_3);
  memcpy(&h->rfilter_cutoff         ,bb+198, 4); MdcSWAP(h->rfilter_cutoff);
  memcpy(&h->rfilter_resolution     ,bb+202, 4); MdcSWAP(h->rfilter_resolution);
  memcpy(&h->rfilter_code           ,bb+206, 2); MdcSWAP(h->rfilter_code);
  memcpy(&h->rfilter_order          ,bb+208, 2); MdcSWAP(h->rfilter_order);
  memcpy(&h->zfilter_cutoff         ,bb+210, 4); MdcSWAP(h->zfilter_cutoff);
  memcpy(&h->zfilter_resolution     ,bb+214, 4); MdcSWAP(h->zfilter_resolution);
  memcpy(&h->zfilter_code           ,bb+218, 2); MdcSWAP(h->zfilter_code);
  memcpy(&h->zfilter_order          ,bb+220, 2); MdcSWAP(h->zfilter_order);
  memcpy(&h->mt_1_4                 ,bb+222, 4); MdcSWAP(h->mt_1_4);
  memcpy(&h->mt_2_4                 ,bb+226, 4); MdcSWAP(h->mt_2_4);
  memcpy(&h->mt_3_4                 ,bb+230, 4); MdcSWAP(h->mt_3_4);
  memcpy(&h->scatter_type           ,bb+234, 2); MdcSWAP(h->scatter_type);
  memcpy(&h->recon_type             ,bb+236, 2); MdcSWAP(h->recon_type);
  memcpy(&h->recon_views            ,bb+238, 2); MdcSWAP(h->recon_views);
  memcpy( h->fill_cti               ,bb+240,174);
  for (i=0; i<87; i++) MdcSWAP(h->fill_cti[i]);
  memcpy( h->fill_user              ,bb+414,96);
  for (i=0; i<48; i++) MdcSWAP(h->fill_user[i]);

  return (0);
}


/*********************************************************/
float mdc_get_vax_float(Uint16 bufr[], Int32 off)
{
  Uint16 t1, t2;
  union {Uint32 t3; float t4;} test;

  if (bufr[off]==0 && bufr[off+1]==0) return(0.0);
  t1 = bufr[off] & 0x80ff;
  t2=(((bufr[off])&0x7f00)+0xff00)&0x7f00;
  test.t3 = (t1+t2)<<16;
  test.t3 =test.t3+bufr[off+1];
  return(test.t4);
}

/*********************************************************/
Int32 mdc_get_vax_long(Uint16 bufr[], Int32 off)
{
  return ((bufr[off+1]<<16)+bufr[off]);
}

Mdc_Mat_dir mdc_mat_read_dir(FILE *fptr, Uint8 *selector)
{ Int32 i, n, blk, nxtblk, ndblks, bufr[128];
  Mdc_Mat_dir dir;

  blk = MdcMatFirstDirBlk;
  nxtblk = 0;
  for (ndblks=0; nxtblk != MdcMatFirstDirBlk; ndblks++)
  {
    mdc_mat_rblk( fptr, blk, (Uint8 *)bufr, 1);
    if (MdcHostBig()) {
      MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 8);
      MdcSWAW( (Uint16 *)bufr, (Uint16 *)bufr, 4);
    }
    nxtblk = bufr[1];
    blk = nxtblk;
  }
  dir = (Mdc_Mat_dir) malloc( sizeof(struct mdc_matdir));
  dir->nmats = 0;
  dir->nmax = 31 * ndblks;
  dir->entry = (struct Mdc_MatDir *) malloc( 31*ndblks*sizeof( struct Mdc_MatDir));
  for (n=0, nxtblk=0, blk=MdcMatFirstDirBlk; nxtblk != MdcMatFirstDirBlk; blk = nxtblk)
  {
    mdc_mat_rblk( fptr, blk, (Uint8 *)bufr, 1);
    if (MdcHostBig()) {
      MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
      MdcSWAW( (Uint16 *)bufr, (Uint16 *)bufr, 256);
    }
    nxtblk = bufr[1];
    for (i=4; i<MdcMatBLKSIZE/4; n++)
    { dir->entry[n].matnum = bufr[i++];
      dir->entry[n].strtblk = bufr[i++];
      dir->entry[n].endblk = bufr[i++];
      dir->entry[n].matstat = bufr[i++];
      if (dir->entry[n].matnum != 0) dir->nmats++;
    }
  }
  return dir;
}

/*********************************************************/

Int32 mdc_mat_wblk(FILE *fptr, Int32 blkno, Uint8 *bufr, Int32 nblks)
{
  Int32 err;
  /* seek to position in file */
  err=fseeko( fptr, (off_t)(blkno-1)*MdcMatBLKSIZE, 0);
  if (err) return(-1);

  /* write matrix data */
  err=fwrite( bufr, 1, (unsigned)nblks*MdcMatBLKSIZE, fptr);
  if (err != nblks*MdcMatBLKSIZE) return(-1);
  if (ferror(fptr)) return (-1);
  return (0);
}

FILE *mdc_mat_create(char *fname, Mdc_Main_header *mhead)
{
  FILE *fptr;
  Int32 i, *bufr;
  fptr = mdc_mat_open( fname, "wb+");
  if (!fptr) return fptr;
  mdc_mat_write_main_header( fptr, mhead);
  bufr = (Int32 *) malloc( MdcMatBLKSIZE);
  for (i=0; i<128; i++)
    bufr[i] = 0;
  bufr[0] = 31;
  bufr[1] = 2;
  if (MdcHostBig()) {
    MdcSWAW( (Uint16 *)bufr, (Uint16 *)bufr, 256);
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
  }
  mdc_mat_wblk( fptr, MdcMatFirstDirBlk, (Uint8 *)bufr, 1);
  free( bufr);
  return (fptr);
}

Int32 mdc_mat_enter(FILE *fptr, Int32 matnum, Int32 nblks)
{

  Int32 dirblk, dirbufr[128+4], i, nxtblk, busy, oldsize;

  dirblk = MdcMatFirstDirBlk;
  mdc_mat_rblk( fptr, dirblk, (Uint8 *)dirbufr, 1);
  if (MdcHostBig()) {
    MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
    MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
  }
  busy = 1;
  while (busy) {
    nxtblk = dirblk+1;
    for (i=4; i<128; i+=4)
    {
      if (dirbufr[i] == 0)
      { busy = 0;
        break;
      }
      else if (dirbufr[i] == matnum)
      { oldsize = dirbufr[i+2]-dirbufr[i+1]+1;
        if (oldsize < nblks)
        { dirbufr[i] = 0xFFFFFFFF;
          if (MdcHostBig()) {
            MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
            MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
          }
          mdc_mat_wblk( fptr, dirblk, (Uint8 *)dirbufr, 1);
          if (MdcHostBig()) {
            MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
            MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
          }
          nxtblk = dirbufr[i+2]+1;
        }
        else
        { nxtblk = dirbufr[i+1];
          dirbufr[0]++;
          dirbufr[3]--;
          busy = 0;
          break;
        }
      }
      else nxtblk = dirbufr[i+2]+1;
    }
    if (!busy) break;
    if (dirbufr[1] != MdcMatFirstDirBlk)
    { dirblk = dirbufr[1];
      mdc_mat_rblk( fptr, dirblk, (Uint8 *)dirbufr, 1);
      if (MdcHostBig()) {
        MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
        MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
      }
    } else
    { dirbufr[1] = nxtblk;
      if (MdcHostBig()) {
        MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
        MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
      }
      mdc_mat_wblk( fptr, dirblk, (Uint8 *)dirbufr, 1);
      dirbufr[0] = 31;
      dirbufr[1] = MdcMatFirstDirBlk;
      dirbufr[2] = dirblk;
      dirbufr[3] = 0;
      dirblk = nxtblk;
      for (i=4; i<128; i++) dirbufr[i] = 0;
    }
  }

  dirbufr[i] = matnum;
  dirbufr[i+1] = nxtblk;
  dirbufr[i+2] = nxtblk + nblks;
  dirbufr[i+3] = 1;
  dirbufr[0]--;
  dirbufr[3]++;
  if (MdcHostBig()) {
    MdcSWAW( (Uint16 *)dirbufr, (Uint16 *)dirbufr, 256);
    MdcSWAB( (Uint8 *)dirbufr, (Uint8 *)dirbufr, 512);
  }
  mdc_mat_wblk( fptr, dirblk, (Uint8 *)dirbufr, 1);
  return (nxtblk);
}

Int32 mdc_mat_write_image(FILE *fptr, Int32 matnum, Mdc_Image_subheader *header, Uint16 *data, Int32 data_size)
{
  Int32 nxtblk, size, error ;

  size = (data_size+511)/512;
  nxtblk = mdc_mat_enter( fptr, matnum, size);
  mdc_mat_write_image_subheader( fptr, nxtblk, header);
  error = mdc_write_matrix_data(fptr, nxtblk+1, size,
      (Uint8 *)data,
      header->data_type) ;
  return(error) ;
}

Int32 mdc_mat_write_scan(FILE *fptr, Int32 matnum, Mdc_Scan_subheader *header, Uint16 *data, Int32 data_size)
{
  Int32 nxtblk, size, error ;

  size = (data_size+511)/512;
  nxtblk = mdc_mat_enter( fptr, matnum, size);
  mdc_mat_write_scan_subheader( fptr, nxtblk, header);
  error = mdc_write_matrix_data(fptr, nxtblk+1, size,
      (Uint8 *)data,
      header->data_type) ;
  return(error) ;
}

Int32 mdc_mat_write_attn(FILE *fptr, Int32 matnum, Mdc_Attn_subheader *header, float *data, Int32 data_size)
{
  Int32 nxtblk, size, error ;

  size = (data_size+511)/512;
  nxtblk = mdc_mat_enter( fptr, matnum, size);
  mdc_mat_write_attn_subheader( fptr, nxtblk, header);
  error = mdc_write_matrix_data (fptr, nxtblk+1, size,
      (Uint8 *)data,
      header->data_type) ;
  return(error) ;
}

Int32 mdc_mat_write_norm(FILE *fptr, Int32 matnum, Mdc_Norm_subheader *header, float *data, Int32 data_size)
{
  Int32 nxtblk, size, error ;

  size = (data_size+511)/512;
  nxtblk = mdc_mat_enter( fptr, matnum, size);
  mdc_mat_write_norm_subheader( fptr, nxtblk, header);
  error = mdc_write_matrix_data(fptr, nxtblk+1, size,
      (Uint8 *)data,
      header->data_type) ;
  return(error) ;
}

Int32 mdc_mat_write_idata(FILE *fptr, Int32 blk, Uint8 *data, Int32 size)
{
  Uint8 bufr[512];
  Int32 i, nbytes, nblks;

  nblks = (size+511)/512;
  for (i=0; i<nblks; i++)
  {
    nbytes = (size < 512) ? size: 512;
    memcpy( (Uint8 *)bufr, (Uint8 *)data, (unsigned)nbytes);
    if (MdcHostBig())
      MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
    mdc_mat_wblk( fptr, blk+i, (Uint8 *)bufr, 1);
    data += nbytes;
    size -= nbytes;
  }
  return 0;
}

Int32 mdc_mat_write_fdata(FILE *fptr, Int32 blk, float *data, Int32 size)
{
  float bufr[128];
  Int32 i, j, nvals, nblks;

  nblks = (size+511)/512;
  for (i=0; i<nblks; i++)
  {
    nvals = (size < 512) ? size/4: 512/4;
    for (j=0; j<nvals; j++)
      mdc_hostftovaxf( *data++, (Uint16 *)&bufr[j]);
    if (MdcHostBig())
      MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
    mdc_mat_wblk( fptr, blk+i, (Uint8 *)bufr, 1);
    size -= 4*nvals;
  }
  return 0;
}

Int32 mdc_matrix_selector(Int32 matnum, Int32 ranges[2][5])
{
  struct Mdc_Matval m;

  mdc_mat_numdoc( matnum, &m);
  if (ranges[0][0] != -1)
    if (m.frame < ranges[0][0] || m.frame > ranges[1][0]) return (0);
  if (ranges[0][1] != -1)
    if (m.plane < ranges[0][1] || m.plane > ranges[1][1]) return (0);
  if (ranges[0][2] != -1)
    if (m.gate  < ranges[0][2] || m.gate  > ranges[1][2]) return (0);
  if (ranges[0][3] != -1)
    if (m.data  < ranges[0][3] || m.data  > ranges[1][3]) return (0);
  if (ranges[0][4] != -1)
    if (m.bed   < ranges[0][4] || m.bed   > ranges[1][4]) return (0);
  return (matnum);
}

Int32 mdc_decode_selector(char *s1, Int32 ranges[2][5])
{ 
  char xword[16];
  Int32 i;

  mdc_fix_selector( s1, s1);
  for (i=0;i<5;i++) /* set all ranges to all (-1) */
  { ranges[0][i]=ranges[1][i]=-1;
    s1 = mdc_nex_word( s1, xword);
    if (xword[0] == '*') continue;
    else if (strchr(xword,':'))
      sscanf(xword,"%d:%d",&ranges[0][i],&ranges[1][i]);
    else
    { sscanf(xword,"%d",&ranges[0][i]);
      ranges[1][i]=ranges[0][i];
    };
  }
  return 0;
}

Int32 mdc_str_find(char *s1, char *s2)
{
  Int32 i, j, k;

  for (i=0;s1[i];i++) {
    for (j=i,k=0; s2[k]!='\0' && s1[j]==s2[k]; j++, k++) ;
    if (s2[k]=='\0') return (i);
  } return (-1);
}

Int32 mdc_str_replace(char *s1, char *s2, char *s3, char *s4)
{
  Int32 nf=0, n;

  *s1 = '\0';
  while (1)
  { if ((n=mdc_str_find(s2, s3))==-1)
    { strcat(s1, s2);
      return (nf);
    } else
    { strncat(s1, s2, (unsigned)n);
      strcat(s1, s4);
      s2+= n+strlen(s3);
      nf++;
    }
  }
}

Int32 mdc_string_replace(char *s1, char *s2, char *s3, char *s4)
{
  char temp[256];

  strcpy(temp, s2);
  while (mdc_str_replace(s1, temp, s3, s4) > 0)
    strcpy(temp, s1);
  return 0;
}

Int32 mdc_fix_selector(char *s1, char *s2)
{
  char temp[256];
  mdc_string_replace(temp, s2, "," , " ");
  mdc_string_replace(s1, temp, "..", ":");
  mdc_string_replace(temp, s1, ".", ":");
  mdc_string_replace(s1, temp, "-", ":");
  mdc_string_replace(temp, s1, "**", "*");
  mdc_string_replace(s1, temp, "  ", " ");
  mdc_string_replace(temp, s1, " :", ":");
  mdc_string_replace(s1, temp, ": ", ":");
  return 0;
}

char* mdc_nex_word(char *s, char *w)
{
  while (*s && *s!=' ') *w++=*s++;
  *w='\0';
  if (*s) s++;
  return (s);
}

/********************************************************/
/*  HOSTFTOVAXF                                         */
/********************************************************/

Int32 mdc_hostftovaxf(float f_orig, Uint16 number[])
{

  /* convert from host float to vax float */

  union {
    Uint16 t[2];
    float t4;
  } test ;
  Uint16 exp;

  number[0] = 0;
  number[1] = 0;

  test.t4 = f_orig;
  if (test.t4 == 0.0)
    return 0;

  if (!MdcHostBig()) MdcSWAW((Uint16 *)test.t, (Uint16 *)test.t,2);

  number[1] = test.t[1];

  exp = ((test.t[0] & 0x7f00) + 0x0100) & 0x7f00;
  test.t[0] = (test.t[0] & 0x80ff) + exp;

  number[0] = test.t[0];
  return 0;

}

/*********************************************************/
Int32 mdc_mat_write_main_header(FILE *fptr, Mdc_Main_header *header)
{
  Uint8 *bbufr;
  Int16 bufr[256];
  Int32 err,i;

  for (i=0; i<256; i++)
    bufr[i] = 0;
  bbufr = (Uint8 *) bufr;

  bufr[24] = header->sw_version;
  bufr[25] = header->data_type;
  bufr[26] = header->system_type;
  bufr[27] = header->file_type;
  bufr[33] = header->scan_start_day;
  bufr[34] = header->scan_start_month;
  bufr[35] = header->scan_start_year;
  bufr[36] = header->scan_start_hour;
  bufr[37] = header->scan_start_minute;
  bufr[38] = header->scan_start_second;
  mdc_hostftovaxf (header->isotope_halflife, (Uint16 *)&bufr[43]);
  mdc_hostftovaxf (header->gantry_tilt, (Uint16 *)&bufr[61]);
  mdc_hostftovaxf (header->gantry_rotation, (Uint16 *)&bufr[63]);
  mdc_hostftovaxf (header->bed_elevation, (Uint16 *)&bufr[65]);
  bufr[67] = header->rot_source_speed;
  bufr[68] = header->wobble_speed;
  bufr[69] = header->transm_source_type;
  mdc_hostftovaxf (header->axial_fov, (Uint16 *)&bufr[70]);
  mdc_hostftovaxf (header->transaxial_fov, (Uint16 *)&bufr[72]);
  bufr[74] = header->transaxial_samp_mode;
  bufr[75] = header->coin_samp_mode;
  bufr[76] = header->axial_samp_mode;
  mdc_hostftovaxf (header->calibration_factor,(Uint16 *)&bufr[77]);
  bufr[79] = header->calibration_units;
  bufr[80] = header->compression_code;
  bufr[175] = header->acquisition_type;
  bufr[176] = header->bed_type;
  bufr[177] = header->septa_type;
  bufr[188] = header->num_planes;
  bufr[189] = header->num_frames;
  bufr[190] = header->num_gates;
  bufr[191] = header->num_bed_pos;
  mdc_hostftovaxf (header->init_bed_position,(Uint16 *)&bufr[192]);
  for (i=0; i<15; i++)
  {
    mdc_hostftovaxf (header->bed_offset[i],(Uint16 *)&bufr[194+2*i]);
  }
  mdc_hostftovaxf (header->plane_separation,(Uint16 *)&bufr[224]);
  bufr[226] = header->lwr_sctr_thres;
  bufr[227] = header->lwr_true_thres;
  bufr[228] = header->upr_true_thres;
  mdc_hostftovaxf (header->collimator,(Uint16 *)&bufr[229]);
  bufr[236] = header->acquisition_mode;

  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, MdcMatBLKSIZE);

  memcpy( bbufr+28, header->original_file_name, 20);
  /* write the node_id - character string */
  memcpy( bbufr+56, header->node_id, 10);
  /* write the isotope code - char string */
  memcpy( bbufr+78, header->isotope_code, 8);
  /* write the radiopharmaceutical  - char string */
  memcpy( bbufr+90, header->radiopharmaceutical, 32);
  /* study_name - char string */
  memcpy( bbufr+162, header->study_name, 12);
  /* patient_id - char string */
  memcpy( bbufr+174, header->patient_id, 16);
  /* patient_name - char string */
  memcpy( bbufr+190, header->patient_name, 32);
  /* patient_sex - char */
  bbufr[222] = header->patient_sex;
  /* patient_age - char string */
  memcpy( bbufr+223, header->patient_age, 10);
  /* patient_height  - char string */
  memcpy( bbufr+233, header->patient_height, 10);
  /* patient_weight - char string */
  memcpy( bbufr+243, header->patient_weight, 10);
  /* patient_dexterity - char */
  bbufr[253] = header->patient_dexterity;
  /* physician_name - char string */
  memcpy( bbufr+254, header->physician_name, 32);
  /* operator_name - char string */
  memcpy( bbufr+286, header->operator_name, 32);
  /* study_description - char string */
  memcpy( bbufr+318, header->study_description, 32);
  /* facility_name */
  memcpy( bbufr+356, header->facility_name, 20);
  /* user_process_code  - char string */
  memcpy( bbufr+462, header->user_process_code, 10);

  err = mdc_mat_wblk( fptr, 1, (Uint8 *)bufr, 1); /* write main header at block 1 */
  if (err) return(err);

  return (0);
}

/*********************************************************/

Int32 mdc_mat_write_image_subheader(FILE *fptr, Int32 blknum, Mdc_Image_subheader *header)
{
  Uint8 *bbufr;
  Int16 bufr[256];
  Int32 i, err;

  for (i=0; i<256; i++)
    bufr[i] = 0;
  bbufr = (Uint8 *) bufr;
  /* transfer subheader information */
  bufr[63] = header->data_type;
  bufr[64] = header->num_dimensions;
  bufr[66] = header->dimension_1;
  bufr[67] = header->dimension_2;
  mdc_hostftovaxf(header->x_origin,(Uint16 *)&bufr[80]);
  mdc_hostftovaxf(header->y_origin,(Uint16 *)&bufr[82]);
  mdc_hostftovaxf(header->recon_scale,(Uint16 *)&bufr[84]);
  mdc_hostftovaxf(header->quant_scale,(Uint16 *)&bufr[86]);
  bufr[88] = header->image_min;
  bufr[89] = header->image_max;
  mdc_hostftovaxf(header->pixel_size,(Uint16 *)&bufr[92]);
  mdc_hostftovaxf(header->slice_width,(Uint16 *)&bufr[94]);
  mdc_hostltovaxl(header->frame_duration,(Uint16 *)&bufr[96]);
  mdc_hostltovaxl(header->frame_start_time,(Uint16 *)&bufr[98]);
  bufr[100] = header->slice_location;
  bufr[101] = header->recon_start_hour;
  bufr[102] = header->recon_start_minute;
  bufr[103] = header->recon_start_sec;
  mdc_hostltovaxl(header->gate_duration,(Uint16 *)&bufr[104]);
  bufr[118] = header->filter_code;
  mdc_hostltovaxl(header->scan_matrix_num,(Uint16 *)&bufr[119]);
  mdc_hostltovaxl(header->norm_matrix_num,(Uint16 *)&bufr[121]);
  mdc_hostltovaxl(header->atten_cor_matrix_num,(Uint16 *)&bufr[123]);
  mdc_hostftovaxf(header->image_rotation,(Uint16 *)&bufr[148]);
  mdc_hostftovaxf(header->plane_eff_corr_fctr,(Uint16 *)&bufr[150]);
  mdc_hostftovaxf(header->decay_corr_fctr,(Uint16 *)&bufr[152]);
  mdc_hostftovaxf(header->loss_corr_fctr,(Uint16 *)&bufr[154]);
  mdc_hostftovaxf(header->intrinsic_tilt,(Uint16 *)&bufr[156]);
  bufr[188] = header->processing_code;
  bufr[190] = header->quant_units;
  bufr[191] = header->recon_start_day;
  bufr[192] = header->recon_start_month;
  bufr[193] = header->recon_start_year;
  mdc_hostftovaxf(header->ecat_calibration_fctr,(Uint16 *)&bufr[194]);
  mdc_hostftovaxf(header->well_counter_cal_fctr,(Uint16 *)&bufr[196]);

  for (i=0; i<6; i++)
    mdc_hostftovaxf(header->filter_params[i],(Uint16 *)&bufr[198+2*i]);

  /* swap the bytes */
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, MdcMatBLKSIZE);

  strcpy ((char *)(bbufr+420), header->annotation);

  /* write to matrix file */
  err = mdc_mat_wblk( fptr, blknum, bbufr, 1);
  if (err) return(err);

  return(0);
}

/*********************************************************/
Int32 mdc_hostltovaxl(Int32 in, Uint16 out[2])
{

  out[0]=(in&0x0000FFFF);
  out[1]=(in&0xFFFF0000)>>16;

  return 0;
}

/*********************************************************/
Int32 mdc_mat_write_scan_subheader(FILE *fptr, Int32 blknum, Mdc_Scan_subheader *header)
{
  Int16 bufr[256];
  Int32 i, err;

  for (i=0; i<256; bufr[i++]=0);
  bufr[0] = 256;
  bufr[1] = 1;
  bufr[2] = 22;
  bufr[3] = -1;
  bufr[4] = 25;
  bufr[5] = 62;
  bufr[6] = 79;
  bufr[7] = 106;
  bufr[24] = 37;
  bufr[25] = -1;
  bufr[61] = 17;
  bufr[62] = -1;
  bufr[78] = 27;
  bufr[79] = -1;
  bufr[105] = 52;
  bufr[106] = -1;
  bufr[63] = header->data_type;
  bufr[66] = header->dimension_1;   /* x dimension */
  bufr[67] = header->dimension_2;   /* y_dimension */
  bufr[68] = header->smoothing;
  bufr[69] = header->processing_code;
  mdc_hostftovaxf(header->sample_distance,(Uint16 *)&bufr[73]);
  mdc_hostftovaxf(header->isotope_halflife,(Uint16 *)&bufr[83]);
  bufr[85] = header->frame_duration_sec;
  mdc_hostltovaxl(header->gate_duration,(Uint16 *)&bufr[86]);
  mdc_hostltovaxl(header->r_wave_offset,(Uint16 *)&bufr[88]);
  mdc_hostftovaxf(header->scale_factor,(Uint16 *)&bufr[91]);
  bufr[96] = header->scan_min;
  bufr[97] = header->scan_max;
  mdc_hostltovaxl(header->prompts,(Uint16 *)&bufr[98]);
  mdc_hostltovaxl(header->delayed,(Uint16 *)&bufr[100]);
  mdc_hostltovaxl(header->multiples,(Uint16 *)&bufr[102]);
  mdc_hostltovaxl(header->net_trues,(Uint16 *)&bufr[104]);
  for (i=0; i<16; i++)
  {
    mdc_hostftovaxf(header->cor_singles[i],(Uint16 *)&bufr[158+2*i]);
    mdc_hostftovaxf(header->uncor_singles[i],(Uint16 *)&bufr[190+2*i]);
  };
  mdc_hostftovaxf(header->tot_avg_cor,(Uint16 *)&bufr[222]);
  mdc_hostftovaxf(header->tot_avg_uncor,(Uint16 *)&bufr[224]);
  mdc_hostltovaxl(header->total_coin_rate,(Uint16 *)&bufr[226]);
  /* total coin rate */
  mdc_hostltovaxl(header->frame_start_time,(Uint16 *)&bufr[228]);
  mdc_hostltovaxl(header->frame_duration,(Uint16 *)&bufr[230]);
  mdc_hostftovaxf(header->loss_correction_fctr,(Uint16 *)&bufr[232]);
  for (i=0; i<8; i++)
    mdc_hostltovaxl(header->phy_planes[i],(Uint16 *)&bufr[234+2*i]);


  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, MdcMatBLKSIZE);

  err = mdc_mat_wblk( fptr, blknum, (Uint8 *)bufr, 1);
  return (err);
}

Int32 mdc_mat_write_attn_subheader(FILE *fptr, Int32 blknum, Mdc_Attn_subheader *header)
{
  Int16 bufr[256];
  Int32 i,err;

  for (i=0; i<256; bufr[i++]=0);
  bufr[0] = 256;
  bufr[1] = 1;
  bufr[2] = 22;
  bufr[3] = -1;
  bufr[4] = 25;
  bufr[5] = 62;
  bufr[6] = 79;
  bufr[7] = 106;
  bufr[24] = 37;
  bufr[25] = -1;
  bufr[61] = 17;
  bufr[62] = -1;
  bufr[78] = 27;
  bufr[79] = -1;
  bufr[105] = 52;
  bufr[106] = -1;
  bufr[63] = header->data_type;
  bufr[64] = header->attenuation_type;
  bufr[66] = header->dimension_1;
  bufr[67] = header->dimension_2;
  mdc_hostftovaxf( header->scale_factor,(Uint16 *)&bufr[91]);
  mdc_hostftovaxf( header->x_origin,(Uint16 *)&bufr[93]);
  mdc_hostftovaxf( header->y_origin,(Uint16 *)&bufr[95]);
  mdc_hostftovaxf( header->x_radius,(Uint16 *)&bufr[97]);
  mdc_hostftovaxf( header->y_radius,(Uint16 *)&bufr[99]);
  mdc_hostftovaxf( header->tilt_angle,(Uint16 *)&bufr[101]);
  mdc_hostftovaxf( header->attenuation_coeff,(Uint16 *)&bufr[103]);
  mdc_hostftovaxf( header->sample_distance,(Uint16 *)&bufr[105]);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
  err = mdc_mat_wblk( fptr, blknum, (Uint8 *)bufr, 1);
  return (err);
}

Int32 mdc_mat_write_norm_subheader(FILE *fptr, Int32 blknum, Mdc_Norm_subheader *header)
{
  Int16 bufr[256];
  Int32 i,err;

  for (i=0; i<256; bufr[i++]=0);
  bufr[0] = 256;
  bufr[1] = 1;
  bufr[2] = 22;
  bufr[3] = -1;
  bufr[4] = 25;
  bufr[5] = 62;
  bufr[6] = 79;
  bufr[7] = 106;
  bufr[24] = 37;
  bufr[25] = -1;
  bufr[61] = 17;
  bufr[62] = -1;
  bufr[78] = 27;
  bufr[79] = -1;
  bufr[105] = 52;
  bufr[106] = -1;
  bufr[63] = header->data_type;
  bufr[66] = header->dimension_1;
  bufr[67] = header->dimension_2;
  mdc_hostftovaxf( header->scale_factor,(Uint16 *)&bufr[91]);
  bufr[93] = header->norm_hour;
  bufr[94] = header->norm_minute;
  bufr[95] = header->norm_second;
  bufr[96] = header->norm_day;
  bufr[97] = header->norm_month;
  bufr[98] = header->norm_year;
  mdc_hostftovaxf( header->fov_source_width,(Uint16 *)&bufr[99]);
  mdc_hostftovaxf( header->ecat_calib_factor,(Uint16 *)&bufr[101]);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, 512);
  err = mdc_mat_wblk( fptr, blknum, (Uint8 *)bufr, 1);
  return (err);
}

Int32 mdc_mat_read_attn_subheader(FILE *fptr, Int32 blknum, Mdc_Attn_subheader *header)
{
  Int16 bufr[256];
  Int32 err;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)bufr, 1);
  if (err) return(err);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, MdcMatBLKSIZE);

  header->data_type = bufr[63];
  header->attenuation_type = bufr[64];
  header->dimension_1 = bufr[66];
  header->dimension_2 = bufr[67];
  header->scale_factor = mdc_get_vax_float((Uint16 *)bufr, 91);
  header->x_origin = mdc_get_vax_float((Uint16 *)bufr, 93);
  header->y_origin = mdc_get_vax_float((Uint16 *)bufr, 95);
  header->x_radius = mdc_get_vax_float((Uint16 *)bufr, 97);
  header->y_radius = mdc_get_vax_float((Uint16 *)bufr, 99);
  header->tilt_angle = mdc_get_vax_float((Uint16 *)bufr, 101);
  header->attenuation_coeff = mdc_get_vax_float((Uint16 *)bufr, 103);
  header->sample_distance = mdc_get_vax_float((Uint16 *)bufr, 105);
  return (0);
}

Int32 mdc_mat_read_attn_subheader7(FILE *fptr, Int32 blknum, Mdc_Attn_subheader7 *h)
{
  Int16 b[256];
  Int32 err, i;
  char *bb;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)b, 1);
  if (err) return(err);
  bb = (char *)b;

  memcpy(&h->data_type             ,bb    ,  2); MdcSWAP(h->data_type);
  memcpy(&h->num_dimensions        ,bb+  2,  2); MdcSWAP(h->num_dimensions);
  memcpy(&h->attenuation_type      ,bb+  4,  2); MdcSWAP(h->attenuation_type);
  memcpy(&h->num_r_elements        ,bb+  6,  2); MdcSWAP(h->num_r_elements);
  memcpy(&h->num_angles            ,bb+  8,  2); MdcSWAP(h->num_angles);
  memcpy(&h->num_z_elements        ,bb+ 10,  2); MdcSWAP(h->num_z_elements);
  memcpy(&h->ring_difference       ,bb+ 12,  2); MdcSWAP(h->ring_difference);
  memcpy(&h->x_resolution          ,bb+ 14,  4); MdcSWAP(h->x_resolution);
  memcpy(&h->y_resolution          ,bb+ 18,  4); MdcSWAP(h->y_resolution);
  memcpy(&h->z_resolution          ,bb+ 22,  4); MdcSWAP(h->z_resolution);
  memcpy(&h->w_resolution          ,bb+ 26,  4); MdcSWAP(h->w_resolution);
  memcpy(&h->scale_factor          ,bb+ 30,  4); MdcSWAP(h->scale_factor);
  memcpy(&h->x_offset              ,bb+ 34,  4); MdcSWAP(h->x_offset);
  memcpy(&h->y_offset              ,bb+ 38,  4); MdcSWAP(h->y_offset);
  memcpy(&h->x_radius              ,bb+ 42,  4); MdcSWAP(h->x_radius);
  memcpy(&h->y_radius              ,bb+ 46,  4); MdcSWAP(h->y_radius);
  memcpy(&h->tilt_angle            ,bb+ 50,  4); MdcSWAP(h->tilt_angle);
  memcpy(&h->attenuation_coeff     ,bb+ 54,  4); MdcSWAP(h->attenuation_coeff);
  memcpy(&h->attenuation_min       ,bb+ 58,  4); MdcSWAP(h->attenuation_min);
  memcpy(&h->attenuation_max       ,bb+ 62,  4); MdcSWAP(h->attenuation_max);
  memcpy(&h->skull_thickness       ,bb+ 66,  4); MdcSWAP(h->skull_thickness);
  memcpy(&h->num_xtra_atten_coeff  ,bb+ 70,  2);
  MdcSWAP(h->num_xtra_atten_coeff);
  memcpy(&h->xtra_atten_coeff      ,bb+ 72, 32);
  for (i=0; i<8;  i++) MdcSWAP(h->xtra_atten_coeff[i]);
  memcpy(&h->edge_finding_threshold,bb+104,  4);
  MdcSWAP(h->edge_finding_threshold);
  memcpy(&h->storage_order         ,bb+108,  2); MdcSWAP(h->storage_order);
  memcpy(&h->span                  ,bb+110,  2); MdcSWAP(h->span);
  memcpy(&h->z_elements            ,bb+112,128);
  for (i=0; i<64; i++) MdcSWAP(h->z_elements[i]);
  memcpy(&h->fill_unused           ,bb+240,172);
  for (i=0; i<86; i++) MdcSWAP(h->fill_unused[i]);
  memcpy(&h->fill_user             ,bb+412,100);
  for (i=0; i<50; i++) MdcSWAP(h->fill_user[i]);

  return (0);
}

Int32 mdc_mat_read_norm_subheader(FILE *fptr, Int32 blknum, Mdc_Norm_subheader *header)
{
  Int16 bufr[256];
  Int32 err;

  err = mdc_mat_rblk( fptr, blknum, (Uint8 *)bufr, 1);
  if (err) return(err);
  if (MdcHostBig())
    MdcSWAB( (Uint8 *)bufr, (Uint8 *)bufr, MdcMatBLKSIZE);

  header->data_type = bufr[63];
  header->dimension_1 = bufr[66];
  header->dimension_2 = bufr[67];
  header->scale_factor = mdc_get_vax_float((Uint16 *)bufr, 91);
  header->norm_hour = bufr[93];
  header->norm_minute = bufr[94];
  header->norm_second = bufr[95];
  header->norm_day = bufr[96];
  header->norm_month = bufr[97];
  header->norm_year = bufr[98];
  header->fov_source_width = mdc_get_vax_float((Uint16 *)bufr, 99);
  header->ecat_calib_factor = mdc_get_vax_float((Uint16 *)bufr, 101);
  return (0);
}

/* Following function was copied from CTI-source file 'matrix_extra.c' */
/* and slightly modified ...                                           */

Int32 mdc_write_matrix_data(FILE *fptr, Int32 strtblk, Int32 nblks, Uint8 *dptr, Int32 dtype)
{
  Int32 err;

  switch (dtype)
  {
    case 1: /* byte format...no
                 * translation necessary */
      err = mdc_mat_wblk(fptr, strtblk, dptr, nblks);
      break;
    case 2: /* Vax I*2 */
      err = mdc_mat_write_idata(fptr, strtblk, (Uint8 *)dptr, 512 * nblks);
      break;
    case 4: /* Vax R*4 */
      err = mdc_mat_write_fdata(fptr, strtblk, (float *)dptr, 512 * nblks);
      break;
    case 5: /* IEEE R*4 */
      err = mdc_mat_wblk(fptr, strtblk, dptr, nblks);
      break;
    case 6: /* 68K I*2 */
      err = mdc_mat_wblk(fptr, strtblk, dptr, nblks);
      break;
    case 7: /* 68K I*4 */
      err = mdc_mat_wblk(fptr, strtblk, dptr, nblks);
      break;
    default:  /* something
                 * else...treat as Vax
                 * I*2 */
      err = mdc_mat_write_idata(fptr, strtblk, (Uint8 *)dptr, 512 * nblks);
      break;
  }

  return (err);
}

/* code from mat_get_spec.c */
Int32 mdc_mat_get_spec (char *file, Int32 *num_frames, Int32 *num_planes, Int32 *num_gates, Int32 *num_bed)
{
  struct Mdc_MatDir matrixlist[5000];
  FILE *fptr;
  Int32 status, num_matrices, i;
  struct Mdc_Matval matnum;

  /* initialization */
  status = 0;
  *num_frames = 0;
  *num_planes = 0;
  *num_gates = 0;
  *num_bed = 0;

  /* open the specified file */
  fptr = mdc_mat_open (file, "r");
  if (fptr != NULL)
  {
    /* get the matrix entries */
    num_matrices = mdc_mat_list( fptr, matrixlist, 5000);

    for (i=0; i<num_matrices; i++)
    {
      mdc_mat_numdoc (matrixlist[i].matnum, &matnum);

      if (matnum.frame > *num_frames)
        (*num_frames)++;

      if (matnum.plane > *num_planes)
        (*num_planes)++;

      if (matnum.gate > *num_gates)
        (*num_gates)++;

      if (matnum.bed > *num_bed)
        (*num_bed)++;
    }

    /* bed is zero based in the matrix number, but all numbers returned */
    /* from this function will be one based                             */
    (*num_bed)++;
    mdc_mat_close (fptr);
  }
  else
    status = 1;

  return(status);
}

/* code from sort_order.c */

static int mdc_compare_anatloc(const void *vi, const void *vj)
{
  struct ExpMatDir *i, *j;

  i = (struct ExpMatDir *)vi;
  j = (struct ExpMatDir *)vj;

  if (i->anatloc < j->anatloc) return (-1);
  if (i->anatloc > j->anatloc) return (1);
  return (0);
}

/* matrix list by anatomical position */
void mdc_anatomical_sort (struct Mdc_MatDir matrix_list[], Int32 num_matrices, Mdc_Main_header *mhead, Int32 num_bed_pos)
{
  struct Mdc_Matval matval;
  Int32 i, plane, bed;
  float bed_pos[16], plane_separation;
  struct ExpMatDir exp_matlist[5000];

  bed_pos[0] = 0.0;
  for (i=1; i < num_bed_pos; i++)
    bed_pos[i] = mhead->bed_offset[i-1];

  plane_separation = mhead->plane_separation;

  /* if plane separation not filled in main header, use plane number to sort */
  if (plane_separation == 0.0) plane_separation = 1.0;

  for (i=0; i < num_matrices; i++)
  {
    mdc_mat_numdoc (matrix_list[i].matnum, &matval);
    plane = matval.plane;
    bed = matval.bed;
    exp_matlist[i].matnum = matrix_list[i].matnum;
    exp_matlist[i].strtblk = matrix_list[i].strtblk;
    exp_matlist[i].endblk = matrix_list[i].endblk;
    exp_matlist[i].matstat = matrix_list[i].matstat;
    exp_matlist[i].anatloc = bed_pos[bed]+(plane-1)*plane_separation;
  }

  qsort(exp_matlist,(unsigned)num_matrices
      ,sizeof(struct ExpMatDir)
      ,mdc_compare_anatloc);

  for (i=0; i < num_matrices; i++)
  {
    matrix_list[i].matnum = exp_matlist[i].matnum;
    matrix_list[i].strtblk = exp_matlist[i].strtblk;
    matrix_list[i].endblk = exp_matlist[i].endblk;
    matrix_list[i].matstat = exp_matlist[i].matstat;
  }
}

static int mdc_compmatdir(const void *vi, const void *vj)
{
  struct Mdc_MatDir *i, *j;

  i = (struct Mdc_MatDir *)vi;
  j = (struct Mdc_MatDir *)vj;

  return((i->matnum - j->matnum));
}


void mdc_matnum_sort(struct Mdc_MatDir mlist[], Int32 num_entry)
{
  qsort(mlist,(unsigned)num_entry, sizeof(struct Mdc_MatDir), mdc_compmatdir);
}

/* sort by planes varying first */
void mdc_plane_sort (struct Mdc_MatDir matrix_list[], Int32 num_matrices)
{
  struct Mdc_Matval matval;
  Int32 i, frame, plane, bed;
  struct ExpMatDir exp_matlist[5000];

  for (i=0; i < num_matrices; i++)
  {
    mdc_mat_numdoc (matrix_list[i].matnum, &matval);
    plane = matval.plane;
    frame = matval.frame;
    bed = matval.bed;
    exp_matlist[i].matnum = matrix_list[i].matnum;
    exp_matlist[i].strtblk = matrix_list[i].strtblk;
    exp_matlist[i].endblk = matrix_list[i].endblk;
    exp_matlist[i].matstat = matrix_list[i].matstat;
    exp_matlist[i].anatloc = (float)(frame*1000 + plane*10 + bed);
  }

  qsort (exp_matlist,(unsigned)num_matrices
      ,sizeof(struct ExpMatDir)
      ,mdc_compare_anatloc);

  for (i=0; i < num_matrices; i++)
  {
    matrix_list[i].matnum = exp_matlist[i].matnum;
    matrix_list[i].strtblk = exp_matlist[i].strtblk;
    matrix_list[i].endblk = exp_matlist[i].endblk;
    matrix_list[i].matstat = exp_matlist[i].matstat;
  }

}
