changeset 2099:be6c75043ba4

Initial checkin
author bert <bert>
date Thu, 12 May 2005 21:15:29 +0000
parents 33ba63961f07
children c9273cf62803
files conversion/Acr_nema/Makefile.am conversion/Acr_nema/acr_io.c conversion/Acr_nema/acr_nema.h conversion/Acr_nema/acr_test.c conversion/Acr_nema/autogen.sh conversion/Acr_nema/configure.ac conversion/Acr_nema/copy_acr_nema.c conversion/Acr_nema/dicom.txt conversion/Acr_nema/dicom_client_routines.c conversion/Acr_nema/dicom_network.c conversion/Acr_nema/dicom_test.c conversion/Acr_nema/dump_acr_nema.c conversion/Acr_nema/element.c conversion/Acr_nema/extract_acr_nema.c conversion/Acr_nema/file_io.c conversion/Acr_nema/globals.c conversion/Acr_nema/group.c conversion/Acr_nema/message.c conversion/Acr_nema/read_acr_nema.c conversion/Acr_nema/sample_dicom_client.c conversion/Acr_nema/value_repr.c conversion/dcm2mnc/acr_element_defs.h conversion/dcm2mnc/dcm2mnc.c conversion/dcm2mnc/dcm2mnc.h conversion/dcm2mnc/dicom_read.c conversion/dcm2mnc/dicom_read.h conversion/dcm2mnc/dicom_to_minc.c conversion/dcm2mnc/dicom_to_minc.h conversion/dcm2mnc/ext_element_defs.h conversion/dcm2mnc/gems_element_defs.h conversion/dcm2mnc/minc_file.c conversion/dcm2mnc/minc_file.h conversion/dcm2mnc/numaris.txt conversion/dcm2mnc/pms_element_defs.h conversion/dcm2mnc/progress.c conversion/dcm2mnc/progress.h conversion/dcm2mnc/siemens_header_defs.h conversion/dcm2mnc/siemens_header_table.h conversion/dcm2mnc/siemens_to_dicom.c conversion/dcm2mnc/siemens_to_dicom.h conversion/dcm2mnc/spi_element_defs.h conversion/dcm2mnc/string_to_filename.c conversion/dcm2mnc/string_to_filename.h
diffstat 43 files changed, 9863 insertions(+), 399 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/conversion/Acr_nema/Makefile.am
@@ -0,0 +1,60 @@
+AUTOMAKE_OPTIONS = check-news
+
+# This is the only header installed in the "includedir"
+#
+include_HEADERS = acr_nema.h
+
+# All other headers are installed in this subdirectory.
+#
+include_acr_nemadir = $(includedir)/acr_nema
+
+include_acr_nema_HEADERS = \
+	acr_nema/acr_io.h \
+	acr_nema/dicom_client_routines.h \
+	acr_nema/dicom_network.h \
+	acr_nema/element.h \
+	acr_nema/file_io.h \
+	acr_nema/group.h \
+	acr_nema/message.h \
+	acr_nema/value_repr.h
+
+# Libraries which must be built and installed.
+#
+lib_LTLIBRARIES = libacr_nema.la
+
+bin_PROGRAMS = \
+	acr_test \
+	dump_acr_nema \
+	extract_acr_nema \
+	read_acr_nema \
+	dicom_test \
+	copy_acr_nema
+
+noinst_PROGRAMS = \
+	sample_dicom_client
+
+LDADD = libacr_nema.la
+
+acr_test_SOURCES = acr_test.c
+
+dump_acr_nema_SOURCES = dump_acr_nema.c
+
+extract_acr_nema_SOURCES = extract_acr_nema.c
+
+read_acr_nema_SOURCES = read_acr_nema.c
+
+dicom_test_SOURCES = dicom_test.c
+
+copy_acr_nema_SOURCES = copy_acr_nema.c
+
+libacr_nema_la_LDFLAGS = -version-info 1:0:1
+libacr_nema_la_SOURCES = \
+	acr_io.c \
+	dicom_client_routines.c \
+	dicom_network.c \
+	element.c \
+	file_io.c \
+	globals.c \
+	group.c \
+	message.c \
+	value_repr.c
--- a/conversion/Acr_nema/acr_io.c
+++ b/conversion/Acr_nema/acr_io.c
@@ -7,7 +7,19 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: acr_io.c,v $
- * Revision 6.5  2000-08-16 15:53:46  neelin
+ * Revision 6.7.2.1  2005-05-12 21:15:29  bert
+ * Initial checkin
+ *
+ * Revision 6.7  2005/03/04 00:15:14  bert
+ * Lose public and private keywords; change acr_read_one_element to assume implicit VR format for special sequence delimiters (group 0xfffe)
+ *
+ * Revision 6.6  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.5  2000/08/16 15:53:46  neelin
  * Added VR type UN (unknown) which has a length field similar to OB.
  *
  * Revision 6.4  2000/05/01 17:54:02  neelin
@@ -96,7 +108,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <limits.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Define constants */
@@ -104,9 +115,6 @@
 #  define TRUE 1
 #  define FALSE 0
 #endif
-#ifndef private
-#  define private static
-#endif
 
 #define ACR_BYTE_ORDER_DEFAULT ACR_LITTLE_ENDIAN
 
@@ -120,13 +128,13 @@
 } *Data_Info;
 
 /* Private functions */
-private int test_vr(char vr_to_test[2], char *vr_list[]);
-private int is_sequence_vr(char vr_to_test[2]);
-private int is_special_vr(char vr_to_test[2]);
-private Data_Info get_data_info(Acr_File *afp);
-private void invert_values(Acr_byte_order byte_order, 
-                           long nvals, size_t value_size, 
-                           void *input_value, void *mach_value);
+static int test_vr(char vr_to_test[2], char *vr_list[]);
+static int is_sequence_vr(char vr_to_test[2]);
+static int is_special_vr(char vr_to_test[2]);
+static Data_Info get_data_info(Acr_File *afp);
+static void invert_values(Acr_byte_order byte_order, 
+                          long nvals, size_t value_size, 
+                          void *input_value, void *mach_value);
 
 /* Macros */
 #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
@@ -146,7 +154,7 @@
 @CREATED    : January 29, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private int test_vr(char vr_to_test[2], char *vr_list[])
+static int test_vr(char vr_to_test[2], char *vr_list[])
 {
    int found_special, i;
 
@@ -162,13 +170,13 @@
    return found_special;
 }
 
-private int is_sequence_vr(char vr_to_test[2])
+static int is_sequence_vr(char vr_to_test[2])
 {
    static char *sequence_vrs[] = {"SQ", NULL};
    return test_vr(vr_to_test, sequence_vrs);
 }
 
-private int is_special_vr(char vr_to_test[2])
+static int is_special_vr(char vr_to_test[2])
 {
    static char *special_vrs[] = {"OB", "OW", "SQ", "UN", NULL};
    return test_vr(vr_to_test, special_vrs);
@@ -187,7 +195,7 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private Data_Info get_data_info(Acr_File *afp)
+static Data_Info get_data_info(Acr_File *afp)
 {
    Data_Info data_info;
 
@@ -215,8 +223,7 @@
 @CREATED    : January 29, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_byte_order(Acr_File *afp, 
-                               Acr_byte_order byte_order)
+void acr_set_byte_order(Acr_File *afp, Acr_byte_order byte_order)
 {
    Data_Info data_info;
 
@@ -240,7 +247,7 @@
 @CREATED    : January 29, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_byte_order acr_get_byte_order(Acr_File *afp)
+Acr_byte_order acr_get_byte_order(Acr_File *afp)
 {
    Data_Info data_info;
 
@@ -264,7 +271,7 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_machine_byte_order(void)
+int acr_get_machine_byte_order(void)
 {
    int dummy = 1;
    char *ptr = (char *) &dummy;
@@ -296,7 +303,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : January 29, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public int acr_need_invert(Acr_byte_order byte_order)
+int acr_need_invert(Acr_byte_order byte_order)
 {
    return (acr_get_machine_byte_order() != byte_order);
 }
@@ -314,8 +321,7 @@
 @CREATED    : January 29, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_vr_encoding(Acr_File *afp, 
-                                Acr_VR_encoding_type vr_encoding)
+void acr_set_vr_encoding(Acr_File *afp, Acr_VR_encoding_type vr_encoding)
 {
    Data_Info data_info;
 
@@ -339,7 +345,7 @@
 @CREATED    : January 29, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_VR_encoding_type acr_get_vr_encoding(Acr_File *afp)
+Acr_VR_encoding_type acr_get_vr_encoding(Acr_File *afp)
 {
    Data_Info data_info;
 
@@ -366,8 +372,7 @@
 @CREATED    : April 28, 2000 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_ignore_errors(Acr_File *afp, 
-                                  int ignore_nonfatal_protocol_errors)
+void acr_set_ignore_errors(Acr_File *afp, int ignore_nonfatal_protocol_errors)
 {
    Data_Info data_info;
 
@@ -392,7 +397,7 @@
 @CREATED    : April 28, 2000 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_ignore_protocol_errors(Acr_File *afp)
+int acr_ignore_protocol_errors(Acr_File *afp)
 {
    Data_Info data_info;
 
@@ -420,8 +425,8 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_reverse_byte_order(long nvals, size_t value_size, 
-                                   void *input_values, void *output_values)
+void acr_reverse_byte_order(long nvals, size_t value_size, 
+                            void *input_values, void *output_values)
 {
    long i, jlow, jhigh;
    char *ptr1, *ptr2, v0, v1;
@@ -464,9 +469,9 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void invert_values(Acr_byte_order byte_order, 
-                           long nvals, size_t value_size, 
-                           void *input_value, void *mach_value)
+static void invert_values(Acr_byte_order byte_order, 
+                          long nvals, size_t value_size, 
+                          void *input_value, void *mach_value)
 {
    long i;
    char *ptr1, *ptr2;
@@ -499,9 +504,9 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_get_short(Acr_byte_order byte_order, 
-                          long nvals, void *input_value, 
-                          unsigned short *mach_value)
+void acr_get_short(Acr_byte_order byte_order, 
+                   long nvals, void *input_value, 
+                   unsigned short *mach_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_SHORT, 
                  input_value, mach_value);
@@ -522,8 +527,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_get_long(Acr_byte_order byte_order, 
-                         long nvals, void *input_value, long *mach_value)
+void acr_get_long(Acr_byte_order byte_order, 
+                  long nvals, void *input_value, long *mach_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_LONG, 
                  input_value, mach_value);
@@ -545,8 +550,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_get_float(Acr_byte_order byte_order, 
-                          long nvals, void *input_value, float *mach_value)
+void acr_get_float(Acr_byte_order byte_order, 
+                   long nvals, void *input_value, float *mach_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_FLOAT, 
                  input_value, mach_value);
@@ -568,8 +573,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_get_double(Acr_byte_order byte_order, 
-                           long nvals, void *input_value, double *mach_value)
+void acr_get_double(Acr_byte_order byte_order, 
+                    long nvals, void *input_value, double *mach_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_DOUBLE, 
                  input_value, mach_value);
@@ -590,9 +595,9 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_put_short(Acr_byte_order byte_order, 
-                          long nvals, unsigned short *mach_value, 
-                          void *output_value)
+void acr_put_short(Acr_byte_order byte_order, 
+                   long nvals, unsigned short *mach_value, 
+                   void *output_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_SHORT, 
                  mach_value, output_value);
@@ -613,8 +618,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_put_long(Acr_byte_order byte_order, 
-                         long nvals, long *mach_value, void *output_value)
+void acr_put_long(Acr_byte_order byte_order, 
+                  long nvals, long *mach_value, void *output_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_LONG, 
                  mach_value, output_value);
@@ -635,8 +640,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_put_float(Acr_byte_order byte_order, 
-                          long nvals, float *mach_value, void *output_value)
+void acr_put_float(Acr_byte_order byte_order, 
+                   long nvals, float *mach_value, void *output_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_FLOAT, 
                  mach_value, output_value);
@@ -657,8 +662,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_put_double(Acr_byte_order byte_order, 
-                           long nvals, double *mach_value, void *output_value)
+void acr_put_double(Acr_byte_order byte_order, 
+                    long nvals, double *mach_value, void *output_value)
 {
    invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_DOUBLE, 
                  mach_value, output_value);
@@ -681,7 +686,7 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_skip_input_data(Acr_File *afp, long nbytes_to_skip)
+Acr_Status acr_skip_input_data(Acr_File *afp, long nbytes_to_skip)
 {
    long i;
    int ch;
@@ -727,8 +732,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_read_buffer(Acr_File *afp, unsigned char buffer[],
-                                  long nbytes_to_read, long *nbytes_read)
+Acr_Status acr_read_buffer(Acr_File *afp, unsigned char buffer[],
+                           long nbytes_to_read, long *nbytes_read)
 {
    long i;
    int ch;
@@ -775,8 +780,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_unget_buffer(Acr_File *afp, unsigned char buffer[],
-                                   long nbytes_to_unget)
+Acr_Status acr_unget_buffer(Acr_File *afp, unsigned char buffer[],
+                            long nbytes_to_unget)
 {
    long i;
 
@@ -810,8 +815,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_write_buffer(Acr_File *afp, unsigned char buffer[],
-                                   long nbytes_to_write, long *nbytes_written)
+Acr_Status acr_write_buffer(Acr_File *afp, unsigned char buffer[],
+                            long nbytes_to_write, long *nbytes_written)
 {
    long i;
 
@@ -856,7 +861,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : January 29, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_test_byte_order(Acr_File *afp)
+Acr_Status acr_test_byte_order(Acr_File *afp)
 {
    long buflen;
    unsigned char buffer[2*ACR_SIZEOF_SHORT+ACR_SIZEOF_LONG];
@@ -917,6 +922,9 @@
                        &data_length2);
       }
       if (data_length2 >= ACR_TEST_MAX2) {
+         /* If we get here, we have completely failed to make sense of 
+          * the byte ordering.
+          */
          acr_set_byte_order(afp, old_byte_order);
       }
    }
@@ -938,7 +946,7 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_copy_file_encoding(Acr_File *afp1, Acr_File *afp2)
+void acr_copy_file_encoding(Acr_File *afp1, Acr_File *afp2)
 {
    acr_set_byte_order(afp2, acr_get_byte_order(afp1));
    acr_set_vr_encoding(afp2, acr_get_vr_encoding(afp1));
@@ -957,8 +965,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_element_header_size(char vr_name[2], 
-                                       Acr_VR_encoding_type vr_encoding)
+int acr_get_element_header_size(char vr_name[2], 
+                                Acr_VR_encoding_type vr_encoding)
 {
    int length;
 
@@ -985,8 +993,8 @@
 @CREATED    : February 5, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_peek_at_next_element_id(Acr_File *afp,
-                                              int *group_id, int *element_id)
+Acr_Status acr_peek_at_next_element_id(Acr_File *afp,
+                                       int *group_id, int *element_id)
 {
    long buflen;
    unsigned char buffer[2*ACR_SIZEOF_SHORT];
@@ -1042,10 +1050,10 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : January 29, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_read_one_element(Acr_File *afp,
-                                       int *group_id, int *element_id,
-                                       char vr_name[],
-                                       long *data_length, char **data_pointer)
+Acr_Status acr_read_one_element(Acr_File *afp,
+                                int *group_id, int *element_id,
+                                char vr_name[],
+                                long *data_length, char **data_pointer)
 {
    long buflen;
    unsigned char buffer[2*ACR_SIZEOF_SHORT+ACR_SIZEOF_LONG];
@@ -1071,7 +1079,7 @@
    *element_id = elid;
 
    /* Look for VR and length of data */
-   if (acr_get_vr_encoding(afp) == ACR_IMPLICIT_VR) {
+   if (grpid == ACR_ITEM_GROUP || acr_get_vr_encoding(afp) == ACR_IMPLICIT_VR) {
       vr_name[0] = '\0';
       vr_name[1] = '\0';
       acr_get_long(byte_order, 1, &buffer[offset], (long *) &datalen);
@@ -1148,10 +1156,10 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : January 29, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_write_one_element(Acr_File *afp,
-                                        int group_id, int element_id,
-                                        char vr_name[],
-                                        long data_length, char *data_pointer)
+Acr_Status acr_write_one_element(Acr_File *afp,
+                                 int group_id, int element_id,
+                                 char vr_name[],
+                                 long data_length, char *data_pointer)
 {
    long buflen;
    unsigned char buffer[2*ACR_SIZEOF_SHORT+2*ACR_SIZEOF_LONG];
@@ -1233,7 +1241,7 @@
 @CREATED    : July 10, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_status_string(Acr_Status status)
+char *acr_status_string(Acr_Status status)
 {
    char *status_string;
 
--- a/conversion/Acr_nema/acr_nema.h
+++ b/conversion/Acr_nema/acr_nema.h
@@ -6,7 +6,19 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: acr_nema.h,v $
- * Revision 6.1  1999-10-29 17:51:50  neelin
+ * Revision 6.3.2.1  2005-05-12 21:15:48  bert
+ * Initial checkin
+ *
+ * Revision 6.3  2005/02/16 19:22:32  bert
+ * Autoconfiscation
+ *
+ * Revision 6.2  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.1  1999/10/29 17:51:50  neelin
  * Fixed Log keyword
  *
  * Revision 6.0  1997/09/12 13:23:59  neelin
@@ -75,11 +87,17 @@
 #endif
 
 /* Include files */
-#include <file_io.h>
-#include <acr_io.h>
-#include <value_repr.h>
-#include <element.h>
-#include <group.h>
-#include <message.h>
-#include <dicom_network.h>
-#include <dicom_client_routines.h>
+#include <acr_nema/file_io.h>
+#include <acr_nema/acr_io.h>
+#include <acr_nema/value_repr.h>
+#include <acr_nema/element.h>
+#include <acr_nema/group.h>
+#include <acr_nema/message.h>
+#include <acr_nema/dicom_network.h>
+#include <acr_nema/dicom_client_routines.h>
+
+/* these are pinched from minc_def.h */
+#define MALLOC(size) ((void *) malloc(size))
+#define FREE(ptr) free(ptr)
+#define REALLOC(ptr, size) ((void *) realloc(ptr, size))
+#define CALLOC(nelem, elsize) ((void *) calloc(nelem, elsize))
--- a/conversion/Acr_nema/acr_test.c
+++ b/conversion/Acr_nema/acr_test.c
@@ -5,7 +5,6 @@
 #define GLOBAL_ELEMENT_DEFINITION
 
 #include <acr_nema.h>
-#include <minc_def.h>
 
 GLOBAL_ELEMENT(ACR_Recognition_code, 0x0, 0x10, LO);
 GLOBAL_ELEMENT(Shadow_Recognition_code, 0x1, 0x10, LO);
new file mode 100755
--- /dev/null
+++ b/conversion/Acr_nema/autogen.sh
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+cat <<EOF
+Messages of the following type may be safely ignored.
+Any other diagnostics may be a sign of trouble.  
+Let us know if something goes wrong.
+
+    automake: configure.in: installing [...]
+    warning: AC_TRY_RUN called without default to allow cross compiling
+
+
+
+EOF
+
+aclocal
+autoheader
+libtoolize --automake
+automake --add-missing
+autoconf
+
new file mode 100644
--- /dev/null
+++ b/conversion/Acr_nema/configure.ac
@@ -0,0 +1,24 @@
+AC_INIT
+AC_CONFIG_SRCDIR([./acr_nema.h])
+AC_CONFIG_AUX_DIR(ac_config_aux)
+AM_INIT_AUTOMAKE(acr_nema, 1.0)
+AC_CONFIG_HEADERS([config.h])
+
+AC_REVISION($Revision: 6.1.2.1 $)
+
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+AM_PROG_CC_C_O
+AC_PROG_RANLIB
+
+AC_DISABLE_SHARED
+AC_PROG_LIBTOOL
+
+AC_CONFIG_FILES([
+Makefile 
+])
+AC_OUTPUT
+
+
--- a/conversion/Acr_nema/copy_acr_nema.c
+++ b/conversion/Acr_nema/copy_acr_nema.c
@@ -7,7 +7,16 @@
 @CREATED    : November 9, 2000 (Peter Neelin)
 @MODIFIED   : 
  * $Log: copy_acr_nema.c,v $
- * Revision 6.4  2001-11-08 14:17:05  neelin
+ * Revision 6.5.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.5  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.4  2001/11/08 14:17:05  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -39,7 +48,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 #define UNKNOWN_VR_ENCODING ((Acr_VR_encoding_type) -1)
new file mode 100644
--- /dev/null
+++ b/conversion/Acr_nema/dicom.txt
@@ -0,0 +1,490 @@
+// Group 8
+Specific_Character_Set                  0x0008  0x0005  CS
+Image_Type                              0x0008  0x0008  CS
+Instance_Creation_Date                  0x0008  0x0012  DA
+Instance_Creation_Time                  0x0008  0x0013  TM
+Instance_Creator_UID                    0x0008  0x0014  UI
+SOP_Class_UID                           0x0008  0x0016  UI
+SOP_Instance_UID                        0x0008  0x0018  UI
+Related_General_SOP_Class_UID           0x0008  0x001A  UI
+Original_Specialized_SOP_Class_UID      0x0008  0x001B  UI
+Study_Date                              0x0008  0x0020  DA
+Series_Date                             0x0008  0x0021  DA
+Acquisition_Date                        0x0008  0x0022  DA
+Content_Date                            0x0008  0x0023  DA
+Overlay_Date                            0x0008  0x0024  DA
+Curve_Date                              0x0008  0x0025  DA
+Acquisition_Datetime                    0x0008  0x002A  DT
+Study_Time                              0x0008  0x0030  TM
+Series_Time                             0x0008  0x0031  TM
+Acquisition_Time                        0x0008  0x0032  TM
+Content_Time                            0x0008  0x0033  TM
+Overlay_Time                            0x0008  0x0034  TM
+Curve_Time                              0x0008  0x0035  TM
+Data_Set_Type                           0x0008  0x0040  RET
+Data_Set_Subtype                        0x0008  0x0041  RET
+Nuclear_Medicine_Series_Type            0x0008  0x0042  CS
+Accession_Number                        0x0008  0x0050  SH
+Query/Retrieve_Level                    0x0008  0x0052  CS
+Retrieve_AE_Title                       0x0008  0x0054  AE
+Instance_Availability                   0x0008  0x0056  CS
+Failed_SOP_Instance_UID_List            0x0008  0x0058  UI
+Modality                                0x0008  0x0060  CS
+Modalities_in_Study                     0x0008  0x0061  CS
+SOP_Classes_in_Study                    0x0008  0x0062  UI
+Conversion_Type                         0x0008  0x0064  CS
+Presentation_Intent_Type                0x0008  0x0068  CS
+Manufacturer                            0x0008  0x0070  LO
+Institution_Name                        0x0008  0x0080  LO
+Institution_Address                     0x0008  0x0081  ST
+Institution_Code_Sequence               0x0008  0x0082  SQ
+Referring_Physician's_Name              0x0008  0x0090  PN
+Referring_Physician's_Address           0x0008  0x0092  ST
+Referring_Physician's_Telephone_Numbers 0x0008  0x0094  SH
+Referring_Physician_Identificiation_Sequence 0x0008 0x0096 SQ
+Code_Value                              0x0008  0x0100  SH
+Coding_Scheme_Designator                0x0008  0x0102  SH
+Coding_Scheme_Version                   0x0008  0x0103  SH
+Code_Meaning                            0x0008  0x0104  LO
+Mapping_Resource                        0x0008  0x0105  CS
+Context_Group_Version                   0x0008  0x0106  DT
+Context_Group_Local_Version             0x0008  0x0107  DT
+// Some omitted fields
+Timezone_Offset_From_UTC                0x0008  0x0201  SH
+// Some fields omitted here...
+Network_ID                              0x0008  0x1000  RET
+Station_Name                            0x0008  0x1010  SH
+Study_Description                       0x0008  0x1030  LO
+Procedure_Code_Sequence                 0x0008  0x1032  SQ
+Series_Description                      0x0008  0x103E  LO
+Institutional_Department_Name           0x0008  0x1040  LO
+Physician(s)_of_Record                  0x0008  0x1048  PN
+Physician(s)_of_Record_Identification_Sequence 0x0008 0x1049 SQ
+Performing_Physician's_Name             0x0008  0x1050  PN
+Performing_Physician_Idntification_Sequence 0x0008 0x1052 SQ
+Name_of_Physician(s)_Reading_Study      0x0008  0x1060  PN
+Physician(s)_Reading_Study_Identification_Sequence 0x0008 0x1062 SQ
+Operator's_Name                         0x0008  0x1070  PN
+Operator_Identification_Sequence        0x0008  0x1072  SQ
+Admitting_Diagnoses_Description         0x0008  0x1080  LO
+Admitting_Diagnoses_Code_Sequence       0x0008  0x1084  SQ
+Manufacturer's_Model_Name               0x0008  0x1090  LO
+Referenced_Results_Sequence             0x0008  0x1100  SQ
+Referenced_Study_Sequence               0x0008  0x1110  SQ
+Referenced_Performed_Procedure_Step_Sequence 0x0008 0x1111 SQ
+Referenced_Series_Sequence              0x0008  0x1115  SQ
+Referenced_Patient_Sequence             0x0008  0x1120  SQ
+Referenced_Visit_Sequence               0x0008  0x1125  SQ
+Referenced_Overlay_Sequence             0x0008  0x1130  SQ
+Referenced_Waveform_Sequence            0x0008  0x113A  SQ
+Referenced_Image_Sequence               0x0008  0x1140  SQ
+Referenced_Curve_Sequence               0x0008  0x1145  SQ
+Referenced_Instance_Sequence            0x0008  0x114A  SQ
+Referenced_SOP_Class_UID                0x0008  0x1150  UI
+Referenced_SOP_Instance_UID             0x0008  0x1155  UI
+Referenced_SOP_Sequence                 0x0008  0x1199  SQ
+Anatomic_Region_Sequence                0x0008  0x2218  SQ
+Frame_Type                              0x0008  0x9007  CS
+Referenced_Raw_Data_Sequence            0x0008  0x9121  SQ
+Pixel_Presentation                      0x0008  0x9205  CS
+Volumetric_Properties                   0x0008  0x9206  CS
+Volume_Based_Calculation_Technique      0x0008  0x9207  CS
+Complex_Image_Component                 0x0008  0x9208  CS
+Acquisition_Contrast                    0x0008  0x9209  CS
+// More stuff omitted..
+// Group 10
+Patient's_Name                          0x0010  0x0010  PN
+Patient_ID                              0x0010  0x0020  LO
+Issuer_of_Patient_ID                    0x0010  0x0021  LO
+Patient's_Birth_Date                    0x0010  0x0030  DA
+Patient's_Birth_Time                    0x0010  0x0032  TM
+Patient's_Sex                           0x0010  0x0040  CS
+Patient's_Insurance_Plan_Code_Sequence  0x0010  0x0050  SQ
+Patient's_Primary_Language_Code_Sequence 0x0010 0x0101  SQ
+Patient's_Primary_Language_Code_Modifier_Sequence 0x0010 0x0102 SQ
+Other_Patient_IDs                       0x0010  0x1000  LO
+Other_Patient_Names                     0x0010  0x1001  PN
+Patient's_Birth_Name                    0x0010  0x1005  PN
+Patient's_Age                           0x0010  0x1010  AS
+Patient's_Size                          0x0010  0x1020  DS
+Patient's_Weight                        0x0010  0x1030  DS
+Patient's_Address                       0x0010  0x1040  LO
+Insurance_Plan_Identification           0x0010  0x1050  RET
+Patient's_Mother's_Birth_Name           0x0010  0x1060  PN
+Military_Rank                           0x0010  0x1080  LO
+Branch_of_Service                       0x0010  0x1081  LO
+Medical_Record_Locator                  0x0010  0x1090  LO
+Medical_Alerts                          0x0010  0x2000  LO
+Contrast_Allergies                      0x0010  0x2110  LO
+Country_of_Residence                    0x0010  0x2150  LO
+Region_of_Residence                     0x0010  0x2152  LO
+Patient's_Telephone_Numbers             0x0010  0x2154  SH
+Ethnic_Group                            0x0010  0x2160  SH
+Occupation                              0x0010  0x2180  SH
+Smoking_Status                          0x0010  0x21A0  CS
+Additional_Patient_History              0x0010  0x21B0  LT
+Pregnancy_Status                        0x0010  0x21C0  US
+Last_Menstrual_Date                     0x0010  0x21D0  DA
+Patient's_Religious_Preference          0x0010  0x21F0  LO
+Patient_Comments                        0x0010  0x4000  LT
+// Group 12 (clinical trial)
+Clinical_Trial_Sponsor_Name             0x0012  0x0010  LO
+Clinical_Trial_Protocol_ID              0x0012  0x0020  LO
+Clinical_Trial_Protocol_Name            0x0012  0x0021  LO
+Clinical_Trial_Site_ID                  0x0012  0x0030  LO
+Clinical_Trial_Site_Name                0x0012  0x0031  LO
+Clinical_Trial_Subject_ID               0x0012  0x0040  LO
+Clinical_Trial_Subject_Reading_ID       0x0012  0x0042  LO
+Clinical_Trial_Time_Point_ID            0x0012  0x0050  LO
+Clinical_Trial_Time_Point_Description   0x0012  0x0051  ST
+Clinical_Trial_Coordinating_Center_Name 0x0012  0x0060  LO
+// Group 18
+Contrast/Bolus_Agent                    0x0018  0x0010  LO
+Contrast/Bolus_Agent_Sequence           0x0018  0x0012  SQ
+Contrast/Bolus_Agent_Administration_Route_Sequence 0x0018 0x0014 SQ
+Body_Part_Examined                      0x0018  0x0015  CS
+Scanning_Sequence                       0x0018  0x0020  CS
+Sequence_Variant                        0x0018  0x0021  CS
+Scan_Options                            0x0018  0x0022  CS
+MR_Acquisition_Type                     0x0018  0x0023  CS
+Sequence_Name                           0x0018  0x0024  SH
+Angio_Flag                              0x0018  0x0025  CS
+Intervention_Drug_Information_Sequence  0x0018  0x0026  SQ
+Intervention_Drug_Stop_Time             0x0018  0x0027  TM
+Intervention_Drug_Dose                  0x0018  0x0028  DS
+Intervention_Drug_Sequence              0x0018  0x0029  SQ
+Additional_Drug_Sequence                0x0018  0x002A  SQ
+Radionuclide                            0x0018  0x0030  LO
+Radiopharmaceutical                     0x0018  0x0031  LO
+Energy_Window_Centerline                0x0018  0x0032  DS
+Energy_Window_Total_Width               0x0018  0x0033  DS
+Intervention_Drug_Name                  0x0018  0x0034  LO
+Intervention_Drug_Start_Time            0x0018  0x0035  TM
+Intervention_Sequence                   0x0018  0x0036  SQ
+Therapy_Type                            0x0018  0x0037  CS
+Intervention_Status                     0x0018  0x0038  CS
+Therapy_Description                     0x0018  0x0039  CS
+Intervention_Description                0x0018  0x003A  ST
+Cine_Rate                               0x0018  0x0040  IS
+Slice_Thickness                         0x0018  0x0050  DS
+KVP                                     0x0018  0x0060  DS
+Counts_Accumulated                      0x0018  0x0070  IS
+Acquisition_Termination_Condition       0x0018  0x0071  CS
+Effective_Duration                      0x0018  0x0072  DS
+Acquisition_Start_Condition             0x0018  0x0073  CS
+Acquisition_Start_Condition_Data        0x0018  0x0074  IS
+Acquisition_Termination_Condition_Data  0x0018  0x0075  IS
+Repetition_Time                         0x0018  0x0080  DS
+Echo_Time                               0x0018  0x0081  DS
+Inversion_Time                          0x0018  0x0082  DS
+Number_of_Averages                      0x0018  0x0083  DS
+Imaging_Frequency                       0x0018  0x0084  DS
+Imaged_Nucleus                          0x0018  0x0085  SH
+Echo_Number(s)                          0x0018  0x0086  IS
+Magnetic_Field_Strength                 0x0018  0x0087  DS
+Spacing_Between_Slices                  0x0018  0x0088  DS
+Number_of_Phase_Encoding_Steps          0x0018  0x0089  IS
+Data_Collection_Diameter                0x0018  0x0090  DS
+Echo_Train_Length                       0x0018  0x0091  IS
+Percent_Sampling                        0x0018  0x0093  DS
+Percent_Phase_Field_of_View             0x0018  0x0094  DS
+Pixel_Bandwidth                         0x0018  0x0095  DS
+Device_Serial_Number                    0x0018  0x1000  LO
+Plate_ID                                0x0018  0x1004  LO
+Secondary_Capture_Device_ID             0x0018  0x1010  LO
+Hardcopy_Creation_Device_ID             0x0018  0x1011  LO
+Date_of_Secondary_Capture               0x0018  0x1012  DA
+Time_of_Secondary_Capture               0x0018  0x1014  TM
+Secondary_Capture_Device_Manufacturer   0x0018  0x1016  LO
+Hardcopy_Device_Manufacturer            0x0018  0x1017  LO
+Secondary_Capture_Device_Manufacturer's_Model_name 0x0018 0x1018 LO
+Secondary_Capture_Device_Software_Version(s) 0x0018 0x1019 LO
+Hardcopy_Device_Software_Version        0x0018  0x101A  LO
+Hardcopy_Device_Manufacturer's_Model_Name 0x0018 0x101B LO
+Software_Version                        0x0018  0x1020  LO
+Video_Image_Format_Acquired             0x0018  0x1022  SH
+Digital_Image_Format_Acquired           0x0018  0x1022  LO
+Protocol_Name                           0x0018  0x1030  LO
+Contrast/Bolus_Route                    0x0018  0x1040  LO
+Contrast/Bolus_Volume                   0x0018  0x1041  DS
+Contrast/Bolus_Start_Time               0x0018  0x1042  TM
+Contrast/Bolus_Stop_Time                0x0018  0x1043  TM
+Contrast/Bolus_Total_Dose               0x0018  0x1044  DS
+Syringe_Counts                          0x0018  0x1045  IS
+Contrast_Flow_Rate                      0x0018  0x1046  DS
+Contrast_Flow_Duration                  0x0018  0x1047  DS
+Contrast/Bolus_Ingredient               0x0018  0x1048  CS
+Contrast/Bolus_Ingredient_Concentration 0x0018  0x1049  DS
+Spatial_Resolution                      0x0018  0x1050  DS
+Trigger_Time                            0x0018  0x1060  DS
+Trigger_Source_or_Type                  0x0018  0x1061  LO
+Nominal_Interval                        0x0018  0x1062  IS
+Frame_Time                              0x0018  0x1063  DS
+Framing_Type                            0x0018  0x1064  LO
+Frame_Time_Vector                       0x0018  0x1065  DS
+Frame_Delay                             0x0018  0x1066  DS
+Image_Trigger_Delay                     0x0018  0x1067  DS
+Multiplex_Group_Time_Offset             0x0018  0x1068  DS
+Trigger_Time_Offset                     0x0018  0x1069  DS
+Synchronization_Trigger                 0x0018  0x106A  CS
+// ...
+Cardiac_Number_of_Images                0x0018  0x1090  IS
+// ...
+Date_of_Last_Calibration                0x0018  0x1200  DA
+Time_of_Last_Calibration                0x0018  0x1201  TM
+Convolution_Kernel                      0x0018  0x1210  SH
+Upper/Lower_Pixel_Values                0x0018  0x1240  RET
+Actual_Frame_Duration                   0x0018  0x1242  IS
+Count_Rate                              0x0018  0x1243  IS
+Preferred_Playback_Sequencing           0x0018  0x1244  US
+Receive_Coil_Name                       0x0018  0x1250  SH
+Transmit_Coil_Name                      0x0018  0x1251  SH
+Plate_Type                              0x0018  0x1260  SH
+Phosphor_Type                           0x0018  0x1261  LO
+Scan_Velocity                           0x0018  0x1300  DS
+Whole_Body_Technique                    0x0018  0x1301  CS
+Scan_Length                             0x0018  0x1302  IS
+Acquisition_Matrix                      0x0018  0x1310  US
+In-plane_Phase_Encoding_Direction       0x0018  0x1312  CS
+Flip_Angle                              0x0018  0x1314  DS
+Variable_Flip_Angle_Flag                0x0018  0x1315  CS
+SAR                                     0x0018  0x1316  DS
+dB/dt                                   0x0018  0x1318  DS
+Acquisition_Device_Processing_Description 0x0018 0x1400 LO
+Acquisition_Device_Processing_Code      0x0018  0x1401  LO
+Cassette_Orientation                    0x0018  0x1402  CS
+Cassette_Size                           0x0018  0x1403  CS
+Exposures_on_Plate                      0x0018  0x1404  US
+//...
+Patient_Position                        0x0018  0x5100  CS
+//...
+Content_Qualification                   0x0018  0x9004  CS
+//...
+Applicable_Safety_Standard_Agency       0x0018  0x9174  CS
+MR_Image_Frame_Type_Sequence            0x0018  0x9226  SQ
+
+Contrast/Bolus_Agent_Number             0x0018  0x9337  US
+Contrast/Bolus_Ingredient_Code_Sequence 0x0018  0x9338  SQ
+Contrast/Bolus_Usage_Sequence           0x0018  0x9341  SQ
+Contrast/Bolus_Agent_Administered       0x0018  0x9342  CS
+Contrast/Bolus_Agent_Detected           0x0018  0x9343  CS
+Contrast/Bolus_Agent_Phase              0x0018  0x9344  CS
+//...
+// Group 20 (study)
+Study_Instance_UID                      0x0020  0x000D  UI
+Series_Instance_UID                     0x0020  0x000E  UI
+Study_ID                                0x0020  0x0010  SH
+Series_Number                           0x0020  0x0011  IS
+Acquisition_Number                      0x0020  0x0012  IS
+Instance_Number                         0x0020  0x0013  IS
+Isotope_Number                          0x0020  0x0014  IS
+Phase_Number                            0x0020  0x0015  IS
+Interval_Number                         0x0020  0x0016  IS
+Time_Slot_Number                        0x0020  0x0017  IS
+Angle_Number                            0x0020  0x0018  IS
+Item_Number                             0x0020  0x0019  IS
+Patient_Orientation                     0x0020  0x0020  CS
+Overlay_Number                          0x0020  0x0022  IS
+Curve_Number                            0x0020  0x0024  IS
+Lookup_Table_Number                     0x0020  0x0026  IS
+Image_Position                          0x0020  0x0030  RET
+Image_Position_(Patient)                0x0020  0x0032  DS
+Image_Orientation                       0x0020  0x0035  RET
+Image_Orientation_(Patient)             0x0020  0x0037  DS
+Location                                0x0020  0x0050  RET
+Frame_of_Reference_UID                  0x0020  0x0052  UI
+Laterality                              0x0020  0x0060  CS
+Image_Laterality                        0x0020  0x0062  CS
+Image_Geometry_Type                     0x0020  0x0070  RET
+Masking_Image                           0x0020  0x0080  RET
+Temporal_Position_Identifier            0x0020  0x0100  IS
+Number_of_Temporal_Positions            0x0020  0x0105  IS
+Temporal_Resolution                     0x0020  0x0110  DS
+Synchronization_Frame_of_Refernence_UID 0x0020  0x0200  UI
+Series_in_Study                         0x0020  0x1000  IS
+Acquisitions_in_Series                  0x0020  0x1001  RET
+Images_in_Acquisition                   0x0020  0x1002  IS
+Acquisitions_in_Study                   0x0020  0x1004  IS
+Reference                               0x0020  0x1020  RET
+Position_Reference_Indicator            0x0020  0x1040  LO
+Slice_Location                          0x0020  0x1041  DS
+Other_Study_Numbers                     0x0020  0x1070  IS
+Number_of_Patient_Related_Studies       0x0020  0x1200  IS
+Number_of_Patient_Related_Series        0x0020  0x1202  IS
+Number_of_Patient_Related_Instances     0x0020  0x1204  IS
+Number_of_Study_Related_Series          0x0020  0x1206  IS
+Number_of_Study_Related_Instances       0x0020  0x1208  IS
+//...
+Image_Comments                          0x0020  0x4000  LT
+//...
+Frame_Anatomy_Sequence                  0x0020  0x9071  SQ
+Frame_Laterality                        0x0020  0x9072  CS
+Frame_Content_Sequence                  0x0020  0x9111  SQ
+Plane_Position_Sequence                 0x0020  0x9113  SQ
+Plane_Orientation_Sequence              0x0020  0x9116  SQ
+Frame_Acquisition_Number                0x0020  0x9156  US
+//...
+Dimension_Organization_Sequence         0x0020  0x9221  SQ
+Dimension_Index_Sequence                0x0020  0x9222  SQ
+//...
+//Group 28
+Samples_per_Pixel                       0x0028  0x0002  US
+Samples_per_Pixel_Used                  0x0028  0x0003  US
+Photometric_Interpretation              0x0028  0x0004  CS
+Image_Dimensions                        0x0028  0x0005  RET
+Planar_Configuration                    0x0028  0x0006  US
+Number_of_Frames                        0x0028  0x0008  IS
+Frame_Increment_Pointer                 0x0028  0x0009  AT
+Frame_Dimension_Pointer                 0x0028  0x000A  AT
+Rows                                    0x0028  0x0010  US
+Columns                                 0x0028  0x0011  US
+Planes                                  0x0028  0x0012  US
+Ultrasound_Color_Data_Present           0x0028  0x0014  US
+Pixel_Spacing                           0x0028  0x0030  DS
+Zoom_Factor                             0x0028  0x0031  DS
+Zoom_Center                             0x0028  0x0032  DS
+Pixel_Aspect_Ratio                      0x0028  0x0034  IS
+Image_Format                            0x0028  0x0040  RET
+Manipulated_Image                       0x0028  0x0050  RET
+Corrected_Image                         0x0028  0x0051  CS
+Compression_Code                        0x0028  0x0060  RET
+Bits_Allocated                          0x0028  0x0100  US
+Bits_Stored                             0x0028  0x0101  US
+High_Bit                                0x0028  0x0102  US
+Pixel_Representation                    0x0028  0x0103  US
+Smallest_Valid_Pixel_Value              0x0028  0x0104  RET
+Largest_Valid_Pixel_Value               0x0028  0x0105  RET
+Smallest_Image_Pixel_Value              0x0028  0x0106  US
+Largest_Image_Pixel_Value               0x0028  0x0107  US
+Smallest_Pixel_Value_in_Series          0x0028  0x0108  US
+Largest_Pixel_Value_in_Series           0x0028  0x0109  US
+Smallest_Pixel_Value_in_Plane           0x0028  0x0110  US
+Largest_Pixel_Value_in_Plane            0x0028  0x0111  US
+Pixel_Padding_Value                     0x0028  0x0120  US
+Image_Location                          0x0028  0x0200  RET
+Quality_Control_Image                   0x0028  0x0300  CS
+Burned_In_Annotation                    0x0028  0x0301  CS
+Pixel_Intensity_Relationship            0x0028  0x1040  CS
+Pixel_Intensity_Relationship_Sign       0x0028  0x1041  SS
+Window_Center                           0x0028  0x1050  DS
+Window_Width                            0x0028  0x1051  DS
+Rescale_Intercept                       0x0028  0x1052  DS
+Rescale_Slope                           0x0028  0x1053  DS
+Rescale_Type                            0x0028  0x1054  LO
+Window_Center&Width_Explanation         0x0028  0x1055  LO
+Gray_Scale                              0x0028  0x1080  RET
+Lossy_Image_Compression                 0x0028  0x2110  CS
+Lossy_Image_Compression_Ratio           0x0028  0x2112  DS
+Lossy_Image_Compression_Method          0x0028  0x2114  CS
+LUT_Explanation                         0x0028  0x3003  LO
+Pixel_Measures_Sequence                 0x0028  0x9110  SQ
+Frame_VOI_LUT_Sequence                  0x0028  0x9132  SQ
+Pixel_Value_Transformation_Sequence     0x0028  0x9145  SQ
+//...
+//Group 32
+Requested_Procedure_Description         0x0032  0x1060  LO
+Study_Comments                          0x0032  0x4000  LT
+//Group 40
+Performed_Procedure_Step_Start_Date     0x0040  0x0244  DA
+Performed_Procedure_Step_Start_Time     0x0040  0x0245  TM
+Performed_Procedure_Step_ID             0x0040  0x0253  SH
+Acquisition_Context_Sequence            0x0040  0x0555  SQ
+Measurement_Units_Code_Sequence         0x0040  0x08EA  SQ
+Real_World_Value_Mapping_Sequence       0x0040  0x9096  SQ
+LUT_Label                               0x0040  0x9210  SH
+Real_World_Value_Last_Value_Mapped      0x0040  0x9211  US
+Real_World_Value_LUT_Data               0x0040  0x9212  FD
+Real_World_Value_First_Value_Mapped     0x0040  0x9216  US
+Real_World_Value_Intercept              0x0040  0x9224  FD
+Real_World_Value_Slope                  0x0040  0x9225  FD
+//Group 54
+Energy_Window_Vector                    0x0054  0x0010  US
+Number_of_Energy_Windows                0x0054  0x0011  US
+Energy_Window_Information_Sequence      0x0054  0x0012  SQ
+Energy_Window_Range_Sequence            0x0054  0x0013  SQ
+Energy_Window_Lower_Limit               0x0054  0x0014  DS
+Energy_Window_Upper_Limit               0x0054  0x0015  DS
+Radiopharmaceutical_Information_Sequence 0x0054 0x0016  SQ
+Residual_Syringe_Counts                 0x0054  0x0017  IS
+Energy_Window_Name                      0x0054  0x0018  SH
+Detector_Vector                         0x0054  0x0020  US
+Number_of_Detectors                     0x0054  0x0021  US
+Detector_Information_Sequence           0x0054  0x0022  SQ
+Phase_Vector                            0x0054  0x0030  US
+Number_of_Phases                        0x0054  0x0031  US
+Phase_Information_Sequence              0x0054  0x0032  SQ
+Number_of_Frames_in_Phase               0x0054  0x0033  US
+Phase_Delay                             0x0054  0x0036  IS
+Pause_Between_Frames                    0x0054  0x0038  IS
+Phase_Description                       0x0054  0x0039  CS
+Rotation_Vector                         0x0054  0x0050  US
+Number_of_Rotations                     0x0054  0x0051  US
+Rotation_Information_Sequence           0x0054  0x0052  SQ
+Number_of_Frames_in_Rotation            0x0054  0x0053  US
+R-R_Interval_Vector                     0x0054  0x0060  US
+Number_of_R-R_Intervals                 0x0054  0x0061  US
+Gated_Information_Sequence              0x0054  0x0062  SQ
+Data_Information_Sequence               0x0054  0x0063  SQ
+Time_Slot_Vector                        0x0054  0x0070  US
+Number_of_Time_Slots                    0x0054  0x0071  US
+Time_Slot_Information_Sequence          0x0054  0x0072  SQ
+Time_Slot_Time                          0x0054  0x0073  DS
+Slice_Vector                            0x0054  0x0080  US
+Number_of_Slices                        0x0054  0x0081  US
+Angular_View_Vector                     0x0054  0x0090  US
+Time_Slice_Vector                       0x0054  0x0100  US
+Number_of_Time_Slices                   0x0054  0x0101  US
+Start_Angle                             0x0054  0x0200  DS
+Type_of_Detector_Motion                 0x0054  0x0202  CS
+Trigger_Vector                          0x0054  0x0210  IS
+Number_of_Triggers_in_Phase             0x0054  0x0211  US
+View_Code_Sequence                      0x0054  0x0220  SQ
+View_Modifier_Code_Sequence             0x0054  0x0222  SQ
+Radionuclide_Code_Sequence              0x0054  0x0300  SQ
+Administration_Route_Code_Sequence      0x0054  0x0302  SQ
+Radiopharmaceutical_Code_Sequence       0x0054  0x0304  SQ
+Calibration_Data_Sequence               0x0054  0x0306  SQ
+Energy_Window_Number                    0x0054  0x0308  US
+Image_ID                                0x0054  0x0400  SH
+Patient_Orientation_Code_Sequence       0x0054  0x0410  SQ
+Patient_Orientation_Modifier_Code_Sequence 0x0054 0x0412 SQ
+Patient_Gantry_Relationship_Code_Sequence 0x0054 0x0414 SQ
+Slice_Progression_Direction             0x0054  0x0500  CS
+Series_Type                             0x0054  0x1000  CS
+Units                                   0x0054  0x1001  CS
+Counts_Source                           0x0054  0x1002  CS
+Reprojection_Method                     0x0054  0x1004  CS
+Randoms_Correction_Method               0x0054  0x1100  CS
+Attenuation_Correction_Method           0x0054  0x1101  LO
+Decay_Correction                        0x0054  0x1102  CS
+Reconstruction_Method                   0x0054  0x1103  LO
+Detector_Lines_of_Response_Used         0x0054  0x1104  LO
+Scatter_Correction_Method               0x0054  0x1105  LO
+Axial_Acceptance                        0x0054  0x1200  DS
+Axial_Mash                              0x0054  0x1201  IS
+Transverse_Mash                         0x0054  0x1202  IS
+Detector_Element_Size                   0x0054  0x1203  DS
+Concidence_Window_Width                 0x0054  0x1210  DS
+Secondary_Counts_Type                   0x0054  0x1220  CS
+Frame_Reference_Time                    0x0054  0x1300  DS
+Primary_(Prompts)_Counts_Accumulated    0x0054  0x1310  IS
+Secondary_Counts_Accumulated            0x0054  0x1311  IS
+Slice_Sensitivity_Factor                0x0054  0x1320  DS
+Decay_Factor                            0x0054  0x1321  DS
+Dose_Calibration_Factor                 0x0054  0x1322  DS
+Scatter_Fraction_Factor                 0x0054  0x1323  DS
+Dead_Time_Factor                        0x0054  0x1324  DS
+Image_Index                             0x0054  0x1330  US
+Counts_Included                         0x0054  0x1400  CS
+Dead_Time_Correction_Flag               0x0054  0x1401  CS
+//Group 0x2050
+Presentation_LUT_Sequence               0x2050  0x0010  SQ
+Presentation_LUT_Shape                  0x2050  0x0020  CS
+Referenced_Presentation_LUT_Sequence    0x2050  0x0500  SQ
+//Group 0x5200
+Shared_Functional_Groups_Sequence       0x5200  0x9229  SQ
+Per_Frame_Functional_Groups_Sequence    0x5200  0x9230  SQ
+
+//Group 0x7fe0
+Pixel_Data                              0x7fe0  0x0010  OW
+
--- a/conversion/Acr_nema/dicom_client_routines.c
+++ b/conversion/Acr_nema/dicom_client_routines.c
@@ -6,7 +6,19 @@
 @CREATED    : May 6, 1997 (Peter Neelin)
 @MODIFIED   : 
  * $Log: dicom_client_routines.c,v $
- * Revision 6.19  2001-03-19 18:31:55  neelin
+ * Revision 6.21.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.21  2005/02/16 19:22:32  bert
+ * Autoconfiscation
+ *
+ * Revision 6.20  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.19  2001/03/19 18:31:55  neelin
  * Modifications to allow opening a stream to stdout (with no input) so
  * that a dicom stream can be captured.
  *
@@ -110,7 +122,7 @@
 ---------------------------------------------------------------------------- */
 
 #ifndef lint
-static char rcsid[]="$Header: /private-cvsroot/minc/conversion/Acr_nema/dicom_client_routines.c,v 6.19 2001-03-19 18:31:55 neelin Exp $";
+static char rcsid[]="$Header: /private-cvsroot/minc/conversion/Acr_nema/dicom_client_routines.c,v 6.21.2.1 2005-05-12 21:15:30 bert Exp $";
 #endif
 
 #include <stdio.h>
@@ -131,7 +143,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Constants */
--- a/conversion/Acr_nema/dicom_network.c
+++ b/conversion/Acr_nema/dicom_network.c
@@ -6,7 +6,16 @@
 @CREATED    : February 10, 1997 (Peter Neelin)
 @MODIFIED   : 
  * $Log: dicom_network.c,v $
- * Revision 6.10  2001-03-19 18:30:32  neelin
+ * Revision 6.11.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.11  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.10  2001/03/19 18:30:32  neelin
  * Added function to set implementation uid and changed name of function
  * that gets it.
  *
@@ -91,7 +100,6 @@
 #include <ctype.h>
 #include <string.h>
 #include <time.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Constants */
--- a/conversion/Acr_nema/dicom_test.c
+++ b/conversion/Acr_nema/dicom_test.c
@@ -3,7 +3,6 @@
 #include <limits.h>
 
 #include <acr_nema.h>
-#include <minc_def.h>
 
 #if 0
 #define WRITING
--- a/conversion/Acr_nema/dump_acr_nema.c
+++ b/conversion/Acr_nema/dump_acr_nema.c
@@ -6,7 +6,19 @@
 @CREATED    : November 24, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: dump_acr_nema.c,v $
- * Revision 6.5  2001-11-08 14:17:05  neelin
+ * Revision 6.7.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.7  2005/03/11 22:19:59  bert
+ * add '-t' option to parse files which contain lists of field names with corresponding group and element id's.
+ *
+ * Revision 6.6  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.5  2001/11/08 14:17:05  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -84,10 +96,90 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
+#define N_NAME 31
+
+struct table_element {
+    struct table_element *next;
+    unsigned short el_id;
+    char name[N_NAME+1];
+};
+
+struct table_group {
+    struct table_group *next;
+    struct table_element *list;
+    unsigned short grp_id;
+};
+
+struct table_group *_head;
+
+char *get_name(unsigned short grp_id, unsigned short el_id)
+{
+    struct table_group *tg_ptr;
+    struct table_element *te_ptr;
+
+    for (tg_ptr = _head; tg_ptr; tg_ptr = tg_ptr->next) {
+        if (tg_ptr->grp_id == grp_id) {
+            for (te_ptr = tg_ptr->list; te_ptr; te_ptr = te_ptr->next) {
+                if (te_ptr->el_id == el_id) {
+                    return (te_ptr->name);
+                }
+            }
+        }
+    }
+    return (NULL);
+}
+
+void parse_table(char *filename)
+{
+    FILE *fp;
+    char line[1024];
+    char name[1024];
+    unsigned int el_id;         /* Must be int for sscanf */
+    unsigned int grp_id;        /* Must be int for sscanf */
+    char vr[1024];
+    struct table_element *te_ptr;
+    struct table_group *tg_ptr;
+
+    fp = fopen(filename, "r");
+    if (fp == NULL) {
+        return;
+    }
+
+    while (fgets(line, sizeof(line), fp)) {
+        if (!isalnum(line[0])) {
+            continue;           /* Ignore */
+        }
+        if (sscanf(line, "%s %x %x %s\n", name, &grp_id, &el_id, vr) != 4) {
+            continue;
+        }
+
+        for (tg_ptr = _head; tg_ptr; tg_ptr = tg_ptr->next) {
+            if (tg_ptr->grp_id == grp_id) {
+                break;
+            }
+        }
+        if (tg_ptr == NULL) {
+            tg_ptr = malloc(sizeof(struct table_group));
+            tg_ptr->next = _head;
+            _head = tg_ptr;
+            tg_ptr->list = NULL;
+            tg_ptr->grp_id = (unsigned short) grp_id;
+        }
+
+        te_ptr = malloc(sizeof(struct table_element));
+        te_ptr->el_id = (unsigned short) el_id;
+        te_ptr->next = tg_ptr->list;
+        tg_ptr->list = te_ptr;
+        strncpy(te_ptr->name, name, N_NAME);
+    }
+    fclose(fp);
+}
+
+
 #define UNKNOWN_VR_ENCODING ((Acr_VR_encoding_type) -1)
 
 int main(int argc, char *argv[])
@@ -107,7 +199,7 @@
    char *ptr;
    int iarg, argcounter;
    char *arg;
-   char *usage = "Usage: %s [-h] [-i] [-b] [-l] [-e] [<file> [<max group>]]\n";
+   char *usage = "Usage: %s [-h] [-i] [-b] [-l] [-e] [-t <table>] [<file> [<max group>]]\n";
 
    /* Check arguments */
    pname = argv[0];
@@ -120,9 +212,17 @@
             exit(EXIT_FAILURE);
          }
          switch (arg[1]) {
+         case 't':
+             if (iarg < argc - 1) {
+                 parse_table(argv[++iarg]);
+                 _acr_name_proc = get_name;
+                 break;
+             }
+             /* Fall through */
          case 'h':
             (void) fprintf(stderr, "Options:\n");
             (void) fprintf(stderr, "   -h:\tPrint this message\n");
+            (void) fprintf(stderr, "   -t <table>:\tUse table to decode element names\n");
             (void) fprintf(stderr, "   -i:\tIgnore protocol errors\n");
             (void) fprintf(stderr, "   -b:\tAssume big-endian data\n");
             (void) fprintf(stderr, "   -l:\tAssume little-endian data\n");
--- a/conversion/Acr_nema/element.c
+++ b/conversion/Acr_nema/element.c
@@ -6,7 +6,25 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: element.c,v $
- * Revision 6.3  2002-12-07 01:37:24  neelin
+ * Revision 6.7.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.7  2005/04/18 23:22:29  bert
+ * Initialize newlist in acr_copy_element() to avoid problems with empty lists
+ *
+ * Revision 6.6  2005/03/11 22:05:29  bert
+ * Implement _acr_name_proc to allow printing of field names in dump_acr_nema
+ *
+ * Revision 6.5  2005/03/04 00:25:54  bert
+ * Avoid memory leak by freeing unused elements in a sequence.  Fix order of initialization in acr_create_element() to set variable length property correctly. Don't change VR encoding when parsing a sequence, rely on the new handling of 0xfffe group items by the acr_io functions
+ *
+ * Revision 6.4  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.3  2002/12/07 01:37:24  neelin
  * Added missing type
  *
  * Revision 6.2  2001/12/12 19:00:54  neelin
@@ -93,14 +111,13 @@
 #include <string.h>
 #include <ctype.h>
 #include <math.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Private functions */
-private void delete_element_data(Acr_Element element);
-private Acr_Element create_element_mem(Acr_Element_Id elid,
-                                       Acr_VR_Type vr_code, 
-                                       size_t value_size, void *value);
+static void delete_element_data(Acr_Element element);
+static Acr_Element create_element_mem(Acr_Element_Id elid,
+                                      Acr_VR_Type vr_code, 
+                                      size_t value_size, void *value);
 
 /* Macros */
 #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
@@ -128,9 +145,9 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : February 4, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element(int group_id, int element_id, 
-                                      Acr_VR_Type vr_code, 
-                                      long data_length, char *data_pointer)
+Acr_Element acr_create_element(int group_id, int element_id, 
+                               Acr_VR_Type vr_code, 
+                               long data_length, char *data_pointer)
 {
    Acr_Element element;
 
@@ -144,9 +161,9 @@
    acr_set_element_vr(element, vr_code);
    acr_set_element_vr_encoding(element, ACR_EXPLICIT_VR);
    acr_set_element_byte_order(element, acr_get_machine_byte_order());
-   acr_set_element_variable_length(element, (data_length < 0));
    acr_set_element_next(element, NULL);
    acr_set_element_data(element, data_length, data_pointer);
+   acr_set_element_variable_length(element, (data_length < 0));
 
    return element;
 }
@@ -164,7 +181,7 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void delete_element_data(Acr_Element element)
+static void delete_element_data(Acr_Element element)
 {
    char *data_pointer;
 
@@ -193,7 +210,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : February 4, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public void acr_delete_element(Acr_Element element)
+void acr_delete_element(Acr_Element element)
 {
 
    if (element == NULL) return;
@@ -215,7 +232,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_delete_element_list(Acr_Element element_list)
+void acr_delete_element_list(Acr_Element element_list)
 {
    Acr_Element next, cur;
 
@@ -246,8 +263,8 @@
 @CREATED    : February 11, 1997 (P.N.)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_element_list_add(Acr_Element element_list, 
-                                        Acr_Element element)
+Acr_Element acr_element_list_add(Acr_Element element_list, 
+                                 Acr_Element element)
 {
    Acr_Element current;
 
@@ -281,8 +298,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_id(Acr_Element element,
-                               int group_id, int element_id)
+void acr_set_element_id(Acr_Element element,
+                        int group_id, int element_id)
 {
    element->group_id = group_id;
    element->element_id = element_id;
@@ -303,8 +320,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_vr(Acr_Element element,
-                               Acr_VR_Type vr_code)
+void acr_set_element_vr(Acr_Element element,
+                        Acr_VR_Type vr_code)
 {
    element->vr_code = (short) vr_code;
    return;
@@ -324,8 +341,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_vr_encoding(Acr_Element element,
-                                        Acr_VR_encoding_type vr_encoding)
+void acr_set_element_vr_encoding(Acr_Element element,
+                                 Acr_VR_encoding_type vr_encoding)
 {
    element->uses_explicit_vr = (vr_encoding == ACR_EXPLICIT_VR);
    return;
@@ -345,8 +362,8 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_byte_order(Acr_Element element,
-                                       Acr_byte_order byte_order)
+void acr_set_element_byte_order(Acr_Element element,
+                                Acr_byte_order byte_order)
 {
    element->has_little_endian_order = (byte_order == ACR_LITTLE_ENDIAN);
    return;
@@ -367,8 +384,8 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_variable_length(Acr_Element element,
-                                            int has_variable_length)
+void acr_set_element_variable_length(Acr_Element element,
+                                     int has_variable_length)
 {
    if (acr_element_is_sequence(element)) {
       element->has_variable_length = (has_variable_length != FALSE);
@@ -396,8 +413,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : February 4, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public void acr_set_element_data(Acr_Element element,
-                                 long data_length, char *data_pointer)
+void acr_set_element_data(Acr_Element element,
+                          long data_length, char *data_pointer)
 {
    Acr_Element item, last, last2;
    long last_length;
@@ -465,7 +482,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_element_next(Acr_Element element, Acr_Element next)
+void acr_set_element_next(Acr_Element element, Acr_Element next)
 {
    element->next = next;
    return;
@@ -483,7 +500,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_element_group(Acr_Element element)
+int acr_get_element_group(Acr_Element element)
 {
    return element->group_id;
 }
@@ -500,7 +517,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_element_element(Acr_Element element)
+int acr_get_element_element(Acr_Element element)
 {
    return element->element_id;
 }
@@ -517,7 +534,7 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_VR_Type acr_get_element_vr(Acr_Element element)
+Acr_VR_Type acr_get_element_vr(Acr_Element element)
 {
    return (Acr_VR_Type) element->vr_code;
 }
@@ -534,7 +551,7 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_VR_encoding_type acr_get_element_vr_encoding(Acr_Element element)
+Acr_VR_encoding_type acr_get_element_vr_encoding(Acr_Element element)
 {
    return (element->uses_explicit_vr ? ACR_EXPLICIT_VR : ACR_IMPLICIT_VR);
 }
@@ -551,7 +568,7 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_element_is_sequence(Acr_Element element)
+int acr_element_is_sequence(Acr_Element element)
 {
    return element->is_sequence;
 }
@@ -568,7 +585,7 @@
 @CREATED    : February 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_byte_order acr_get_element_byte_order(Acr_Element element)
+Acr_byte_order acr_get_element_byte_order(Acr_Element element)
 {
    return (element->has_little_endian_order ? 
            ACR_LITTLE_ENDIAN : ACR_BIG_ENDIAN);
@@ -586,7 +603,7 @@
 @CREATED    : February 4, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_element_has_variable_length(Acr_Element element)
+int acr_element_has_variable_length(Acr_Element element)
 {
    return element->has_variable_length;
 }
@@ -604,7 +621,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_element_length(Acr_Element element)
+long acr_get_element_length(Acr_Element element)
 {
    long data_length;
 
@@ -629,7 +646,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_get_element_data(Acr_Element element)
+char *acr_get_element_data(Acr_Element element)
 {
    return element->data_pointer;
 }
@@ -639,7 +656,7 @@
 @INPUT      : element
               vr_encoding - ACR_IMPLICIT_VR or ACR_EXPLICIT_VR
 @OUTPUT     : (none)
-@RETURNS    : total length for element
+@RETURNS    : total length for element, or zero if error.
 @DESCRIPTION: Get total length for element in ACR-NEMA representation
               depending on VR
 @METHOD     : 
@@ -648,12 +665,19 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_element_total_length(Acr_Element element,
-                                         Acr_VR_encoding_type vr_encoding)
+long acr_get_element_total_length(Acr_Element element,
+                                  Acr_VR_encoding_type vr_encoding)
 {
+   /* bert- verify that the VR name is non-null. This protects against
+    * core dumps when reading improperly-formatted files.
+    */
+   char *vr_name = acr_get_vr_name(acr_get_element_vr(element));
+   if (vr_name == NULL) {
+      return (0);
+   }
+
    return acr_get_element_length(element) + 
-      acr_get_element_header_size(acr_get_vr_name(acr_get_element_vr(element)),
-                                  vr_encoding);
+      acr_get_element_header_size(vr_name, vr_encoding);
 }
 
 /* ----------------------------- MNI Header -----------------------------------
@@ -668,7 +692,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_get_element_next(Acr_Element element)
+Acr_Element acr_get_element_next(Acr_Element element)
 {
    return element->next;
 }
@@ -685,7 +709,7 @@
 @CREATED    : November 26, 1993 (Peter Neelin)
 @MODIFIED   : February 4, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_copy_element(Acr_Element element)
+Acr_Element acr_copy_element(Acr_Element element)
 {
    Acr_Element copy;
    long length;
@@ -700,6 +724,7 @@
       length = -1;
       olditem = (Acr_Element) acr_get_element_data(element);
       newitem = NULL;
+      newlist = NULL;           /* bert- initialize in case list is empty */
       while (olditem != NULL) {
          if (newitem == NULL) {
             newlist = acr_copy_element(olditem);
@@ -754,7 +779,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_input_element(Acr_File *afp, Acr_Element *element)
+Acr_Status acr_input_element(Acr_File *afp, Acr_Element *element)
 {
    int group_id, element_id, item_gid, item_elid;
    long data_length;
@@ -764,11 +789,13 @@
    int is_sequence, more_to_read, found_delimiter, has_variable_length;
    Acr_Element item, itemlist, previtem;
    Acr_VR_Type vr_code;
-   Acr_VR_encoding_type old_vr_encoding;
+   Acr_VR_encoding_type vr_encoding;
 
    /* Set element in case of error */
    *element = NULL;
 
+   vr_encoding = acr_get_vr_encoding(afp);
+
    /* Read in the value */
    status = acr_read_one_element(afp, &group_id, &element_id, vr_name,
                                  &data_length, &data_pointer);
@@ -785,16 +812,16 @@
    if ((data_length > 0)  && (data_pointer == NULL)) {
       is_sequence = TRUE;
    }
+
    has_variable_length = (data_length < 0);
 
    /* If we have a sequence, read in all the items and store them as a 
-      list of elements. We must turn off explicit VR encoding for items. */
+      list of elements. */
    if (is_sequence) {
 
       more_to_read = TRUE;
       itemlist = NULL;
-      old_vr_encoding = acr_get_vr_encoding(afp);
-      acr_set_vr_encoding(afp, ACR_IMPLICIT_VR);
+
       while (more_to_read) {
 
          /* Read in an item */
@@ -803,7 +830,7 @@
 
          /* If we know the length of the whole sequence, check it */
          if ((status == ACR_OK) && (data_length > 0)) {
-            data_length -= acr_get_element_total_length(item, ACR_IMPLICIT_VR);
+            data_length -= acr_get_element_total_length(item, vr_encoding);
             if (data_length < 0) status = ACR_PROTOCOL_ERROR;
          }
 
@@ -825,6 +852,9 @@
             }
             previtem = item;
          }
+         else {
+             free(item);        /* Avoid leaking memory */
+         }
 
          /* Check for end of items */
          if ((data_length == 0) || found_delimiter || (status != ACR_OK)) {
@@ -832,9 +862,6 @@
          }
       }        /* End of loop over items */
 
-      /* Restore the VR encoding */
-      acr_set_vr_encoding(afp, old_vr_encoding);
-
       /* Save the item list as the data */
       data_pointer = (char *) itemlist;
    }
@@ -866,7 +893,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_output_element(Acr_File *afp, Acr_Element element)
+Acr_Status acr_output_element(Acr_File *afp, Acr_Element element)
 {
    char *vr_name;
    Acr_VR_Type vr_code;
@@ -957,8 +984,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_convert_element_byte_order(Acr_Element element, 
-                                           Acr_byte_order byte_order)
+void acr_convert_element_byte_order(Acr_Element element, 
+                                    Acr_byte_order byte_order)
 {
    Acr_byte_order element_byte_order;
    long nvalues;
@@ -1015,8 +1042,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_match_element_id(Acr_Element_Id elid,
-                                Acr_Element element)
+int acr_match_element_id(Acr_Element_Id elid,
+                         Acr_Element element)
 {
    return ((elid->group_id == acr_get_element_group(element)) &&
            (elid->element_id == acr_get_element_element(element)));
@@ -1037,8 +1064,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_find_element_id(Acr_Element element_list,
-                                       Acr_Element_Id elid)
+Acr_Element acr_find_element_id(Acr_Element element_list,
+                                Acr_Element_Id elid)
 {
    Acr_Element element;
 
@@ -1071,7 +1098,7 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void *acr_memdup(size_t value_size, void *value)
+void *acr_memdup(size_t value_size, void *value)
 {
    char *copy, *original;
    size_t i;
@@ -1100,9 +1127,9 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private Acr_Element create_element_mem(Acr_Element_Id elid,
-                                       Acr_VR_Type vr_code, 
-                                       size_t value_size, void *value)
+static Acr_Element create_element_mem(Acr_Element_Id elid,
+                                      Acr_VR_Type vr_code, 
+                                      size_t value_size, void *value)
 {
    return acr_create_element(elid->group_id, elid->element_id, vr_code,
                              value_size, acr_memdup(value_size, value));
@@ -1121,8 +1148,8 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element_short(Acr_Element_Id elid,
-                                            unsigned short value)
+Acr_Element acr_create_element_short(Acr_Element_Id elid,
+                                     unsigned short value)
 {
    return create_element_mem(elid, ACR_VR_US, sizeof(value), (void *) &value);
 }
@@ -1140,8 +1167,8 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element_long(Acr_Element_Id elid,
-                                           long value)
+Acr_Element acr_create_element_long(Acr_Element_Id elid,
+                                    long value)
 {
    return create_element_mem(elid, ACR_VR_UL, sizeof(value), (void *) &value);
 }
@@ -1162,8 +1189,8 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element_numeric(Acr_Element_Id elid,
-                                              double value)
+Acr_Element acr_create_element_numeric(Acr_Element_Id elid,
+                                       double value)
 {
    char string[256];
    Acr_Element element;
@@ -1192,8 +1219,8 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element_string(Acr_Element_Id elid,
-                                             char *value)
+Acr_Element acr_create_element_string(Acr_Element_Id elid,
+                                      char *value)
 {
    long data_length;
    long alloc_length;
@@ -1243,8 +1270,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_create_element_sequence(Acr_Element_Id elid,
-                                               Acr_Element itemlist)
+Acr_Element acr_create_element_sequence(Acr_Element_Id elid,
+                                        Acr_Element itemlist)
 {
    return acr_create_element(elid->group_id, elid->element_id, 
                              ACR_VR_SQ, -1L, (char *) itemlist);
@@ -1263,7 +1290,7 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public unsigned short acr_get_element_short(Acr_Element element)
+unsigned short acr_get_element_short(Acr_Element element)
 {
    unsigned short value;
 
@@ -1288,7 +1315,7 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_element_long(Acr_Element element)
+long acr_get_element_long(Acr_Element element)
 {
    long value;
 
@@ -1313,7 +1340,7 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public double acr_get_element_numeric(Acr_Element element)
+double acr_get_element_numeric(Acr_Element element)
 {
    double value;
 
@@ -1337,7 +1364,7 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_get_element_string(Acr_Element element)
+char *acr_get_element_string(Acr_Element element)
 {
 
    return acr_get_string_vr(acr_get_element_vr(element),
@@ -1363,8 +1390,8 @@
 @CREATED    : February 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_element_short_array(Acr_Element element, long max_values, 
-                                        unsigned short values[])
+long acr_get_element_short_array(Acr_Element element, long max_values, 
+                                 unsigned short values[])
 {
    long nvalues;
 
@@ -1407,7 +1434,7 @@
 @CREATED    : February 27, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int *acr_element_numeric_array_separator(int character)
+int *acr_element_numeric_array_separator(int character)
 {
    static int *separator_list = NULL;
    static int nseparators = 0;
@@ -1457,8 +1484,8 @@
 @CREATED    : November 17, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_element_numeric_array(Acr_Element element,
-                                         int max_values, double values[])
+int acr_get_element_numeric_array(Acr_Element element,
+                                  int max_values, double values[])
 {
    char *start, *end, *cur, *prev;
    int *separator_list;
@@ -1519,8 +1546,8 @@
 @CREATED    : February 12, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_dump_element_list(FILE *file_pointer, 
-                                  Acr_Element element_list)
+void acr_dump_element_list(FILE *file_pointer, 
+                           Acr_Element element_list)
 {
 #define INDENT_AMOUNT 3
    Acr_Element cur_element;
@@ -1548,11 +1575,23 @@
 
       /* Print the element id */
       (void) fprintf(file_pointer, 
-                     "0x%04x  0x%04x  length = %d :",
+                     "0x%04x  0x%04x  length = %d ",
                      acr_get_element_group(cur_element),
                      acr_get_element_element(cur_element),
                      (int) acr_get_element_length(cur_element));
 
+      if (_acr_name_proc != NULL) {
+          char *name_ptr;
+
+          name_ptr = (*_acr_name_proc)(acr_get_element_group(cur_element),
+                                       acr_get_element_element(cur_element));
+
+          if (name_ptr != NULL) {
+              fprintf(file_pointer, "(%s)", name_ptr);
+          }
+      }
+      fprintf(file_pointer, ":");
+
       /* Print value if needed */
       vr_code = acr_get_element_vr(cur_element);
       if (acr_element_is_sequence(cur_element)) {
--- a/conversion/Acr_nema/extract_acr_nema.c
+++ b/conversion/Acr_nema/extract_acr_nema.c
@@ -6,7 +6,16 @@
 @CREATED    : November 24, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: extract_acr_nema.c,v $
- * Revision 6.5  2001-11-08 14:17:05  neelin
+ * Revision 6.6.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.6  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.5  2001/11/08 14:17:05  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -71,7 +80,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 #define UNKNOWN_VR_ENCODING ((Acr_VR_encoding_type) -1)
--- a/conversion/Acr_nema/file_io.c
+++ b/conversion/Acr_nema/file_io.c
@@ -6,7 +6,22 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: file_io.c,v $
- * Revision 6.4  2001-11-08 14:17:05  neelin
+ * Revision 6.7.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.7  2005/03/04 00:09:00  bert
+ * Lose private and public
+ *
+ * Revision 6.6  2005/02/16 19:22:32  bert
+ * Autoconfiscation
+ *
+ * Revision 6.5  2004/10/29 13:08:41  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.4  2001/11/08 14:17:05  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -88,8 +103,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <limits.h>
-#include <minc_def.h>
-#include <file_io.h>
+#include <acr_nema/file_io.h>
 
 /* Define some constants */
 #define ACR_MAX_BUFFER_LENGTH (64*1024)
@@ -122,7 +136,7 @@
 @CREATED    : February 18, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_enable_trace(Acr_File *afp)
+void acr_file_enable_trace(Acr_File *afp)
 {
    afp->do_trace = TRUE;
 }
@@ -139,7 +153,7 @@
 @CREATED    : February 18, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_disable_trace(Acr_File *afp)
+void acr_file_disable_trace(Acr_File *afp)
 {
    afp->do_trace = FALSE;
 }
@@ -161,9 +175,9 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : February 5, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_File *acr_file_initialize(void *io_data,
-                                     int maxlength,
-                                     Acr_Io_Routine io_routine)
+Acr_File *acr_file_initialize(void *io_data,
+                              int maxlength,
+                              Acr_Io_Routine io_routine)
 {
    Acr_File *afp;
 
@@ -173,7 +187,7 @@
    }
 
    /* Allocate the strcture */
-   afp = MALLOC(sizeof(*afp));
+   afp = malloc(sizeof(*afp));
 
    /* Initialize fields */
    afp->io_data = io_data;
@@ -191,7 +205,7 @@
    afp->client_data = NULL;
 
    /* Allocate the buffer */
-   afp->start = MALLOC((size_t) afp->buffer_length);
+   afp->start = malloc((size_t) afp->buffer_length);
 
    /* Set ptr and end to start so that we can detect beginning of i/o */
    afp->length = 0;
@@ -217,22 +231,22 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_free(Acr_File *afp)
+void acr_file_free(Acr_File *afp)
 {
    if (afp != NULL) {
       if (afp->stream_type == ACR_WRITE_STREAM) {
          (void) acr_file_flush(afp);
       }
       if (afp->start != NULL) {
-         FREE(afp->start);
+         free(afp->start);
       }
       if (afp->tracefp != NULL) {
          (void) fclose(afp->tracefp);
       }
       if (afp->client_data != NULL) {
-         FREE(afp->client_data);
+         free(afp->client_data);
       }
-      FREE(afp);
+      free(afp);
    }
    return;
 }
@@ -250,7 +264,7 @@
 @CREATED    : February 18, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_reset(Acr_File *afp)
+void acr_file_reset(Acr_File *afp)
 {
    afp->watchpoint_set = FALSE;
    afp->bytes_to_watchpoint = 0;
@@ -277,8 +291,8 @@
 @CREATED    : May 17, 2000 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_set_ismore_function(Acr_File *afp, 
-                                         Acr_Ismore_Function ismore_function)
+void acr_file_set_ismore_function(Acr_File *afp, 
+                                  Acr_Ismore_Function ismore_function)
 {
    afp->ismore_function = ismore_function;
 }
@@ -298,7 +312,7 @@
 @CREATED    : March 10, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_set_eof(Acr_File *afp)
+void acr_file_set_eof(Acr_File *afp)
 {
    afp->reached_eof = TRUE;
 }
@@ -320,10 +334,10 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_file_set_client_data(Acr_File *afp, void *client_data)
+void acr_file_set_client_data(Acr_File *afp, void *client_data)
 {
    if (afp->client_data != NULL) {
-      FREE(afp->client_data);
+      free(afp->client_data);
    }
    afp->client_data = client_data;
 }
@@ -340,7 +354,7 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void *acr_file_get_client_data(Acr_File *afp)
+void *acr_file_get_client_data(Acr_File *afp)
 {
    return afp->client_data;
 }
@@ -358,7 +372,7 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : February 5, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public int acr_file_read_more(Acr_File *afp)
+int acr_file_read_more(Acr_File *afp)
 {
    int nread, ichar;
    char trace_file[128];
@@ -434,8 +448,7 @@
    if (afp->do_trace) {
       if (afp->tracefp == NULL) {
          (void) strcpy(trace_file, Input_trace_file);
-         (void) mktemp(trace_file);
-         afp->tracefp = fopen(trace_file, "w");
+         afp->tracefp = fdopen(mkstemp(trace_file), "w");
          if (afp->tracefp != NULL) {
             (void) fprintf(stderr, "Opened input trace file %s.\n", 
                            trace_file);
@@ -482,7 +495,7 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : February 5, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public int acr_file_write_more(Acr_File *afp, int character)
+int acr_file_write_more(Acr_File *afp, int character)
 {
 
    /* Check the pointer */
@@ -517,7 +530,7 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : February 5, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public int acr_file_flush(Acr_File *afp)
+int acr_file_flush(Acr_File *afp)
 {
    int length, nwritten;
    char trace_file[128];
@@ -549,8 +562,7 @@
       if (afp->do_trace) {
          if (afp->tracefp == NULL) {
             (void) strcpy(trace_file, Output_trace_file);
-            (void) mktemp(trace_file);
-            afp->tracefp = fopen(trace_file, "w");
+            afp->tracefp = fdopen(mkstemp(trace_file), "w");
             if (afp->tracefp != NULL) {
                (void) fprintf(stderr, "Opened output trace file %s.\n", 
                               trace_file);
@@ -607,7 +619,7 @@
 @CREATED    : November 25, 1993 (Peter Neelin)
 @MODIFIED   : February 5, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public int acr_ungetc(int c, Acr_File *afp)
+int acr_ungetc(int c, Acr_File *afp)
 {
 
    /* Check the pointer */
@@ -645,7 +657,7 @@
 @CREATED    : February 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void *acr_file_get_io_data(Acr_File *afp)
+void *acr_file_get_io_data(Acr_File *afp)
 {
    return afp->io_data;
 }
@@ -666,7 +678,7 @@
 @CREATED    : February 5, 1997 (P.N.)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_io_watchpoint(Acr_File *afp, long bytes_to_watchpoint)
+void acr_set_io_watchpoint(Acr_File *afp, long bytes_to_watchpoint)
 {
    if (afp == NULL) return;
 
@@ -710,7 +722,7 @@
 @CREATED    : February 5, 1997 (P.N.)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_io_watchpoint(Acr_File *afp)
+long acr_get_io_watchpoint(Acr_File *afp)
 {
    if ((afp == NULL) || !afp->watchpoint_set) return ACR_NO_WATCHPOINT;
 
@@ -738,7 +750,7 @@
 @CREATED    : May 17, 2000 (P.N.)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_file_ismore(Acr_File *afp)
+int acr_file_ismore(Acr_File *afp)
 {
    int retval;
 
@@ -791,7 +803,7 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_stdio_read(void *io_data, void *buffer, int nbytes)
+int acr_stdio_read(void *io_data, void *buffer, int nbytes)
 {
    FILE *fp;
    int nread;
@@ -821,7 +833,7 @@
 @CREATED    : November 9, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_stdio_write(void *io_data, void *buffer, int nbytes)
+int acr_stdio_write(void *io_data, void *buffer, int nbytes)
 {
    FILE *fp;
    int nwritten;
@@ -855,7 +867,7 @@
 @CREATED    : May 17, 2000 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_stdio_ismore(void *io_data)
+int acr_stdio_ismore(void *io_data)
 {
    FILE *fp;
    int val;
--- a/conversion/Acr_nema/globals.c
+++ b/conversion/Acr_nema/globals.c
@@ -24,5 +24,4 @@
 #include <stdio.h>
 #include <limits.h>
 #include <ctype.h>
-#include <minc_def.h>
 #include <acr_nema.h>
--- a/conversion/Acr_nema/group.c
+++ b/conversion/Acr_nema/group.c
@@ -6,7 +6,25 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: group.c,v $
- * Revision 6.6  2002-12-08 22:31:34  neelin
+ * Revision 6.10.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.10  2005/05/09 15:34:46  bert
+ * For acr_find_{short,int,long,double}, treat a zero-length element as if it were absent, and return the default value.
+ *
+ * Revision 6.9  2005/03/11 22:05:29  bert
+ * Implement _acr_name_proc to allow printing of field names in dump_acr_nema
+ *
+ * Revision 6.8  2005/03/04 17:09:11  bert
+ * Change several functions to return Acr_Status instead of void; lose public and private; Make insert_element() check the return value of acr_get_element_total_length()
+ *
+ * Revision 6.7  2004/10/29 13:08:42  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.6  2002/12/08 22:31:34  neelin
  * When a last fragment is received, the dicom watchpoint is only updated when the next read happens, so the peek ahead will fail after the watchpoint test in acr_input_group_with_max.
  *
  * Revision 6.5  2001/11/08 14:17:05  neelin
@@ -113,20 +131,21 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Private functions */
-private void steal_element(Acr_Group group, Acr_Element element, 
+static void steal_element(Acr_Group group, Acr_Element element, 
+                          Acr_Element previous);
+static void remove_element(Acr_Group group, Acr_Element element, 
                            Acr_Element previous);
-private void remove_element(Acr_Group group, Acr_Element element, 
-                            Acr_Element previous);
-private void insert_element(Acr_Group group, Acr_Element element, 
-                            Acr_Element previous);
-private void update_group_length_element(Acr_Group group, 
-                                         Acr_VR_encoding_type vr_encoding);
-private Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group, 
-                                            int max_group_id);
+static Acr_Status insert_element(Acr_Group group, Acr_Element element, 
+                                 Acr_Element previous);
+static void update_group_length_element(Acr_Group group, 
+                                        Acr_VR_encoding_type vr_encoding);
+static Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group, 
+                                           int max_group_id);
+
+acr_name_proc_t _acr_name_proc = NULL;
 
 
 /* ----------------------------- MNI Header -----------------------------------
@@ -141,7 +160,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : February 4, 1997 (P.N.)
 ---------------------------------------------------------------------------- */
-public Acr_Group acr_create_group(int group_id)
+Acr_Group acr_create_group(int group_id)
 {
    Acr_Group group;
    Acr_Element length_element;
@@ -183,7 +202,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_delete_group(Acr_Group group)
+void acr_delete_group(Acr_Group group)
 {
    acr_delete_element_list(group->list_head);
 
@@ -204,7 +223,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_delete_group_list(Acr_Group group_list)
+void acr_delete_group_list(Acr_Group group_list)
 {
    Acr_Group next, cur;
 
@@ -234,7 +253,7 @@
 @CREATED    : November 26, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Group acr_copy_group(Acr_Group group)
+Acr_Group acr_copy_group(Acr_Group group)
 {
    Acr_Group copy;
    Acr_Element cur;
@@ -264,7 +283,7 @@
 @CREATED    : November 26, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Group acr_copy_group_list(Acr_Group group_list)
+Acr_Group acr_copy_group_list(Acr_Group group_list)
 {
    Acr_Group copy_list;
    Acr_Group copy_group;
@@ -301,8 +320,8 @@
 @CREATED    : November 6, 1998 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void steal_element(Acr_Group group, Acr_Element element, 
-                           Acr_Element previous)
+static void steal_element(Acr_Group group, Acr_Element element, 
+                          Acr_Element previous)
 {
    Acr_Element next;
 
@@ -347,8 +366,8 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void remove_element(Acr_Group group, Acr_Element element, 
-                            Acr_Element previous)
+static void remove_element(Acr_Group group, Acr_Element element, 
+                           Acr_Element previous)
 {
 
    /* Get rid of the old element from the group */
@@ -366,7 +385,7 @@
               previous - pointer to previous element or NULL if beginning
                  of group element list
 @OUTPUT     : (none)
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Insert an element into a group. 
 @METHOD     : 
 @GLOBALS    : 
@@ -374,10 +393,11 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void insert_element(Acr_Group group, Acr_Element element, 
-                            Acr_Element previous)
+static Acr_Status insert_element(Acr_Group group, Acr_Element element, 
+                                 Acr_Element previous)
 {
    Acr_Element next;
+   long length;
 
    /* Update the pointers */
    if (previous != NULL) {        /* Middle or tail of list */
@@ -397,15 +417,23 @@
 
    /* Update the group fields */
    group->nelements++;
-   group->implicit_total_length += 
-      acr_get_element_total_length(element, ACR_IMPLICIT_VR);
-   group->explicit_total_length += 
-      acr_get_element_total_length(element, ACR_EXPLICIT_VR);
+   length = acr_get_element_total_length(element, ACR_IMPLICIT_VR);
+   if (length <= 0) {
+      return (ACR_OTHER_ERROR);
+   }
+   group->implicit_total_length += length;
+
+   length = acr_get_element_total_length(element, ACR_EXPLICIT_VR);
+   if (length <= 0) {
+      return (ACR_OTHER_ERROR);
+   }
+   group->explicit_total_length += length;
+
 
    /* Update the length element */
    update_group_length_element(group, 
                                acr_get_element_vr_encoding(group->list_head));
-
+   return (ACR_OK);
 }
 
 /* ----------------------------- MNI Header -----------------------------------
@@ -413,7 +441,7 @@
 @INPUT      : group
               element
 @OUTPUT     : (none)
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Insert an element into a group. If an element of the same 
               id already exists in the list, it is removed and deleted.
 @METHOD     : 
@@ -422,8 +450,8 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_group_insert_element(Acr_Group group,
-                                     Acr_Element element)
+Acr_Status acr_group_insert_element(Acr_Group group,
+                                    Acr_Element element)
 {
    Acr_Element next_element, prev_element, cur_element;
    int element_id;
@@ -478,7 +506,7 @@
    }
 
    /* Insert the new element */
-   insert_element(group, element, prev_element);
+   return insert_element(group, element, prev_element);
 
 }
 
@@ -487,7 +515,7 @@
 @INPUT      : group
               element
 @OUTPUT     : (none)
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Add an element to an acr-nema group
 @METHOD     : 
 @GLOBALS    : 
@@ -495,7 +523,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_group_add_element(Acr_Group group, Acr_Element element)
+Acr_Status acr_group_add_element(Acr_Group group, Acr_Element element)
 {
    /* Check that the element belongs in this group */
    if (group->group_id != acr_get_element_group(element)) {
@@ -508,9 +536,7 @@
    }
 
    /* Insert the element at the tail */
-   insert_element(group, element, group->list_tail);
-
-   return;
+   return insert_element(group, element, group->list_tail);
 }
 
 /* ----------------------------- MNI Header -----------------------------------
@@ -526,7 +552,7 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_group_remove_element(Acr_Group group, int element_id)
+void acr_group_remove_element(Acr_Group group, int element_id)
 {
    Acr_Element next_element, prev_element;
 
@@ -564,7 +590,7 @@
 @CREATED    : November 6, 1998 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_group_steal_element(Acr_Group group, Acr_Element element)
+void acr_group_steal_element(Acr_Group group, Acr_Element element)
 {
    int element_id;
    Acr_Element next_element, prev_element;
@@ -605,8 +631,8 @@
 @CREATED    : February 14, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void update_group_length_element(Acr_Group group, 
-                                         Acr_VR_encoding_type vr_encoding)
+static void update_group_length_element(Acr_Group group, 
+                                        Acr_VR_encoding_type vr_encoding)
 {
    long group_length;
    Acr_Element length_element;
@@ -647,7 +673,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_set_group_next(Acr_Group group, Acr_Group next)
+void acr_set_group_next(Acr_Group group, Acr_Group next)
 {
    group->next = next;
    return;
@@ -665,7 +691,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_group_group(Acr_Group group)
+int acr_get_group_group(Acr_Group group)
 {
    return group->group_id;
 }
@@ -682,7 +708,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_get_group_element_list(Acr_Group group)
+Acr_Element acr_get_group_element_list(Acr_Group group)
 {
    return group->list_head;
 }
@@ -700,8 +726,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_get_group_total_length(Acr_Group group,
-                                       Acr_VR_encoding_type vr_encoding)
+long acr_get_group_total_length(Acr_Group group,
+                                Acr_VR_encoding_type vr_encoding)
 {
    if (vr_encoding == ACR_IMPLICIT_VR) 
       return group->implicit_total_length;
@@ -721,7 +747,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_get_group_nelements(Acr_Group group)
+int acr_get_group_nelements(Acr_Group group)
 {
    return group->nelements;
 }
@@ -738,7 +764,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Group acr_get_group_next(Acr_Group group)
+Acr_Group acr_get_group_next(Acr_Group group)
 {
    return group->next;
 }
@@ -760,8 +786,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group, 
-                                            int max_group_id)
+static Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group, 
+                                           int max_group_id)
 {
    int group_id, element_id, next_group_id;
    long group_length;
@@ -894,7 +920,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_input_group(Acr_File *afp, Acr_Group *group)
+Acr_Status acr_input_group(Acr_File *afp, Acr_Group *group)
 {
 
    return acr_input_group_with_max(afp, group, 0);
@@ -914,7 +940,7 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_output_group(Acr_File *afp, Acr_Group group)
+Acr_Status acr_output_group(Acr_File *afp, Acr_Group group)
 {
    long ielement, nelements;
    Acr_Element cur, next;
@@ -965,8 +991,8 @@
 @CREATED    : November 24, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_input_group_list(Acr_File *afp, Acr_Group *group_list,
-                                       int max_group_id)
+Acr_Status acr_input_group_list(Acr_File *afp, Acr_Group *group_list,
+                                int max_group_id)
 {
    Acr_Group cur_group, next_group;
    Acr_Status status;
@@ -1016,7 +1042,7 @@
 @CREATED    : November 6, 1998 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Group acr_find_group(Acr_Group group_list, int group_id)
+Acr_Group acr_find_group(Acr_Group group_list, int group_id)
 {
    Acr_Group group;
    int next_id;
@@ -1050,8 +1076,8 @@
 @CREATED    : November 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Element acr_find_group_element(Acr_Group group_list,
-                                          Acr_Element_Id elid)
+Acr_Element acr_find_group_element(Acr_Group group_list,
+                                   Acr_Element_Id elid)
 {
    Acr_Group group;
 
@@ -1079,7 +1105,7 @@
 @CREATED    : November 24, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_dump_group_list(FILE *file_pointer, Acr_Group group_list)
+void acr_dump_group_list(FILE *file_pointer, Acr_Group group_list)
 {
    Acr_Group cur_group;
 
@@ -1130,13 +1156,13 @@
 @CREATED    : December 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_find_short(Acr_Group group_list, Acr_Element_Id elid, 
-                          int default_value)
+int acr_find_short(Acr_Group group_list, Acr_Element_Id elid, 
+                   int default_value)
 {
    Acr_Element element;
 
    element = acr_find_group_element(group_list, elid);
-   if (element != NULL) 
+   if (element != NULL && acr_get_element_length(element) > 0) 
       return (int) acr_get_element_short(element);
    else
       return default_value;
@@ -1157,13 +1183,13 @@
 @CREATED    : December 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public long acr_find_long(Acr_Group group_list, Acr_Element_Id elid, 
-                          long default_value)
+long acr_find_long(Acr_Group group_list, Acr_Element_Id elid, 
+                   long default_value)
 {
    Acr_Element element;
 
    element = acr_find_group_element(group_list, elid);
-   if (element != NULL) 
+   if (element != NULL && acr_get_element_length(element) > 0) 
       return acr_get_element_long(element);
    else
       return default_value;
@@ -1184,13 +1210,13 @@
 @CREATED    : December 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_find_int(Acr_Group group_list, Acr_Element_Id elid, 
-                        int default_value)
+int acr_find_int(Acr_Group group_list, Acr_Element_Id elid, 
+                 int default_value)
 {
    Acr_Element element;
 
    element = acr_find_group_element(group_list, elid);
-   if (element != NULL) 
+   if (element != NULL && acr_get_element_length(element) > 0) 
       return (int) acr_get_element_numeric(element);
    else
       return default_value;
@@ -1211,13 +1237,13 @@
 @CREATED    : December 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public double acr_find_double(Acr_Group group_list, Acr_Element_Id elid, 
-                              double default_value)
+double acr_find_double(Acr_Group group_list, Acr_Element_Id elid, 
+                       double default_value)
 {
    Acr_Element element;
 
    element = acr_find_group_element(group_list, elid);
-   if (element != NULL) 
+   if (element != NULL && acr_get_element_length(element) > 0) 
       return acr_get_element_numeric(element);
    else
       return default_value;
@@ -1238,13 +1264,13 @@
 @CREATED    : December 10, 1993 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_find_string(Acr_Group group_list, Acr_Element_Id elid, 
-                             char *default_value)
+char *acr_find_string(Acr_Group group_list, Acr_Element_Id elid, 
+                      char *default_value)
 {
    Acr_Element element;
 
    element = acr_find_group_element(group_list, elid);
-   if (element != NULL) 
+   if (element != NULL)         /* Allow zero-length strings */
       return acr_get_element_string(element);
    else
       return default_value;
@@ -1256,7 +1282,7 @@
                  (can be NULL)
               element - element to insert
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Insert an element into a group list. If the group_list is NULL,
               then it is created. Note that the element is not copied, it is
               just inserted into the list, so it should not be modified after
@@ -1268,8 +1294,8 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_element_into_group_list(Acr_Group *group_list,
-                                               Acr_Element element)
+Acr_Status acr_insert_element_into_group_list(Acr_Group *group_list,
+                                              Acr_Element element)
 {
    Acr_Group group, next_group, prev_group;
    int group_id;
@@ -1310,7 +1336,7 @@
    }
 
    /* Insert the element into the appropriate group */
-   acr_group_insert_element(group, element);
+   return acr_group_insert_element(group, element);
 
 }
 
@@ -1320,7 +1346,7 @@
               elid
               value
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Creates and inserts an element into a group list.
 @METHOD     : 
 @GLOBALS    : 
@@ -1328,13 +1354,13 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_short(Acr_Group *group_list, Acr_Element_Id elid, 
-                             int value)
+Acr_Status acr_insert_short(Acr_Group *group_list, Acr_Element_Id elid, 
+                            int value)
 {
    Acr_Element element;
 
    element = acr_create_element_short(elid, value);
-   acr_insert_element_into_group_list(group_list, element);
+   return acr_insert_element_into_group_list(group_list, element);
 
 }
 
@@ -1344,7 +1370,7 @@
               elid
               value
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Creates and inserts an element into a group list.
 @METHOD     : 
 @GLOBALS    : 
@@ -1352,13 +1378,13 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_long(Acr_Group *group_list, Acr_Element_Id elid, 
-                            long value)
+Acr_Status acr_insert_long(Acr_Group *group_list, Acr_Element_Id elid, 
+                           long value)
 {
    Acr_Element element;
 
    element = acr_create_element_long(elid, value);
-   acr_insert_element_into_group_list(group_list, element);
+   return acr_insert_element_into_group_list(group_list, element);
 
 }
 
@@ -1368,7 +1394,7 @@
               elid
               value
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Creates and inserts an element into a group list.
 @METHOD     : 
 @GLOBALS    : 
@@ -1376,13 +1402,14 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_numeric(Acr_Group *group_list, Acr_Element_Id elid, 
-                               double value)
+Acr_Status acr_insert_numeric(Acr_Group *group_list, 
+                              Acr_Element_Id elid, 
+                              double value)
 {
    Acr_Element element;
 
    element = acr_create_element_numeric(elid, value);
-   acr_insert_element_into_group_list(group_list, element);
+   return acr_insert_element_into_group_list(group_list, element);
 
 }
 
@@ -1392,7 +1419,7 @@
               elid
               value
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Creates and inserts an element into a group list.
 @METHOD     : 
 @GLOBALS    : 
@@ -1400,13 +1427,14 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_string(Acr_Group *group_list, Acr_Element_Id elid, 
-                              char *value)
+Acr_Status acr_insert_string(Acr_Group *group_list, 
+                             Acr_Element_Id elid, 
+                             char *value)
 {
    Acr_Element element;
 
    element = acr_create_element_string(elid, value);
-   acr_insert_element_into_group_list(group_list, element);
+   return acr_insert_element_into_group_list(group_list, element);
 
 }
 
@@ -1416,7 +1444,7 @@
               elid
               itemlist
 @OUTPUT     : group_list - modified group list
-@RETURNS    : (nothing)
+@RETURNS    : Acr_Status
 @DESCRIPTION: Creates and inserts an element into a group list.
 @METHOD     : 
 @GLOBALS    : 
@@ -1424,13 +1452,14 @@
 @CREATED    : June 17, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public void acr_insert_sequence(Acr_Group *group_list, Acr_Element_Id elid, 
-                                Acr_Element itemlist)
+Acr_Status acr_insert_sequence(Acr_Group *group_list, 
+                               Acr_Element_Id elid, 
+                               Acr_Element itemlist)
 {
    Acr_Element element;
 
    element = acr_create_element_sequence(elid, itemlist);
-   acr_insert_element_into_group_list(group_list, element);
+   return acr_insert_element_into_group_list(group_list, element);
 
 }
 
@@ -1451,7 +1480,7 @@
 @CREATED    : November 8, 2001 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_Status acr_test_dicom_file(Acr_File *afp)
+Acr_Status acr_test_dicom_file(Acr_File *afp)
 {
 #define DICOM_FILE_MAGIC_OFFSET 128
 #define DICOM_MAGIC_STRING "DICM"
--- a/conversion/Acr_nema/message.c
+++ b/conversion/Acr_nema/message.c
@@ -6,7 +6,16 @@
 @CREATED    : November 16, 1993 (Peter Neelin)
 @MODIFIED   : 
  * $Log: message.c,v $
- * Revision 6.6  2002-12-08 21:43:08  neelin
+ * Revision 6.7.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.7  2004/10/29 13:08:42  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.6  2002/12/08 21:43:08  neelin
  * Fixed excessive memory freeing on error when reading message (seen in linux)
  *
  * Revision 6.5  2002/11/13 03:00:27  neelin
@@ -86,7 +95,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <limits.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Message length group and element id */
--- a/conversion/Acr_nema/read_acr_nema.c
+++ b/conversion/Acr_nema/read_acr_nema.c
@@ -7,7 +7,16 @@
 @CREATED    : March 14, 1994 (Peter Neelin)
 @MODIFIED   : 
  * $Log: read_acr_nema.c,v $
- * Revision 6.2  2001-11-08 14:17:06  neelin
+ * Revision 6.3.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.3  2004/10/29 13:08:42  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.2  2001/11/08 14:17:06  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -60,7 +69,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Define some constants */
--- a/conversion/Acr_nema/sample_dicom_client.c
+++ b/conversion/Acr_nema/sample_dicom_client.c
@@ -5,7 +5,16 @@
 @CREATED    : May 6, 1997 (Peter Neelin)
 @MODIFIED   : 
  * $Log: sample_dicom_client.c,v $
- * Revision 6.2  2001-11-08 14:17:06  neelin
+ * Revision 6.3.2.1  2005-05-12 21:15:30  bert
+ * Initial checkin
+ *
+ * Revision 6.3  2004/10/29 13:08:42  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.2  2001/11/08 14:17:06  neelin
  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
  * files. This function also calls acr_test_byte_order to set up the stream
  * properly and can be used as a direct replacement for that function.
@@ -54,13 +63,12 @@
 ---------------------------------------------------------------------------- */
 
 #ifndef lint
-static char rcsid[]="$Header: /private-cvsroot/minc/conversion/Acr_nema/sample_dicom_client.c,v 6.2 2001-11-08 14:17:06 neelin Exp $";
+static char rcsid[]="$Header: /private-cvsroot/minc/conversion/Acr_nema/sample_dicom_client.c,v 6.3.2.1 2005-05-12 21:15:30 bert Exp $";
 #endif
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 #ifndef public
--- a/conversion/Acr_nema/value_repr.c
+++ b/conversion/Acr_nema/value_repr.c
@@ -6,7 +6,19 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   :  
  * $Log: value_repr.c,v $
- * Revision 6.2  2000-08-16 15:53:46  neelin
+ * Revision 6.4.2.1  2005-05-12 21:15:31  bert
+ * Initial checkin
+ *
+ * Revision 6.4  2005/03/04 00:08:37  bert
+ * Lose private and public
+ *
+ * Revision 6.3  2004/10/29 13:08:42  rotor
+ *  * rewrote Makefile with no dependency on a minc distribution
+ *  * removed all references to the abominable minc_def.h
+ *  * I should autoconf this really, but this is old code that
+ *      is now replaced by Jon Harlaps PERL version..
+ *
+ * Revision 6.2  2000/08/16 15:53:46  neelin
  * Added VR type UN (unknown) which has a length field similar to OB.
  *
  * Revision 6.1  1999/10/29 17:51:54  neelin
@@ -47,7 +59,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <math.h>
-#include <minc_def.h>
 #include <acr_nema.h>
 
 /* Types for VR table entries and conversion functions */
@@ -67,40 +78,40 @@
 };
 
 /* Private functions */
-private void check_table_integrity();
-private Acr_VR_Entry *get_vr_entry(Acr_VR_Type vr_code);
-private Acr_VR_Type find_vr_name(char *vr_name);
-private double return_zero(Acr_VR_Entry *vr_entry, 
-                           Acr_byte_order byte_order,
-                           char *data, long data_length);
-private double string_to_numeric(Acr_VR_Entry *vr_entry, 
-                                 Acr_byte_order byte_order,
-                                 char *data, long data_length);
-private double get_short(Acr_VR_Entry *vr_entry, 
-                         Acr_byte_order byte_order,
-                         char *data, long data_length);
-private double get_long(Acr_VR_Entry *vr_entry, 
+static void check_table_integrity();
+static Acr_VR_Entry *get_vr_entry(Acr_VR_Type vr_code);
+static Acr_VR_Type find_vr_name(char *vr_name);
+static double return_zero(Acr_VR_Entry *vr_entry, 
+                          Acr_byte_order byte_order,
+                          char *data, long data_length);
+static double string_to_numeric(Acr_VR_Entry *vr_entry, 
+                                Acr_byte_order byte_order,
+                                char *data, long data_length);
+static double get_short(Acr_VR_Entry *vr_entry, 
                         Acr_byte_order byte_order,
                         char *data, long data_length);
-private double get_float(Acr_VR_Entry *vr_entry, 
+static double get_long(Acr_VR_Entry *vr_entry, 
+                       Acr_byte_order byte_order,
+                       char *data, long data_length);
+static double get_float(Acr_VR_Entry *vr_entry, 
+                        Acr_byte_order byte_order,
+                        char *data, long data_length);
+static double get_double(Acr_VR_Entry *vr_entry, 
                          Acr_byte_order byte_order,
                          char *data, long data_length);
-private double get_double(Acr_VR_Entry *vr_entry, 
-                          Acr_byte_order byte_order,
-                          char *data, long data_length);
-private double guess_numeric_type(Acr_VR_Entry *vr_entry, 
-                                  Acr_byte_order byte_order,
-                                  char *data, long data_length);
-private void extend_internal_buffer(int length);
-private char *return_empty_string(Acr_VR_Entry *vr_entry, 
-                                  Acr_byte_order byte_order,
-                                  char *data, long data_length);
-private char *return_the_string(Acr_VR_Entry *vr_entry, 
-                                Acr_byte_order byte_order,
-                                char *data, long data_length);
-private char *numeric_to_string(Acr_VR_Entry *vr_entry, 
-                                Acr_byte_order byte_order,
-                                char *data, long data_length);
+static double guess_numeric_type(Acr_VR_Entry *vr_entry, 
+                                 Acr_byte_order byte_order,
+                                 char *data, long data_length);
+static void extend_internal_buffer(int length);
+static char *return_empty_string(Acr_VR_Entry *vr_entry, 
+                                 Acr_byte_order byte_order,
+                                 char *data, long data_length);
+static char *return_the_string(Acr_VR_Entry *vr_entry, 
+                               Acr_byte_order byte_order,
+                               char *data, long data_length);
+static char *numeric_to_string(Acr_VR_Entry *vr_entry, 
+                               Acr_byte_order byte_order,
+                               char *data, long data_length);
 
 /* Table of VRs and conversion routines */
 static Acr_VR_Entry VR_table[] = {
@@ -155,7 +166,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private void check_table_integrity()
+static void check_table_integrity()
 {
    int ientry;
 
@@ -194,7 +205,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private Acr_VR_Entry *get_vr_entry(Acr_VR_Type vr_code)
+static Acr_VR_Entry *get_vr_entry(Acr_VR_Type vr_code)
 {
    CHECK_TABLE_INTEGRITY;
 
@@ -226,7 +237,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-private Acr_VR_Type find_vr_name(char *vr_name)
+static Acr_VR_Type find_vr_name(char *vr_name)
 {
    int ientry;
 
@@ -265,7 +276,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_get_vr_name(Acr_VR_Type vr_code)
+char *acr_get_vr_name(Acr_VR_Type vr_code)
 {
    Acr_VR_Entry *entry;
 
@@ -287,7 +298,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public int acr_test_vr_name(char *vr_name)
+int acr_test_vr_name(char *vr_name)
 {
    Acr_VR_Type vr_code;
 
@@ -308,7 +319,7 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public Acr_VR_Type acr_lookup_vr_name(char *vr_name)
+Acr_VR_Type acr_lookup_vr_name(char *vr_name)
 {
    Acr_VR_Type vr_code;
    int ientry;
@@ -364,9 +375,9 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public double acr_get_numeric_vr(Acr_VR_Type vr_code, 
-                                 Acr_byte_order byte_order,
-                                 char *data, long data_length)
+double acr_get_numeric_vr(Acr_VR_Type vr_code, 
+                          Acr_byte_order byte_order,
+                          char *data, long data_length)
 {
    Acr_VR_Entry *entry;
 
@@ -392,9 +403,9 @@
 @CREATED    : January 31, 1997 (Peter Neelin)
 @MODIFIED   : 
 ---------------------------------------------------------------------------- */
-public char *acr_get_string_vr(Acr_VR_Type vr_code, 
-                               Acr_byte_order byte_order,
-                               char *data, long data_length)
+char *acr_get_string_vr(Acr_VR_Type vr_code, 
+                        Acr_byte_order byte_order,
+                        char *data, long data_length)
 {
    Acr_VR_Entry *entry;
 
@@ -426,25 +437,25 @@
 ---------------------------------------------------------------------------- */
 
 /* ARGSUSED */
-private double return_zero(Acr_VR_Entry *vr_entry, 
-                           Acr_byte_order byte_order,
-                           char *data, long data_length)
+static double return_zero(Acr_VR_Entry *vr_entry, 
+                          Acr_byte_order byte_order,
+                          char *data, long data_length)
 {
    return 0.0;
 }
 
 /* ARGSUSED */
-private double string_to_numeric(Acr_VR_Entry *vr_entry, 
-                                 Acr_byte_order byte_order,
-                                 char *data, long data_length)
+static double string_to_numeric(Acr_VR_Entry *vr_entry, 
+                                Acr_byte_order byte_order,
+                                char *data, long data_length)
 {
    return atof((char *) data);
 }
 
 /* ARGSUSED */
-private double get_short(Acr_VR_Entry *vr_entry, 
-                         Acr_byte_order byte_order,
-                         char *data, long data_length)
+static double get_short(Acr_VR_Entry *vr_entry, 
+                        Acr_byte_order byte_order,
+                        char *data, long data_length)
 {
    unsigned short value;
 
@@ -458,9 +469,9 @@
 }
 
 /* ARGSUSED */
-private double get_long(Acr_VR_Entry *vr_entry, 
-                        Acr_byte_order byte_order,
-                        char *data, long data_length)
+static double get_long(Acr_VR_Entry *vr_entry, 
+                       Acr_byte_order byte_order,
+                       char *data, long data_length)
 {
    long value;
 
@@ -474,9 +485,9 @@
 }
 
 /* ARGSUSED */
-private double get_float(Acr_VR_Entry *vr_entry, 
-                         Acr_byte_order byte_order,
-                         char *data, long data_length)
+static double get_float(Acr_VR_Entry *vr_entry, 
+                        Acr_byte_order byte_order,
+                        char *data, long data_length)
 {
    float value;
 
@@ -490,9 +501,9 @@
 }
 
 /* ARGSUSED */
-private double get_double(Acr_VR_Entry *vr_entry, 
-                          Acr_byte_order byte_order,
-                          char *data, long data_length)
+static double get_double(Acr_VR_Entry *vr_entry, 
+                         Acr_byte_order byte_order,
+                         char *data, long data_length)
 {
    double value;
 
@@ -506,9 +517,9 @@
 }
 
 /* ARGSUSED */
-private double guess_numeric_type(Acr_VR_Entry *vr_entry, 
-                                  Acr_byte_order byte_order,
-                                  char *data, long data_length)
+static double guess_numeric_type(Acr_VR_Entry *vr_entry, 
+                                 Acr_byte_order byte_order,
+                                 char *data, long data_length)
 {
    switch (data_length) {
    case ACR_SIZEOF_SHORT:
@@ -547,7 +558,7 @@
 static char *internal_string_buffer = NULL;
 static int length_of_internal_string = 0;
 
-private void extend_internal_buffer(int length)
+static void extend_internal_buffer(int length)
 {
 
    if (length+1 > length_of_internal_string) {
@@ -561,9 +572,9 @@
 }
 
 /* ARGSUSED */
-private char *return_empty_string(Acr_VR_Entry *vr_entry, 
-                                  Acr_byte_order byte_order,
-                                  char *data, long data_length)
+static char *return_empty_string(Acr_VR_Entry *vr_entry, 
+                                 Acr_byte_order byte_order,
+                                 char *data, long data_length)
 {
    extend_internal_buffer(LINE_LENGTH);
 
@@ -573,17 +584,17 @@
 }
 
 /* ARGSUSED */
-private char *return_the_string(Acr_VR_Entry *vr_entry, 
-                                Acr_byte_order byte_order,
-                                char *data, long data_length)
+static char *return_the_string(Acr_VR_Entry *vr_entry, 
+                               Acr_byte_order byte_order,
+                               char *data, long data_length)
 {
    return (char *) data;
 }
 
 /* ARGSUSED */
-private char *numeric_to_string(Acr_VR_Entry *vr_entry, 
-                                Acr_byte_order byte_order,
-                                char *data, long data_length)
+static char *numeric_to_string(Acr_VR_Entry *vr_entry, 
+                               Acr_byte_order byte_order,
+                               char *data, long data_length)
 {
    extend_internal_buffer(LINE_LENGTH);
    (void) sprintf(internal_string_buffer, "%.6g",
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/acr_element_defs.h
@@ -0,0 +1,148 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : dicom_element_defs.h
+@DESCRIPTION: Element definitions for DICOM
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : January 28, 1997 (Peter Neelin)
+@MODIFIED   : 
+@COPYRIGHT  :
+              Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* Define standard UID's */
+#define FAVORITE_ABSTRACT_SYNTAX       ACR_MR_IMAGE_STORAGE_UID
+#define ACR_MR_IMAGE_STORAGE_UID       "1.2.840.10008.5.1.4.1.1.4"
+#define ACR_EXPLICIT_VR_BIG_END_UID    "1.2.840.10008.1.2.2"
+#define ACR_EXPLICIT_VR_LITTLE_END_UID "1.2.840.10008.1.2.1"
+#define ACR_IMPLICIT_VR_LITTLE_END_UID "1.2.840.10008.1.2"
+#define ACR_APPLICATION_CONTEXT_UID    "1.2.840.10008.3.1.1.1"
+
+#define ACR_IMAGE_GID 0x7fe0
+#define ACR_IMAGE_EID 0x0010
+
+/* Define acr-nema constants */
+#define ACR_MODALITY_MR "MR"
+#define ACR_MODALITY_PT "PT"
+
+/* Defined values for pixel representation (0028,0103) */
+#define ACR_PIXEL_REP_UNSIGNED 0 /* Unsigned magnitude */
+#define ACR_PIXEL_REP_SIGNED 1  /* 2's complement signed */
+
+/* Element id's for DICOM */
+GLOBAL_ELEMENT(ACR_Affected_SOP_class_UID    , 0x0000, 0x0002, UI);
+GLOBAL_ELEMENT(ACR_Command                   , 0x0000, 0x0100, US);
+GLOBAL_ELEMENT(ACR_Message_id                , 0x0000, 0x0110, US);
+GLOBAL_ELEMENT(ACR_Message_id_brt            , 0x0000, 0x0120, US);
+GLOBAL_ELEMENT(ACR_Priority                  , 0x0000, 0x0700, US);
+GLOBAL_ELEMENT(ACR_Dataset_type              , 0x0000, 0x0800, US);
+GLOBAL_ELEMENT(ACR_Status                    , 0x0000, 0x0900, US);
+GLOBAL_ELEMENT(ACR_Affected_SOP_instance_UID , 0x0000, 0x1000, UI);
+GLOBAL_ELEMENT(ACR_Move_originator_AE_title  , 0x0000, 0x1031, AE);
+
+GLOBAL_ELEMENT(ACR_Image_type            , 0x0008, 0x0008, CS);
+GLOBAL_ELEMENT(ACR_SOP_Class_UID         , 0x0008, 0x0016, UI);
+GLOBAL_ELEMENT(ACR_Study_date            , 0x0008, 0x0020, DA);
+GLOBAL_ELEMENT(ACR_Series_date           , 0x0008, 0x0021, DA);
+GLOBAL_ELEMENT(ACR_Acquisition_date      , 0x0008, 0x0022, DA);
+GLOBAL_ELEMENT(ACR_Study_time            , 0x0008, 0x0030, TM);
+GLOBAL_ELEMENT(ACR_Series_time           , 0x0008, 0x0031, TM);
+GLOBAL_ELEMENT(ACR_Acquisition_time      , 0x0008, 0x0032, TM);
+GLOBAL_ELEMENT(ACR_Image_time            , 0x0008, 0x0033, TM);
+GLOBAL_ELEMENT(ACR_Modality              , 0x0008, 0x0060, CS);
+GLOBAL_ELEMENT(ACR_Manufacturer          , 0x0008, 0x0070, LO);
+GLOBAL_ELEMENT(ACR_Institution_id        , 0x0008, 0x0080, LO);
+GLOBAL_ELEMENT(ACR_Referring_physician   , 0x0008, 0x0090, PN);
+GLOBAL_ELEMENT(ACR_Station_id            , 0x0008, 0x1010, SH);
+GLOBAL_ELEMENT(ACR_Procedure_description , 0x0008, 0x1030, LO);
+GLOBAL_ELEMENT(ACR_Performing_physician  , 0x0008, 0x1050, PN);
+GLOBAL_ELEMENT(ACR_Operators_name        , 0x0008, 0x1070, PN);
+GLOBAL_ELEMENT(ACR_Manufacturer_model    , 0x0008, 0x1090, LO);
+
+GLOBAL_ELEMENT(ACR_Patient_name          , 0x0010, 0x0010, PN);
+GLOBAL_ELEMENT(ACR_Patient_identification, 0x0010, 0x0020, LO);
+GLOBAL_ELEMENT(ACR_Patient_birth_date    , 0x0010, 0x0030, DA);
+GLOBAL_ELEMENT(ACR_Patient_sex           , 0x0010, 0x0040, CS);
+GLOBAL_ELEMENT(ACR_Patient_age           , 0x0010, 0x1010, AS);
+GLOBAL_ELEMENT(ACR_Patient_weight        , 0x0010, 0x1030, DS);
+
+GLOBAL_ELEMENT(ACR_Scanning_sequence     , 0x0018, 0x0020, CS);
+GLOBAL_ELEMENT(ACR_MR_acquisition_type   , 0x0018, 0x0023, CS);
+GLOBAL_ELEMENT(ACR_Sequence_name         , 0x0018, 0x0024, CS);
+GLOBAL_ELEMENT(ACR_Slice_thickness       , 0x0018, 0x0050, DS);
+GLOBAL_ELEMENT(ACR_Repetition_time       , 0x0018, 0x0080, DS);
+GLOBAL_ELEMENT(ACR_Echo_time             , 0x0018, 0x0081, DS);
+GLOBAL_ELEMENT(ACR_Inversion_time        , 0x0018, 0x0082, DS);
+GLOBAL_ELEMENT(ACR_Nr_of_averages        , 0x0018, 0x0083, DS);
+GLOBAL_ELEMENT(ACR_Imaging_frequency     , 0x0018, 0x0084, DS);
+GLOBAL_ELEMENT(ACR_Imaged_nucleus        , 0x0018, 0x0085, SH);
+GLOBAL_ELEMENT(ACR_Echo_number           , 0x0018, 0x0086, IS);
+GLOBAL_ELEMENT(ACR_Magnetic_field_strength,0x0018, 0x0087, DS);
+GLOBAL_ELEMENT(ACR_Spacing_between_slices, 0x0018, 0x0088, DS);
+GLOBAL_ELEMENT(ACR_Number_of_phase_encoding_steps, 0x0018, 0x0089, IS);
+GLOBAL_ELEMENT(ACR_Echo_train_length     , 0x0018, 0x0091, IS);
+GLOBAL_ELEMENT(ACR_Percent_sampling      , 0x0018, 0x0093, DS);
+GLOBAL_ELEMENT(ACR_Percent_phase_field_of_view, 0x0018, 0x0094, DS);
+GLOBAL_ELEMENT(ACR_Pixel_bandwidth       , 0x0018, 0x0095, DS);
+GLOBAL_ELEMENT(ACR_Device_serial_number  , 0x0018, 0x1000, LO);
+GLOBAL_ELEMENT(ACR_Software_versions     , 0x0018, 0x1020, LO);
+GLOBAL_ELEMENT(ACR_Protocol_name         , 0x0018, 0x1030, LO);
+GLOBAL_ELEMENT(ACR_Calibration_date      , 0x0018, 0x1200, DA);
+GLOBAL_ELEMENT(ACR_Actual_frame_duration , 0x0018, 0x1242, IS);
+GLOBAL_ELEMENT(ACR_Receive_coil_name     , 0x0018, 0x1250, SH);
+GLOBAL_ELEMENT(ACR_Transmit_coil_name    , 0x0018, 0x1251, SH);
+GLOBAL_ELEMENT(ACR_Acquisition_matrix    , 0x0018, 0x1310, US);
+GLOBAL_ELEMENT(ACR_Phase_encoding_direction, 0x0018, 0x1312, CS);
+GLOBAL_ELEMENT(ACR_Flip_angle            , 0x0018, 0x1314, DS);
+GLOBAL_ELEMENT(ACR_SAR                   , 0x0018, 0x1316, DS);
+GLOBAL_ELEMENT(ACR_Acq_comments          , 0x0018, 0x4000, LT);
+GLOBAL_ELEMENT(ACR_Patient_position      , 0x0018, 0x5100, CS);
+
+GLOBAL_ELEMENT(ACR_Study                 , 0x0020, 0x0010, SH);
+GLOBAL_ELEMENT(ACR_Series                , 0x0020, 0x0011, IS);
+GLOBAL_ELEMENT(ACR_Acquisition           , 0x0020, 0x0012, IS);
+GLOBAL_ELEMENT(ACR_Image                 , 0x0020, 0x0013, IS);
+GLOBAL_ELEMENT(ACR_Image_position_patient_old, 0x0020, 0x0030, DS);
+GLOBAL_ELEMENT(ACR_Image_position_patient, 0x0020, 0x0032, DS);
+GLOBAL_ELEMENT(ACR_Image_orientation_patient_old,
+	                                   0x0020, 0x0035, DS);
+GLOBAL_ELEMENT(ACR_Image_orientation_patient,
+	                                   0x0020, 0x0037, DS);
+GLOBAL_ELEMENT(ACR_Acquisitions_in_series, 0x0020, 0x1001, IS);
+GLOBAL_ELEMENT(ACR_Images_in_acquisition,  0x0020, 0x1002, IS);
+GLOBAL_ELEMENT(ACR_Slice_location,         0x0020, 0x1041, DS);
+
+GLOBAL_ELEMENT(ACR_Rows                  , 0x0028, 0x0010, US);
+GLOBAL_ELEMENT(ACR_Columns               , 0x0028, 0x0011, US);
+GLOBAL_ELEMENT(ACR_Pixel_size            , 0x0028, 0x0030, DS);
+GLOBAL_ELEMENT(ACR_Bits_allocated        , 0x0028, 0x0100, US);
+GLOBAL_ELEMENT(ACR_Bits_stored           , 0x0028, 0x0101, US);
+GLOBAL_ELEMENT(ACR_High_bit              , 0x0028, 0x0102, US);
+GLOBAL_ELEMENT(ACR_Pixel_representation  , 0x0028, 0x0103, US);
+GLOBAL_ELEMENT(ACR_Smallest_pixel_value  , 0x0028, 0x0106, US);
+GLOBAL_ELEMENT(ACR_Largest_pixel_value   , 0x0028, 0x0107, US);
+GLOBAL_ELEMENT(ACR_Image_location        , 0x0028, 0x0200, US);
+GLOBAL_ELEMENT(ACR_Window_centre         , 0x0028, 0x1050, DS);
+GLOBAL_ELEMENT(ACR_Window_width          , 0x0028, 0x1051, DS);
+GLOBAL_ELEMENT(ACR_Rescale_intercept     , 0x0028, 0x1052, DS);
+GLOBAL_ELEMENT(ACR_Rescale_slope         , 0x0028, 0x1053, DS);
+
+GLOBAL_ELEMENT(ACR_Number_of_slices      , 0x0054, 0x0081, US);
+GLOBAL_ELEMENT(ACR_Number_of_time_slices , 0x0054, 0x0101, US);
+GLOBAL_ELEMENT(ACR_Units                 , 0x0054, 0x1001, CS);
+GLOBAL_ELEMENT(ACR_Frame_reference_time  , 0x0054, 0x1300, DS);
+
+GLOBAL_ELEMENT(ACR_Pixel_data            , ACR_IMAGE_GID, ACR_IMAGE_EID, OW);
+
+
+
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dcm2mnc.c
@@ -0,0 +1,931 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : dcm2mnc.c
+@DESCRIPTION: Program to convert dicom files to minc
+@GLOBALS    : 
+@CREATED    : June 2001 (Rick Hoge)
+@MODIFIED   : 
+ * $Log: dcm2mnc.c,v $
+ * Revision 1.14.2.1  2005-05-12 21:16:47  bert
+ * Initial checkin
+ *
+ * Revision 1.14  2005/05/09 15:32:02  bert
+ * Change version to 2.0.05
+ *
+ * Revision 1.13  2005/04/29 23:09:36  bert
+ * Add support for -stdin option to read file list from standard input
+ *
+ * Revision 1.12  2005/04/26 23:49:24  bert
+ * Update version
+ *
+ * Revision 1.11  2005/04/18 16:38:42  bert
+ * Fix up file type detection code
+ *
+ * Revision 1.10  2005/04/06 13:26:41  bert
+ * Fix listing option
+ *
+ * Revision 1.9  2005/04/05 21:52:24  bert
+ * Add -minmax option to enable use of explicit DICOM pixel min/max information, and updated version number
+ *
+ * Revision 1.8  2005/03/18 19:10:31  bert
+ * Scan coordinate and location information for validity before relying on it
+ *
+ * Revision 1.7  2005/03/15 17:03:34  bert
+ * Yet another directory expansion fix (sigh)
+ *
+ * Revision 1.6  2005/03/14 22:51:33  bert
+ * Actually get the directory expansion working properly...
+ *
+ * Revision 1.5  2005/03/14 22:25:41  bert
+ * If a directory is specified on the file list, expand it internally.  This gets around shell limitations.
+ *
+ * Revision 1.4  2005/03/03 20:10:14  bert
+ * Consider patient_id and patient_name when sorting into series
+ *
+ * Revision 1.3  2005/03/03 18:59:15  bert
+ * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+ *
+ * Revision 1.2  2005/03/02 18:23:32  bert
+ * Added mosaic sequence and bitwise options
+ *
+ * Revision 1.1  2005/02/17 16:38:09  bert
+ * Initial checkin, revised DICOM to MINC converter
+ *
+ * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+ * Leili's dicom server for sonata
+ *
+ * Revision 1.5  2002/04/26 12:02:50  rhoge
+ * updated usage statement for new forking defaults
+ *
+ * Revision 1.4  2002/04/26 11:32:48  rhoge
+ * made forking default
+ *
+ * Revision 1.3  2002/03/23 13:17:53  rhoge
+ * added support for Bourget network pushed dicom files, cleaned up
+ * file check and read_numa4_dicom vr check/assignment
+ *
+ * Revision 1.2  2002/03/22 19:19:36  rhoge
+ * Numerous fixes -
+ * - handle Numaris 4 Dicom patient name
+ * - option to cleanup input files
+ * - command option
+ * - list-only option
+ * - debug mode
+ * - user supplied name, idstr
+ * - anonymization
+ *
+ * Revision 1.1  2002/03/22 03:50:02  rhoge
+ * new name for standalone dicom to minc converter
+ *
+ * Revision 1.3  2002/03/22 00:38:08  rhoge
+ * Added progress bar, wait for children at end, updated feedback statements
+ *
+ * Revision 1.2  2002/03/19 13:13:56  rhoge
+ * initial working mosaic support - I think time is scrambled though.
+ *
+ * Revision 1.1  2001/12/31 17:26:21  rhoge
+ * adding file to repository- compiles without warning and converts non-mosaic
+ * Numa 4 files. 
+ * Will probably not work for Numa 3 files yet.
+ *
+---------------------------------------------------------------------------- */
+
+static const char rcsid[]="$Header: /private-cvsroot/minc/conversion/dcm2mnc/dcm2mnc.c,v 1.14.2.1 2005-05-12 21:16:47 bert Exp $";
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dirent.h>
+#include <ParseArgv.h>
+
+#define GLOBAL_ELEMENT_DEFINITION /* To define elements */
+#include "dcm2mnc.h"
+
+/* Function Prototypes */
+static int dcm_sort_function(const void *entry1, const void *entry2);
+static void use_the_files(int num_files, 
+                          Data_Object_Info *data_info[],
+                          const char *out_dir);
+static void usage(void);
+static void free_list(int num_files, 
+                      const char **file_list, 
+                      Data_Object_Info **file_info_list);
+static int check_file_type_consistency(int num_files, const char *file_list[]);
+
+
+struct globals G;
+
+#define VERSION_STRING "2.0.05 built " __DATE__ " " __TIME__
+
+ArgvInfo argTable[] = {
+    {NULL, ARGV_VERINFO, VERSION_STRING, NULL, NULL },
+    {"-clobber", ARGV_CONSTANT, (char *) TRUE, (char *) &G.clobber,
+     "Overwrite output files"},
+    {"-list", ARGV_CONSTANT, (char *) TRUE, (char *) &G.List,
+     "Print list of series (don't create files)"},
+    {"-anon", ARGV_CONSTANT, (char *) TRUE, (char *) &G.Anon,
+     "Exclude subject name from file header"},
+    {"-descr", ARGV_STRING, (char *) 1, G.Name,
+     "Use <str> as session descriptor (default = patient initials)"},
+    {"-cmd", ARGV_STRING, (char *) 1, G.command_line, 
+     "Apply <command> to output files (e.g. gzip)"},
+    {"-verbose", ARGV_CONSTANT, (char *) LO_LOGGING, (char *) &G.Debug,
+     "Print debugging information"},
+    {"-debug", ARGV_CONSTANT, (char *) HI_LOGGING, (char *) &G.Debug,
+     "Print lots of debugging information"},
+    {"-nosplitecho", ARGV_CONSTANT, (char *) FALSE, (char *) &G.splitEcho,
+     "Combine all echoes into a single file."},
+    {"-splitdynamic", ARGV_CONSTANT, (char *) TRUE, (char *)&G.splitDynScan,
+     "Split dynamic scans into a separate files."},
+    {"-opts", ARGV_INT, (char *) 1, (char *) &G.opts, 
+     "Set debugging options"},
+
+    {"-descending", 
+     ARGV_CONSTANT, 
+     (char *) MOSAIC_SEQ_DESCENDING, 
+     (char *) &G.mosaic_seq,
+     "Mosaic sequence is in descending slice order."},
+
+    {"-interleaved", 
+     ARGV_CONSTANT, 
+     (char *) MOSAIC_SEQ_INTERLEAVED, 
+     (char *) &G.mosaic_seq,
+     "Mosaic sequence is in interleaved slice order."},
+
+    {"-minmax", 
+     ARGV_CONSTANT, 
+     (char *)TRUE, 
+     (char *) &G.useMinMax,
+     "Honor DICOM pixel minimum and pixel maximum values."},
+
+    {"-stdin",
+     ARGV_CONSTANT,
+     (char *)TRUE,
+     (char *)&G.use_stdin,
+     "Read file list from standard input."},
+
+    {NULL, ARGV_END, NULL, NULL, NULL}
+
+};
+
+int 
+main(int argc, char *argv[])
+{
+    int ifile;
+    Acr_Group group_list;
+    const char **file_list;     /* List of file names */
+    Data_Object_Info **file_info_list;
+    int num_file_args;          /* Number of files on command line */
+    int num_files;              /* Total number of files */
+    string_t out_dir;           /* Output directory */
+    string_t message;           /* Generic message */
+    int num_files_ok;           /* Actual number of DICOM/IMA files */
+    struct stat st;
+    int length;
+
+    G.mosaic_seq = MOSAIC_SEQ_ASCENDING; /* Assume ascending by default. */
+    G.splitDynScan = FALSE;     /* Don't split dynamic scans by default */
+    G.splitEcho = TRUE;         /* Do split by echo by default */
+    G.use_stdin = FALSE;        /* Do not read file list from stdin */
+
+    G.minc_history = time_stamp(argc, argv); /* Create minc history string */
+
+    G.pname = argv[0];          /* get program name */
+    
+    /* Get the input parameters and file names.
+     */
+    if (ParseArgv(&argc, argv, argTable, 0)) {
+        usage();
+    }
+
+    if (argc < 2) {
+        usage();
+    }
+
+    if (G.List) {
+        num_file_args = argc - 1; /* Assume no directory given. */
+    }
+    else {
+        num_file_args = argc - 2; /* Assume last arg is directory. */
+
+        strcpy(out_dir, argv[argc - 1]); 
+
+        /* make sure path ends with slash 
+         */
+        length = strlen(out_dir);
+        if (out_dir[length - 1] != '/') {
+            out_dir[length++] = '/';
+            out_dir[length++] = '\0';
+        }
+
+        if (stat(out_dir, &st) != 0 || !S_ISDIR(st.st_mode)) {
+            fprintf(stderr, "The final argument, '%s', is not a directory\n", 
+                    out_dir);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    /* Get space for file lists */
+    /* Allocate the array of pointers used to implement the
+     * list of filenames.
+     */
+    file_list = malloc(num_file_args * sizeof(char *));
+    CHKMEM(file_list);
+
+    /* Go through the list of files, expanding directories where they
+     * are encountered...
+     */
+    num_files = 0;
+    for (ifile = 0 ; ifile < num_file_args; ifile++) {
+        if (stat(argv[ifile + 1], &st) == 0 && S_ISDIR(st.st_mode)) {
+            DIR *dp;
+            struct dirent *np;
+            char *tmp_str;
+
+            if (G.Debug) {
+                printf("Expanding directory '%s'\n", argv[ifile + 1]);
+            }
+
+            length = strlen(argv[ifile + 1]);
+
+            dp = opendir(argv[ifile + 1]);
+            if (dp != NULL) {
+                while ((np = readdir(dp)) != NULL) {
+                    /* Generate the full path to the file.
+                     */
+                    tmp_str = malloc(length + strlen(np->d_name) + 2);
+                    strcpy(tmp_str, argv[ifile + 1]);
+                    if (tmp_str[length-1] != '/') {
+                        tmp_str[length] = '/';
+                        tmp_str[length+1] = '\0';
+                    }
+                    strcat(&tmp_str[length], np->d_name);
+                    if (stat(tmp_str, &st) == 0 && S_ISREG(st.st_mode)) {
+                        file_list = realloc(file_list,
+                                            (num_files + 1) * sizeof(char *));
+                        file_list[num_files++] = tmp_str;
+                    }
+                    else {
+                        free(tmp_str);
+                    }
+                }
+                closedir(dp);
+            }
+            else {
+                fprintf(stderr, "Error opening directory '%s'\n", 
+                        argv[ifile + 1]);
+            }
+        }
+        else {
+            file_list[num_files++] = strdup(argv[ifile + 1]);
+        }
+    }
+
+    if (G.use_stdin) {
+        char linebuf[1024];
+        char *p;
+
+        while (fgets(linebuf, sizeof(linebuf), stdin) != NULL) {
+            /* Strip off newline at end of string.
+             */
+            for (p = linebuf; *p != '\0'; p++) {
+                if (*p == '\n') {
+                    *p = '\0';
+                }
+            }
+            if (strlen(linebuf) != 0) {
+                file_list = realloc(file_list,
+                                    (num_files + 1) * sizeof(char *));
+                file_list[num_files++] = strdup(linebuf);
+            }
+        }
+    }
+
+    file_info_list = malloc(num_files * sizeof(*file_info_list));
+    CHKMEM(file_info_list);
+
+    /* figure out what kind of files we have -
+     * supported types are:
+     *
+     *  IMA (Siemens .ima format - Numaris 3.5)
+     *  N4DCM (Siemens DICOM - Numaris 4)
+     *
+     * if not all same type, return an error 
+     *
+     * we start by assuming N4DCM with no offset - we find that the
+     * file is IMA or has an offset (the 128 byte + DICM offset seen
+     * on Syngo CD's and exports) then the appropriate flag will be
+     * set.
+     */
+    printf("Checking file types...\n");
+
+    if (check_file_type_consistency(num_files, file_list) < 0) {
+        exit(EXIT_FAILURE);
+    }
+
+    /* Now loop over all files, getting basic info on each
+     */
+
+    num_files_ok = 0;
+    for (ifile = 0; ifile < num_files; ifile++) {
+        const char *cur_fname_ptr = file_list[ifile];
+
+        if (!G.Debug) {
+            sprintf(message, "Parsing %d files", num_files);
+            progress(ifile, num_files, message);
+        }
+
+        if (G.file_type == IMA) {
+            group_list = siemens_to_dicom(cur_fname_ptr, ACR_IMAGE_GID - 1);
+        }
+        else {
+            /* read up to but not including pixel data
+             */
+            group_list = read_numa4_dicom(cur_fname_ptr, ACR_IMAGE_GID - 1);
+        } 
+
+        if (group_list == NULL) {
+            /* This file appears to be invalid - it is probably a dicomdir
+             * file or some other stray junk in the directory.
+             */
+            printf("Skipping file %s, which is not in the expected format.\n",
+                   cur_fname_ptr);
+            free((void *) cur_fname_ptr);
+        }
+        else {
+            /* Copy it back to the (possibly earlier) position in the real
+             * file list.
+             */
+            file_list[num_files_ok] = cur_fname_ptr;
+
+            /* allocate space for the current entry to file_info_list 
+             */
+            file_info_list[num_files_ok] = malloc(sizeof(*file_info_list[0]));
+            CHKMEM(file_info_list[num_files_ok]);
+            file_info_list[num_files_ok]->file_index = num_files_ok;
+
+            parse_dicom_groups(group_list, file_info_list[num_files_ok]);
+
+            /* put the file name into the info list
+             */
+            file_info_list[num_files_ok]->file_name = strdup(file_list[num_files_ok]);
+
+            /* Delete the group list now that we're done with it
+             */
+            acr_delete_group_list(group_list);
+            num_files_ok++;
+        }
+    } /* end of loop over files to get basic info */
+
+    if (G.Debug) {
+        printf("Using %d files\n", num_files_ok);
+    }
+
+    num_files = num_files_ok;
+
+    printf("Sorting %d files...   ", num_files);
+
+    /* sort the files into series based on acquisition number
+     */
+    qsort(file_info_list, num_files, sizeof(file_info_list[0]),
+          dcm_sort_function);
+
+    /* If DEBUG, print a list of all files.
+     */
+    if (G.Debug) {
+        printf("\n");
+        for (ifile = 0; ifile < num_files; ifile++) {
+            Data_Object_Info *info = file_info_list[ifile];
+            char *fname;
+
+            if ((ifile % 16) == 0) {
+                printf("%-4s %-32.32s %-14s %-8s %-8s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-5s %-16s\n",
+                       "num",
+                       "filename",
+                       "studyid",
+                       "serialno",
+                       "acq",
+                       "nec",
+                       "iec",
+                       "ndy",
+                       "idy",
+                       "nsl",
+                       "isl",
+                       "acol",
+                       "rcol",
+                       "mrow",
+                       "img#",
+                       "seq");
+            }
+            /* Print out info about file.  Truncate the name if necessary.
+             */
+            fname = info->file_name;
+            if (strlen(fname) > 32) {
+                fname += strlen(fname) - 32;
+            }
+
+            printf("%4d %-32.32s %14.6f %8d %8d %4d %4d %4d %4d %4d %4d %4d %4d %4d %5d %-16s\n",
+                   ifile,
+                   fname,
+                   info->study_id,
+                   info->scanner_serialno,
+                   info->acq_id,
+                   info->num_echoes,
+                   info->echo_number,
+                   info->num_dyn_scans,
+                   info->dyn_scan_number,
+                   info->num_slices_nominal,
+                   info->slice_number,
+                   info->acq_cols,
+                   info->rec_cols,
+                   info->num_mosaic_rows,
+                   info->global_image_number,
+                   info->sequence_name);
+        }
+    }
+
+    printf("Done sorting files.\n");
+
+    /* Loop over files, processing by acquisition */ 
+
+    if (G.List) {
+        printf("Listing files by series...\n");
+    }
+    else {
+        printf("Processing files, one series at a time...\n");
+    }
+
+    use_the_files(num_files, file_info_list, out_dir);
+
+    if (G.List) {
+        printf("Done listing files.\n");
+    }
+    else {
+        printf("Done processing files.\n");
+    }
+
+    free_list(num_files, file_list, file_info_list);
+
+    free(file_list);
+    free(file_info_list);
+
+    
+    exit(EXIT_SUCCESS);
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : free_list
+@INPUT      : num_files - number of files in list
+              file_list - array of file names
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Frees up things pointed to in pointer arrays. Does not free
+              the arrays themselves.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : November 22, 1993 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+static void 
+free_list(int num_files, 
+          const char **file_list, 
+          Data_Object_Info **file_info_list)
+{
+    int i;
+
+    for (i = 0; i < num_files; i++) {
+        if (file_list[i] != NULL) {
+            free((void *) file_list[i]);
+        }
+        if (file_info_list[i] != NULL) {
+            free(file_info_list[i]);
+        }
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : dcm_sort_function
+@INPUT      : entry1
+              entry2
+@OUTPUT     : (none)
+@RETURNS    : -1, 0, 1 for lt, eq, gt
+@DESCRIPTION: Function to compare two dcm series numbers
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 2001 (Rick Hoge)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+static int 
+dcm_sort_function(const void *entry1, const void *entry2)
+{
+    Data_Object_Info **file_info_list1 = (Data_Object_Info **) entry1;
+    Data_Object_Info **file_info_list2 = (Data_Object_Info **) entry2;
+
+    // make a sort-able session ID number:  date.time
+    double session1 = (*file_info_list1)->study_date +
+        (*file_info_list1)->study_time / 1e6;
+    double session2 = (*file_info_list2)->study_date +
+        (*file_info_list2)->study_time / 1e6;
+
+    // series index
+    int series1 = (*file_info_list1)->acq_id;
+    int series2 = (*file_info_list2)->acq_id;
+
+    // frame index
+    int frame1 = (*file_info_list1)->dyn_scan_number;
+    int frame2 = (*file_info_list2)->dyn_scan_number;
+
+    // image index
+    int image1 = (*file_info_list1)->global_image_number;
+    int image2 = (*file_info_list2)->global_image_number;
+
+    int slice1 = (*file_info_list1)->slice_number;
+    int slice2 = (*file_info_list2)->slice_number;
+
+    if (session1 < session2) return -1;
+    else if (session1 > session2) return 1;
+    else if (series1 < series2) return -1;
+    else if (series1 > series2) return 1;
+    else if (frame1 < frame2) return -1;
+    else if (frame1 > frame2) return 1;
+    else if (image1 < image2) return -1;
+    else if (image1 > image2) return 1;
+    else if (slice1 < slice2) return -1;
+    else if (slice1 > slice2) return 1;
+    else return 0;
+}
+
+static void 
+usage(void)
+{
+    fprintf(stderr, "\nUsage: %s [options] file1 file2 file3 ... destdir\n",
+            G.pname);
+    fprintf(stderr, "\n");
+    fprintf(stderr,"Files are named according to the following convention:\n\n");
+    fprintf(stderr,"  Directory: lastname_firstname_yyyymmdd_hhmmss/\n");
+    fprintf(stderr,"  Files:     lastname_firstname_yyyymmdd_hhmmss_series_modality.mnc\n\n");
+
+    exit(EXIT_FAILURE);
+}
+
+static void
+use_the_files(int num_files, 
+              Data_Object_Info *di_ptr[],
+              const char *out_dir)
+{
+    int ifile;
+    int acq_num_files;
+    const char **acq_file_list;
+    int *used_file;
+    int *acq_file_index;
+    double cur_study_id;
+    int cur_acq_id;
+    int cur_rec_num;
+    int cur_image_type;
+    int cur_echo_number;
+    int cur_dyn_scan_number;
+    string_t cur_patient_name;
+    string_t cur_patient_id;
+    int exit_status;
+    char *output_file_name;
+    string_t file_prefix;
+    int output_uid;
+    int output_gid;
+    string_t string;
+    FILE *fp;
+    int trust_location;
+    int trust_coord;
+    int user_opts;              /* Options as set by user. We may override.. */
+
+    if (out_dir != NULL) {    /* if an output directory name has been 
+                               * provided on the command line
+                               */
+        if (G.Debug) {
+            printf("Using directory '%s'\n", out_dir);
+        }
+        strcpy(file_prefix, out_dir);
+    }
+    else {
+        file_prefix[0] = '\0';
+    }
+
+    if (G.Debug) {                /* debugging */
+        printf("file_prefix:  [%s]\n", file_prefix);
+    }
+
+    /* Allocate space for acquisition file list.
+     */
+    acq_file_list = malloc(num_files * sizeof(*acq_file_list));
+    CHKMEM(acq_file_list);
+
+    acq_file_index = malloc(num_files * sizeof(*acq_file_index));
+    CHKMEM(acq_file_index);
+
+    used_file = malloc(num_files * sizeof(*used_file));
+    CHKMEM(used_file);
+
+    for (ifile = 0; ifile < num_files; ifile++) {
+        used_file[ifile] = FALSE;
+    }
+
+    for (;;) {
+
+        /* Loop through files, looking for an acquisition
+         * 
+         * file groups should already have been sorted into acquisitions
+         * in calling program 
+         *
+         * this code is in a `forever' loop because we loop over multiple
+         * acquisitions until all of the files are used up.
+         */
+
+        acq_num_files = 0;
+
+        for (ifile = 0; ifile < num_files; ifile++) {
+
+            /* If already marked used (can this happen???), we've already
+             * written the file to an output somewhere.
+             */
+            if (used_file[ifile]) {
+                continue;
+            }
+
+            if (acq_num_files == 0) {
+	 
+                /* found first file: set all current attributes like
+                 * study id, acq id, rec num(?), image type, echo
+                 * number, dyn scan number, flag for multiple echoes,
+                 * flag for multiple time points the flag input file
+                 * as `used' 
+                 */ 
+	 
+                cur_study_id = di_ptr[ifile]->study_id;
+                cur_acq_id = di_ptr[ifile]->acq_id;
+                cur_rec_num = di_ptr[ifile]->rec_num;
+                cur_image_type = di_ptr[ifile]->image_type;
+                cur_echo_number = di_ptr[ifile]->echo_number;
+                cur_dyn_scan_number = di_ptr[ifile]->dyn_scan_number;
+
+                strcpy(cur_patient_name, di_ptr[ifile]->patient_name);
+                strcpy(cur_patient_id, di_ptr[ifile]->patient_id);
+
+                used_file[ifile] = TRUE;
+            }
+            /* otherwise check if attributes of the new input file match those
+             * of the current output context and flag input file as `used' 
+             */
+            else if ((di_ptr[ifile]->study_id == cur_study_id) &&
+                     (di_ptr[ifile]->acq_id == cur_acq_id) &&
+                     (di_ptr[ifile]->rec_num == cur_rec_num) &&
+                     (di_ptr[ifile]->image_type == cur_image_type) &&
+                     (di_ptr[ifile]->echo_number == cur_echo_number ||
+                      !G.splitEcho) &&
+                     (di_ptr[ifile]->dyn_scan_number == cur_dyn_scan_number ||
+                      !G.splitDynScan) &&
+                     !strcmp(cur_patient_name, di_ptr[ifile]->patient_name) &&
+                     !strcmp(cur_patient_id, di_ptr[ifile]->patient_id)) {
+
+                used_file[ifile] = TRUE;
+            }
+            if (used_file[ifile]) {
+	 
+                /* if input file is flagged as `used', then add its index
+                   to the list of files for this acquisition (and increment
+                   counter) */
+
+                acq_file_list[acq_num_files] = di_ptr[ifile]->file_name;
+                acq_file_index[acq_num_files] = ifile;
+                acq_num_files++;
+            }
+        }
+
+        /* If no files were added to this acquisition, it implies that
+         * all files have been processed.
+         */
+        if (acq_num_files == 0) {
+            break;              /* All done!!! */
+        }
+       
+        /* Use the files for this acquisition
+         */
+     
+        /* Print out the file names if we are debugging.
+         */
+        if (G.Debug || G.List) {
+            printf("\nSeries %4d %20s %20s (%4d files):\n",
+                   cur_acq_id,
+                   cur_patient_name,
+                   di_ptr[acq_file_index[0]]->protocol_name,
+                   acq_num_files);
+            for (ifile = 0; ifile < acq_num_files; ifile++) {
+                printf("     %s\n", di_ptr[acq_file_index[ifile]]->file_name);
+            }
+            if (G.List) {
+                continue;
+            }
+        }
+
+        /* Do some sanity checks on the acquisition.  In particular, we 
+         * verify that the coordinate and/or slice location information
+         * looks reliable.
+         */
+        trust_location = 1;
+        trust_coord = 1;
+
+        for (ifile = 0; ifile < acq_num_files; ifile++) {
+            int jfile;
+            int ix = acq_file_index[ifile];
+
+            if (!di_ptr[ix]->coord_found) {
+                trust_coord = 0;
+            }
+
+            for (jfile = ifile + 1; jfile < acq_num_files; jfile++) {
+                int jx = acq_file_index[jfile];
+
+                if (NEARLY_EQUAL(di_ptr[ix]->slice_location,
+                                 di_ptr[jx]->slice_location)) {
+                    trust_location = 0;
+                }
+            }
+        }
+
+        user_opts = G.opts;
+
+        if (!trust_coord) {
+            printf("WARNING: Image coordinates absent or incomplete.\n");
+            if (!trust_location) {
+                printf("WARNING: Slice location is untrustworthy.\n");
+                G.opts |= OPTS_NO_LOCATION;
+            }
+        }
+
+        /* Create minc file
+         */
+        exit_status = dicom_to_minc(acq_num_files, 
+                                    acq_file_list, 
+                                    NULL,
+                                    G.clobber, 
+                                    file_prefix, 
+                                    &output_file_name);
+
+        G.opts = user_opts;
+       
+        if (exit_status != EXIT_SUCCESS) 
+            continue;
+
+        /* Print log message */
+        if (G.Debug) {
+            printf("Created minc file %s.\n", output_file_name);
+        }
+       
+        /* Invoke a command on the file (if requested) and get the 
+         * returned file name 
+         */
+        if (G.command_line[0] != '\0') {
+            sprintf(string, "%s %s", G.command_line, output_file_name);
+            printf("-Applying command '%s' to output file...  ", 
+                   G.command_line);
+            fflush(stdout);
+            if ((fp = popen(string, "r")) != NULL) {
+                fscanf(fp, "%s", output_file_name);
+                if (pclose(fp) != EXIT_SUCCESS) {
+                    fprintf(stderr, 
+                            "Error executing command\n   \"%s\"\n",
+                            string);
+                }
+                else if (G.Debug) {
+                    printf("Executed command \"%s\",\nproducing file %s.\n",
+                           string, output_file_name);
+                }
+            }
+            else {
+                fprintf(stderr, "Error executing command \"%s\"\n", string);
+            }
+            printf("Done.\n");
+        }
+       
+        /* Change the ownership */
+        if ((output_uid != INT_MIN) && (output_gid != INT_MIN)) {
+            chown(output_file_name, (uid_t) output_uid, (gid_t) output_gid);
+        }
+    }
+   
+    /* Free acquisition file list */
+    free(acq_file_list);
+    free(used_file);
+
+}
+
+static int
+is_cdexport_file(const char *fullname)
+{
+    FILE *fp;
+    char tst_str[DICM_MAGIC_SIZE+1];
+    int result = 0;
+
+    if ((fp = fopen(fullname, "rb")) == NULL) {
+        fprintf(stderr, "Error opening file %s!\n", fullname);
+    }
+    else {
+        fseek(fp, DICM_MAGIC_OFFS, SEEK_SET);
+        fread(tst_str, 1, DICM_MAGIC_SIZE, fp);
+        tst_str[DICM_MAGIC_SIZE] = '\0';
+
+        if (!strcmp(tst_str, DICM_MAGIC_STR)) {
+            result = 1;
+        }
+        fclose(fp);
+    }
+    return (result);
+}
+
+static int
+is_ima_file(const char *fullname)
+{
+    FILE *fp;
+    char mfg_str[IMA_MAGIC_SIZE];
+    int result = 0;
+
+    if ((fp = fopen(fullname, "rb")) == NULL) {
+        fprintf(stderr, "Error opening file %s!\n", fullname);
+    }
+    else {
+        fseek(fp, IMA_MAGIC_OFFS, SEEK_SET);
+        fread(mfg_str, 1, IMA_MAGIC_SIZE, fp);
+
+        /* We only deal with Siemens IMA files - not sure any other kinds 
+         * exist, frankly.
+         */
+        if (!strcmp(mfg_str, IMA_MAGIC_STR)) {
+            result = 1;
+        }
+        fclose(fp);
+    }
+    return (result);
+}
+
+static int
+check_file_type_consistency(int num_files, const char *file_list[])
+{
+    int i;
+    const char *fn_ptr;
+    int n4_offset = 0;
+
+    for (i = 0; i < num_files; i++) {
+
+        fn_ptr = file_list[i];
+
+        /* Numaris 4 DICOM CD/Export file? if so, bytes 128-131 will 
+         * contain the string `DICM' with no null termination.
+         */
+
+        if (is_cdexport_file(fn_ptr)) {
+            if (G.file_type == UNDEF) {
+                G.file_type = N4DCM;
+                n4_offset = 1; 
+                printf("File %s appears to be DICOM (CD/Export).\n",
+                       fn_ptr);
+            }
+            else if (G.file_type != N4DCM || n4_offset != 1) {
+                printf("MISMATCH: File %s appears to be DICOM (CD/Export).\n",
+                       fn_ptr);
+                return (-1);
+            }
+        } 
+        else if (is_ima_file(fn_ptr)) {
+            if (G.file_type == UNDEF) {
+                G.file_type = IMA;
+                printf("File %s appears to be Siemens IMA.\n", fn_ptr);
+            }
+            else if (G.file_type != IMA) {
+                printf("MISMATCH: File %s appears to be Siemens IMA.\n", 
+                       fn_ptr);
+                return (-1);
+            }
+        }
+        else {
+            if (G.file_type == UNDEF) {
+                G.file_type = N4DCM;
+                n4_offset = 0; 
+                printf("File %s appears to be standard DICOM.\n", fn_ptr);
+            }
+            else if (G.file_type != N4DCM || n4_offset != 0) {
+                printf("MISMATCH: File %s appears to be standard DICOM.\n",
+                       fn_ptr);
+                return (-1);
+            }
+        }
+    }
+    return (0);
+}
+
+/* compare two floating-point numbers */
+int fcmp(double x, double y, double delta) 
+{
+    return ((fabs(x - y) / ((x == 0.0) ? 1.0 : fabs(x))) < delta);
+}
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dcm2mnc.h
@@ -0,0 +1,234 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : dicomserver.h
+@DESCRIPTION: Header file that includes things needed for dicomserver.
+@METHOD     : 
+@GLOBALS    : 
+@CREATED    : January 28, 1997 (Peter Neelin)
+@MODIFIED   : 
+
+ * $Log: dcm2mnc.h,v $
+ * Revision 1.10.2.1  2005-05-12 21:16:47  bert
+ * Initial checkin
+ *
+ * Revision 1.10  2005/04/29 23:09:36  bert
+ * Add support for -stdin option to read file list from standard input
+ *
+ * Revision 1.9  2005/04/18 16:38:09  bert
+ * Add comments and defines for both DICOM and IMA file detection
+ *
+ * Revision 1.8  2005/04/05 21:50:11  bert
+ * Add comment
+ *
+ * Revision 1.7  2005/03/18 19:10:39  bert
+ * Scan coordinate and location information for validity before relying on it
+ *
+ * Revision 1.6  2005/03/13 19:34:41  bert
+ * Add pms_element_defs.h to the header
+ *
+ * Revision 1.5  2005/03/03 20:10:14  bert
+ * Consider patient_id and patient_name when sorting into series
+ *
+ * Revision 1.4  2005/03/03 18:59:15  bert
+ * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+ *
+ * Revision 1.3  2005/03/02 18:23:33  bert
+ * Added mosaic sequence and bitwise options
+ *
+ * Revision 1.2  2005/02/23 18:28:11  bert
+ * Minor updates
+ *
+ * Revision 1.1  2005/02/17 16:38:09  bert
+ * Initial checkin, revised DICOM to MINC converter
+ *
+ * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+ * Leili's dicom server for sonata
+ *
+ * Revision 1.5  2002/03/19 13:13:56  rhoge
+ * initial working mosaic support - I think time is scrambled though.
+ *
+ * Revision 1.4  2001/12/31 18:27:21  rhoge
+ * modifications for dicomreader processing of Numaris 4 dicom files - at
+ * this point code compiles without warning, but does not deal with
+ * mosaiced files.  Also will probably not work at this time for Numaris
+ * 3 .ima files.  dicomserver may also not be functional...
+ *
+ * Revision 1.3  2000/12/14 21:17:34  rhoge
+ * cleanup of log messages
+ *
+ * Revision 1.2  2000/12/14 21:15:58  rhoge
+ * added ACQ and MEAS constants as flags for type of (non-standard)
+ * dynamic scan looping
+ *
+ * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+ * imported sources to CVS repository on amoeba
+ * added num_slices_nominal to Data_Object_Info
+ * (for support of acquisition loop scans)
+ *
+ * Revision 6.1  1999/10/29 17:51:55  neelin
+ * Fixed Log keyword
+ *
+ * Revision 6.0  1997/09/12 13:24:27  neelin
+ * Release of minc version 0.6
+ *
+ * Revision 5.0  1997/08/21  13:25:26  neelin
+ * Release of minc version 0.5
+ *
+ * Revision 4.0  1997/05/07  20:06:20  neelin
+ * Release of minc version 0.4
+ *
+ * Revision 1.2  1997/03/11  13:10:48  neelin
+ * Working version of dicomserver.
+ *
+ * Revision 1.1  1997/03/04  20:56:47  neelin
+ * Initial revision
+ *
+@COPYRIGHT  :
+              Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <memory.h>
+#include <limits.h>
+#include <float.h>
+#include <time_stamp.h>
+#include <acr_nema.h>
+
+#include "acr_element_defs.h"
+#include "spi_element_defs.h"
+#include "ext_element_defs.h"
+#include "pms_element_defs.h"   /* Philips Medical Systems */
+#include "gems_element_defs.h"  /* GE Medical Systems */
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+/* Constants for "standard" DICOM files (herein referred to as
+ * CD/Export files).  For more details of this, see section 7.1 "DICOM
+ * FILE META INFORMATION" of the DICOM specification section 3.10.
+ */
+#define DICM_MAGIC_SIZE 4
+#define DICM_MAGIC_OFFS 0x0080
+#define DICM_MAGIC_STR "DICM"
+
+/* Constants for Siemens IMA file format detection.  These are somewhat
+ * arbitrary - I test for IMA format by looking for the manufacturer string
+ * SIEMENS at offset 0x0060
+ */
+#define IMA_MAGIC_SIZE (8+1)
+#define IMA_MAGIC_OFFS 0x0060
+#define IMA_MAGIC_STR "SIEMENS"
+
+/* Test to see if two floating-point numbers are very close in value.
+ */
+
+extern int fcmp(double x, double y, double delta);
+
+#define NEARLY_EQUAL(x, y) (fcmp(x, y, 1e-6))
+
+typedef char string_t[511+1];
+#define STRING_T_LEN (sizeof(string_t) - 1)
+
+/* Define logging constants */
+#define NO_LOGGING 0
+#define LO_LOGGING 1
+#define HI_LOGGING 2
+
+/* added by rhoge for ACQ and MEAS loop handling */
+typedef enum { NONE = 0 , ACQ , MEAS } Loop_Type;
+
+/* supported file types */
+typedef enum { UNDEF, IMA, N3DCM, N4DCM } File_Type;
+
+/* Type for carrying around object information 
+ */
+typedef struct {
+    int file_index;             /* input file index */
+    char *file_name;            /* input file name */
+    double study_id;            /* yyyymmdd.hhmmss */
+    int study_date;
+    int study_time;
+    int scanner_serialno;
+    int acq_id;
+    int rec_num;
+    int image_type;
+    int num_echoes;
+    int echo_number;
+    int num_dyn_scans;
+    int dyn_scan_number;
+    int global_image_number;
+    int num_slices_nominal;
+    int slice_number;
+    int acq_rows;
+    int acq_cols;
+    int rec_rows;
+    int rec_cols;
+    int num_mosaic_rows;
+    int num_mosaic_cols;
+    int num_slices_in_file;
+    string_t sequence_name;
+    string_t protocol_name;
+    string_t patient_name;
+    string_t patient_id;
+    double slice_location;
+    int coord_found;
+} Data_Object_Info;
+
+#include "dicom_to_minc.h"
+#include "dicom_read.h"
+#include "minc_file.h"
+#include "progress.h"
+#include "siemens_to_dicom.h"
+#include "string_to_filename.h"
+
+typedef enum {
+    MOSAIC_SEQ_UNKNOWN,
+    MOSAIC_SEQ_INTERLEAVED,
+    MOSAIC_SEQ_ASCENDING,
+    MOSAIC_SEQ_DESCENDING
+} mosaic_seq_t;
+
+/* Globals */
+struct globals {
+    char *minc_history;         /* Global for minc history */
+    char *pname;                /* program name */
+    File_Type file_type;        /* type of input files */
+    short Debug;                /* Debug on/off */
+    short Anon;                 /* "Anonymize" the output */
+    short List;
+    short useMinMax;            /* TRUE if need to use pixel min/max values */
+    short splitEcho;            /* TRUE if echos in separate files */
+    short splitDynScan;  /* TRUE if dynamic scans in separate files */
+    short clobber;
+    string_t Name;
+    string_t command_line;
+    unsigned long opts;
+    mosaic_seq_t mosaic_seq;
+    short use_stdin;
+};
+
+/* Values for options flags */
+#define OPTS_NO_MOSAIC   0x00000001 /* Don't parse mosaic information. */
+#define OPTS_KEEP_COORD  0x00000002 /* Don't flip DICOM coordinates */
+#define OPTS_NO_LOCATION 0x00000004 /* Never rely on slice location */
+
+extern struct globals G;
+
+#define CHKMEM(x) \
+    if ((x) == NULL) \
+        (fprintf(stderr, "Out of memory at %s:%d\n", __FILE__, __LINE__), \
+         exit(-1))
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dicom_read.c
@@ -0,0 +1,1811 @@
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : dicom_read.c
+   @DESCRIPTION: Code to read siemens dicom files and get info from them.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : January 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   * $Log: dicom_read.c,v $
+   * Revision 1.16.2.1  2005-05-12 21:16:47  bert
+   * Initial checkin
+   *
+   * Revision 1.16  2005/05/09 15:30:32  bert
+   * Don't allow a rescale slope value of zero
+   *
+   * Revision 1.15  2005/04/28 17:17:57  bert
+   * Set and update new width information fields in a manner analogous to the coordinate fields in the General_Info and File_Info structures
+   *
+   * Revision 1.14  2005/04/20 23:14:04  bert
+   * Remove most SPI_ references
+   *
+   * Revision 1.13  2005/04/20 17:47:38  bert
+   * Fairly major restructuring, added init_general_info() function
+   *
+   * Revision 1.12  2005/04/18 21:43:04  bert
+   * Properly set default minimum and maximum values based on the pixel representation
+   *
+   * Revision 1.11  2005/04/18 21:01:51  bert
+   * Set signed/unsigned flag correctly
+   *
+   * Revision 1.10  2005/04/18 20:43:25  bert
+   * Added some additional debugging information for image position and orientation
+   *
+   * Revision 1.9  2005/04/18 16:22:13  bert
+   * Don't allow non-slice MRI dimensions to grow arbitrarily
+   *
+   * Revision 1.8  2005/04/05 21:49:52  bert
+   * Use rescale slope and intercept to determine the proper slice minimum and maximum
+   *
+   * Revision 1.7  2005/03/29 20:21:44  bert
+   * Fix use of slice spacing; fully check for position information if possible, otherwise create a reasonable position from the slice index
+   *
+   * Revision 1.6  2005/03/14 23:29:35  bert
+   * Support basic dynamic PET fields.  Also allocate indices and coordinates arrays for all dimensions, even those we won't use.
+   *
+   * Revision 1.5  2005/03/13 19:37:42  bert
+   * Try to use slice location for coordinate when all else fails, also added one debugging message and a check for PET modality
+   *
+   * Revision 1.4  2005/03/03 20:11:00  bert
+   * Consider patient_id and patient_name when sorting into series.  Fix handling of missing direction cosines
+   *
+   * Revision 1.3  2005/03/03 18:59:15  bert
+   * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+   *
+   * Revision 1.2  2005/03/02 20:18:09  bert
+   * Latest fixes and tweaks
+   *
+   * Revision 1.1  2005/02/17 16:38:10  bert
+   * Initial checkin, revised DICOM to MINC converter
+   *
+   * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+   * Leili's dicom server for sonata
+   *
+   * Revision 1.12  2002/05/01 21:29:34  rhoge
+   * removed MrProt from minc header - encountered files with large strings,
+   * causing seg faults
+   *
+   * Revision 1.11  2002/04/26 03:27:03  rhoge
+   * fixed MrProt problem - replaced fixed lenght char array with malloc
+   *
+   * Revision 1.10  2002/04/08 17:26:34  rhoge
+   * added additional sequence info to minc header
+   *
+   * Revision 1.9  2002/03/27 18:57:50  rhoge
+   * added diffusion b value
+   *
+   * Revision 1.8  2002/03/19 13:13:56  rhoge
+   * initial working mosaic support - I think time is scrambled though.
+   *
+   * Revision 1.7  2001/12/31 18:27:21  rhoge
+   * modifications for dicomreader processing of Numaris 4 dicom files - at
+   * this point code compiles without warning, but does not deal with
+   * mosaiced files.  Also will probably not work at this time for Numaris
+   * 3 .ima files.  dicomserver may also not be functional...
+   *
+   * Revision 1.6  2000/12/14 21:33:13  rhoge
+   * code modifications to restore measurement loop support that was broken
+   * by changes to support acqusition loop scanning
+   *
+   * Revision 1.5  2000/12/13 13:25:36  rhoge
+   * removed dummy printf from convert_time_to_seconds - turns out that
+   * buggy behaviour was an optimization problem
+   *
+   * Revision 1.4  2000/12/12 19:27:52  rhoge
+   * changed atof(acr_find_string) back to acr_find_double after realizing
+   * that these functions assume string representation
+   *
+   * Revision 1.3  2000/12/12 14:43:22  rhoge
+   * fixed syntax error (dangling comment symbol) from removal of debug
+   * printfs - compiles now
+   *
+   * Revision 1.2  2000/12/11 20:01:44  rhoge
+   * fixed code for frame time computation - ACR vals are strings.  Also
+   * inserted dummy fprintf statement in convert_time_to_seconds as this
+   * seems to salvage Linux problems
+   *
+   * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+   * imported sources to CVS repository on amoeba
+   * -now always use ACR_Series for run number (seemed to be
+   *  problems with test introduced in 6.1)
+   * -added code to detect use of acquisition loop and also to handle
+   *  `corrected' siemens acq loop scans
+   * -changed code to use registration time instead of scan time for 
+   *  session id
+   * -got rid of extraneous acquisition id digit
+   * -added technical information about data acquisition
+   *
+   * Revision 6.2  1999/10/29 17:51:58  neelin
+   * Fixed Log keyword
+   *
+   * Revision 6.1  1999/08/05 20:00:34  neelin
+   * Get acquisition id from series or study element, depending on the
+   * version of the Siemens software.
+   *
+   * Revision 6.0  1997/09/12  13:24:27  neelin
+   * Release of minc version 0.6
+   *
+   * Revision 5.1  1997/09/10  19:36:13  neelin
+   * Small fix to set default direction cosines when they are absent from the
+   * dicom data.
+   *
+   * Revision 5.0  1997/08/21  13:25:26  neelin
+   * Release of minc version 0.5
+   *
+   * Revision 4.1  1997/06/13  12:51:21  neelin
+   * Changed definition of time index and acquisition id to match change
+   * in Siemens dicom software.
+   *
+   * Revision 4.0  1997/05/07  20:06:20  neelin
+   * Release of minc version 0.4
+   *
+   * Revision 1.2  1997/03/11  13:10:48  neelin
+   * Working version of dicomserver.
+   *
+   * Revision 1.1  1997/03/04  20:56:47  neelin
+   * Initial revision
+   *
+   @COPYRIGHT  :
+   Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+   Montreal Neurological Institute, McGill University.
+   Permission to use, copy, modify, and distribute this
+   software and its documentation for any purpose and without
+   fee is hereby granted, provided that the above copyright
+   notice appear in all copies.  The author and McGill University
+   make no representations about the suitability of this
+   software for any purpose.  It is provided "as is" without
+   express or implied warranty.
+   ---------------------------------------------------------------------------- */
+
+#include "dcm2mnc.h"
+
+#include <math.h>
+
+static double convert_time_to_seconds(double dicom_time);
+static void get_intensity_info(Acr_Group group_list, File_Info *file_info);
+static void get_coordinate_info(Acr_Group group_list, File_Info *file_info,
+                                Orientation *orientation,
+                                World_Index volume_to_world[VOL_NDIMS],
+                                const int sizes[VOL_NDIMS],
+                                double dircos[VOL_NDIMS][WORLD_NDIMS],
+                                double steps[VOL_NDIMS],
+                                double starts[VOL_NDIMS],
+                                double coordinate[WORLD_NDIMS]);
+static void get_general_header_info(Acr_Group group_list,
+                                    General_Info *general_info);
+static void convert_numa3_coordinate(double coordinate[WORLD_NDIMS]);
+static void convert_dicom_coordinate(double coordinate[WORLD_NDIMS]);
+static void get_identification_info(Acr_Group group_list, 
+                                    double *study_id, int *acq_id, 
+                                    int *rec_num, int *image_type);
+
+static int irnd(double x)
+{
+    if (x > 0.0) {
+        x += 0.5;
+    }
+    else {
+        x -= 0.5;
+    }
+    return (int) floor(x);
+}
+
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : init_general_info
+   @INPUT      : fi_ptr - file-specific info
+                 group_list - input data
+                 volume_to_world - correspondence of volume to world dimensions
+                 spatial_sizes - 3D voxel counts
+                 dircos - direction cosines
+                 steps - width of each voxel for each spatial dimension
+                 starts - starting position for each spatial dimension
+                 coordinate - 
+   @OUTPUT     : gi_ptr - general information about files in this series
+
+                 
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Initializes a "General_Info" structure based upon several
+                 bits of information, including a previously initialized
+                 File_Info structure (fi_ptr) and the DICOM group_list.
+                 Broken out from the get_file_info() function to help
+                 simplify that function.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : April 19, 2005 (Bert Vincent)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static void
+init_general_info(General_Info *gi_ptr, /* OUT */
+                  const File_Info *fi_ptr, /* IN */
+                  const Acr_Group group_list, /* IN */
+                  const World_Index volume_to_world[VOL_NDIMS], /* IN */
+                  const int spatial_sizes[VOL_NDIMS], /* IN */
+                  double dircos[VOL_NDIMS][WORLD_NDIMS], /* IN */
+                  const double steps[VOL_NDIMS], /* IN */
+                  const double starts[VOL_NDIMS], /* IN */
+                  double study_id, /* IN */
+                  int acq_id,   /* IN */
+                  int rec_num)  /* IN */
+{
+    Acr_Element_Id mri_total_list[MRI_NDIMS];
+    int ivalue;                 /* For pixel representation value. */
+    World_Index iworld; /* World coordinate index (XCOORD, YCOORD...) */
+    World_Index jworld;         /* World coordinate index */
+    Volume_Index ivolume; /* Voxel coordinate index (VROW, VCOLUMN...) */
+    Mri_Index imri;
+    int index;
+
+    // Initialize array for MRI dimension lengths
+    //
+    mri_total_list[SLICE] = ACR_Images_in_acquisition;
+    mri_total_list[ECHO] = ACR_Echo_train_length;
+    mri_total_list[TIME] = ACR_Acquisitions_in_series;
+    mri_total_list[PHASE] = NULL;
+    mri_total_list[CHEM_SHIFT] = NULL;
+
+    // Get row and columns sizes
+    gi_ptr->nrows = spatial_sizes[VROW];
+    gi_ptr->ncolumns = spatial_sizes[VCOLUMN];
+
+    // Save the study, acquisition, reconstruction and image type 
+    //   identifiers
+    gi_ptr->study_id = study_id;
+    gi_ptr->acq_id = acq_id;
+    gi_ptr->rec_num = rec_num;
+
+    strcpy(gi_ptr->image_type_string, acr_find_string(group_list,
+                                                      ACR_Image_type,
+                                                      ""));
+
+    /* Get dimension information 
+     */
+    for (imri = 0; imri < MRI_NDIMS; imri++) {
+
+        /* Get sizes along "MRI" dimensions... 
+         */
+        gi_ptr->cur_size[imri] = 1;
+
+        if (mri_total_list[imri] != NULL) {
+            int def_val = 1;
+
+            /* Special case for slice index - need to look at the 
+             * new standard element 0x0020:0x1002 "Images in 
+             * Acquisition".  We use this as a default, but override
+             * it with the Siemens-specific value if present.
+             */
+            if (imri == SLICE) {
+                /* Look for the standard slice count fields first. We
+                 * start with the (0054, 0081) first, and if that fails
+                 * we retry with (0020, 1002).
+                 */
+                def_val = acr_find_int(group_list, ACR_Number_of_slices, 0);
+                if (def_val == 0) {
+                    def_val = acr_find_int(group_list,
+                                           ACR_Images_in_acquisition,
+                                           1);
+                }
+            }
+
+            if (imri == TIME) {
+                /* Look for the official time slice count field first.
+                 */
+                def_val = acr_find_int(group_list,
+                                       ACR_Number_of_time_slices,
+                                       0);
+            }
+            gi_ptr->max_size[imri] = acr_find_int(group_list,
+                                                  mri_total_list[imri],
+                                                  def_val);
+        }
+        else {
+            gi_ptr->max_size[imri] = 1;
+        }
+
+        if (gi_ptr->max_size[imri] < 1) {
+            gi_ptr->max_size[imri] = 1;
+        }
+
+        /* Check for 3D partitions for slice dimensions */
+        if (imri == SLICE) {
+            /* Get number of 3D partitions for working out number of
+             * slices
+             */
+            int number_of_3D_partitions =  
+                acr_find_int(group_list, SPI_Number_of_3D_raw_partitions_nominal, 1);
+            if (number_of_3D_partitions < 1) {
+                number_of_3D_partitions = 1;
+            }
+
+            gi_ptr->max_size[imri] *= number_of_3D_partitions;
+        }
+
+        gi_ptr->default_index[imri] = fi_ptr->index[imri];
+        gi_ptr->image_index[imri] = -1;
+	
+        /* Allocate space for index and coordinate arrays.
+         * Set the first values.
+         */
+
+        gi_ptr->indices[imri] = malloc(gi_ptr->max_size[imri] * sizeof(int));
+
+        gi_ptr->coordinates[imri] = 
+            malloc(gi_ptr->max_size[imri] * sizeof(double));
+
+        gi_ptr->widths[imri] = 
+            malloc(gi_ptr->max_size[imri] * sizeof(double));
+
+        for (index = 0; index < gi_ptr->max_size[imri]; index++) {
+            gi_ptr->indices[imri][index] = -1;
+            gi_ptr->coordinates[imri][index] = 0;
+            gi_ptr->widths[imri][index] = 0; /* default */
+        }
+        gi_ptr->search_start[imri] = 0;
+        gi_ptr->indices[imri][0] = fi_ptr->index[imri];
+        gi_ptr->coordinates[imri][0] = fi_ptr->coordinate[imri];
+        gi_ptr->widths[imri][0] = fi_ptr->width[imri];
+
+        if (G.Debug) {
+            printf("%2d. %s axis length %d\n",
+                   imri, Mri_Names[imri], gi_ptr->max_size[imri]);
+        }
+    } /* Loop over dimensions */
+
+    /* Get spatial coordinate information */
+    gi_ptr->slice_world = volume_to_world[VSLICE];
+    gi_ptr->row_world = volume_to_world[VROW];
+    gi_ptr->column_world = volume_to_world[VCOLUMN];
+    for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+        iworld = volume_to_world[ivolume];
+        gi_ptr->step[iworld] = steps[ivolume];
+        gi_ptr->start[iworld] = starts[ivolume];
+        for (jworld = 0; jworld < WORLD_NDIMS; jworld++) {
+            gi_ptr->dircos[iworld][jworld] = dircos[ivolume][jworld];
+        }
+
+        if (G.Debug) {
+            printf("%2d. %s axis length %d step %.3f, start %.3f, cosines %.3f,%.3f,%.3f\n",
+                   ivolume,
+                   World_Names[iworld],
+                   spatial_sizes[ivolume],
+                   gi_ptr->step[iworld],
+                   gi_ptr->start[iworld],
+                   gi_ptr->dircos[iworld][XCOORD],
+                   gi_ptr->dircos[iworld][YCOORD],
+                   gi_ptr->dircos[iworld][ZCOORD]
+                   );
+        }
+    }
+
+    /* Set data type and range */
+    if (fi_ptr->bits_alloc <= 8) {
+        gi_ptr->datatype = NC_BYTE;
+    }
+    else {
+        gi_ptr->datatype = NC_SHORT;
+    }
+
+    /* bert- modify code to correctly read the pixel
+     * representation if available and use that to set the
+     * signed/unsigned flag.
+     */
+    ivalue = acr_find_short(group_list, ACR_Pixel_representation, -1);
+    if (ivalue == ACR_PIXEL_REP_UNSIGNED) {
+        gi_ptr->is_signed = 0;
+    }
+    else if (ivalue == ACR_PIXEL_REP_SIGNED) {
+        gi_ptr->is_signed = 1;
+    }
+    else {
+        if (ivalue != -1) {
+            printf("WARNING: Unknown pixel representation value %d\n",
+                   ivalue);
+        }
+        gi_ptr->is_signed = ((gi_ptr->datatype == NC_SHORT) &&
+                             (fi_ptr->bits_stored < 16));
+    }
+
+    gi_ptr->pixel_min = fi_ptr->pixel_min;
+    gi_ptr->pixel_max = fi_ptr->pixel_max;
+        
+    /* Save display window info */
+    gi_ptr->window_min = fi_ptr->window_min;
+    gi_ptr->window_max = fi_ptr->window_max;
+
+    /* Get the rest of the header information */
+    get_general_header_info(group_list, gi_ptr);
+
+    /* Copy the group list */
+    gi_ptr->group_list = acr_copy_group_list(group_list);
+
+        // note that number of slices will be wrong here for mosaics
+        // we add some other mosaic-relevant fields...
+
+    gi_ptr->num_mosaic_rows =
+        acr_find_int(group_list, EXT_Mosaic_rows, 1);
+    gi_ptr->num_mosaic_cols =
+        acr_find_int(group_list, EXT_Mosaic_columns, 1);
+    gi_ptr->num_slices_in_file = 
+        acr_find_int(group_list, EXT_Slices_in_file, 1);
+    gi_ptr->sub_image_rows =
+        acr_find_short(group_list, EXT_Sub_image_rows,
+                       acr_find_short(group_list, ACR_Rows, 0));
+    gi_ptr->sub_image_columns =
+        acr_find_short(group_list, EXT_Sub_image_columns,
+                       acr_find_short(group_list, ACR_Rows, 0));
+
+    /* Set initialized flag */
+    gi_ptr->initialized = TRUE;
+
+    if (G.Debug) {
+        printf("Pixel minimum %.10f maximum %.10f\n",
+               gi_ptr->pixel_min, gi_ptr->pixel_max);
+        printf("Window minimum %.10f maximum %.10f\n",
+               gi_ptr->window_min, gi_ptr->window_max);
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_file_info
+   @INPUT      : group_list - input data
+   @OUTPUT     : file_inf_p - file-specific info
+   general_info - general information about files
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to extract information from a group list
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : November 25, 1993 (Peter Neelin)
+   @MODIFIED   : Modified Feb. 2000 by Rick Hoge to handle Acquisition loop mode
+   : if assume_acq_loop is FALSE the other added variables don't 
+   : matter 
+   ---------------------------------------------------------------------------- */
+void 
+get_file_info(Acr_Group group_list, File_Info *fi_ptr, General_Info *gi_ptr)
+{
+    Mri_Index imri;             /* MRI index (SLICE, ECHO, TIME, PHASE...) */
+    int nrows;                  /* Row count in this file */
+    int ncolumns;               /* Column count in this file */
+    int spatial_sizes[VOL_NDIMS]; /* Voxel coordinate extents */
+    double study_id;            /* Study identifier */
+    int acq_id;                 /* Acquisition identifier */
+    int rec_num;                /* ? Seems to be a dummy */
+    int cur_index;              /* Index of slice(s) in current file */
+    int index;                  /* General index value */
+    Orientation orientation;    /* TRANSVERSE, SAGITTAL, or CORONAL */
+    World_Index volume_to_world[VOL_NDIMS]; /* Maps voxel to world indices */
+    double coordinate[WORLD_NDIMS]; /* Slice coordinates */
+    double dircos[VOL_NDIMS][WORLD_NDIMS]; /* Direction cosines */
+    double steps[VOL_NDIMS];    /* Step (spacing) coordinates */
+    double starts[VOL_NDIMS];   /* Start (origin) coordinates */
+    Acr_Element_Id mri_index_list[MRI_NDIMS];
+
+    // Initialize array of elements for MRI positions (indices)
+    //
+    mri_index_list[SLICE] = SPI_Current_slice_number;
+    mri_index_list[ECHO] = ACR_Echo_number;
+    mri_index_list[TIME] = ACR_Acquisition;
+    mri_index_list[PHASE] = NULL;
+    mri_index_list[CHEM_SHIFT] = NULL;
+
+    /* Get image dimensions
+     */
+    nrows = acr_find_short(group_list, ACR_Rows, 0);
+    ncolumns = acr_find_short(group_list, ACR_Columns, 0);
+
+    spatial_sizes[VROW] = nrows;
+    spatial_sizes[VCOLUMN] = ncolumns;
+
+    spatial_sizes[VSLICE] = acr_find_int(group_list, ACR_Images_in_acquisition,
+                                         1);
+
+    /* Get intensity information
+     */
+    get_intensity_info(group_list, fi_ptr);
+
+    /* Check for necessary values not found
+     */
+    if ((nrows <= 0) || (ncolumns <= 0) ||
+        (fi_ptr->bits_stored <= 0) ||
+        (fi_ptr->bits_alloc <= 0)) {
+        if (G.Debug) {
+            printf("ERROR: Needed values missing, marking invalid\n");
+        }
+        fi_ptr->valid = FALSE;
+        return;
+    }
+
+    /* Get study, acq, rec, image type id's
+     */
+    get_identification_info(group_list, &study_id, &acq_id, &rec_num, NULL);
+
+    /* Get indices for image in current file
+     */
+    for (imri = 0; imri < MRI_NDIMS; imri++) {
+        if (mri_index_list[imri] != NULL) {
+            fi_ptr->index[imri] = acr_find_int(group_list,
+                                               mri_index_list[imri], 1);
+        }
+        else {
+            fi_ptr->index[imri] = 1;
+        }
+    }
+
+    /* Get coordinate information
+     */
+    get_coordinate_info(group_list, fi_ptr, &orientation, volume_to_world,
+                        spatial_sizes, dircos, steps, starts, coordinate);
+
+    /*
+     * Use the coordinate information rather than the slice or time
+     * position derived above.  This seems to be much more reliable.
+     */
+
+    fi_ptr->index[SLICE] = irnd(fi_ptr->coordinate[SLICE] * 100.0);
+    
+    /* For non-IMA files, use the time coordinate to order the time.
+     * index.  IMA files do not seem to have a reliable slice time
+     * indicator.
+     */
+    if (G.file_type != IMA) {
+        fi_ptr->index[TIME] = irnd(fi_ptr->coordinate[TIME] * 100.0);
+    }
+
+    /* Set up general info on first pass
+     */
+    if (!gi_ptr->initialized) {
+        init_general_info(gi_ptr, 
+                          fi_ptr, 
+                          group_list, 
+                          volume_to_world,
+                          spatial_sizes,
+                          dircos,
+                          steps,
+                          starts,
+                          study_id, 
+                          acq_id, 
+                          rec_num);
+    }
+
+    /* Set up file info */
+
+    /* Update general info and validate file on later passes 
+     */
+    else {
+
+        /* Check for consistent pixel minimum and maximum. */
+        if ((gi_ptr->pixel_max != fi_ptr->pixel_max) ||
+            (gi_ptr->pixel_min != fi_ptr->pixel_min)) {
+            printf("WARNING: Inconsistent pixel minimum and maximum\n");
+        }
+     
+        /* Check for consistent data type */
+        if (((gi_ptr->datatype == NC_BYTE) && (fi_ptr->bits_alloc > 8)) || 
+            ((gi_ptr->datatype == NC_SHORT) && (fi_ptr->bits_alloc <= 8))) {
+            printf("Inconsistent datatype, marking invalid\n");
+            fi_ptr->valid = FALSE;
+            return;
+        }
+
+        /* Check row and columns sizes */
+        if ((nrows != gi_ptr->nrows) && (ncolumns != gi_ptr->ncolumns))  {
+            printf("Mismatched rows/columns, marking invalid\n");
+            fi_ptr->valid = FALSE;
+            return;
+        }
+     
+        /* Check study and acquisition id's */
+        if ((gi_ptr->study_id != study_id) || (gi_ptr->acq_id != acq_id)) {
+            printf("Mismatched acquisition/study, marking invalid\n");
+            fi_ptr->valid = FALSE;
+            return;
+        }
+
+        /* Look to see if indices have changed */
+        for (imri = 0; imri < MRI_NDIMS; imri++) {
+            /* If a dimension is known to have a maximum size of one
+             * or less, we do NOT allow it to grow in any way.  An
+             * exception is made for the slice dimension, however,
+             * since it appears that it is common for it to be
+             * unspecified and can be guessed only by the number of
+             * distinct locations discovered.
+             */
+            if (imri != SLICE && gi_ptr->max_size[imri] <= 1) {
+                continue;
+            }
+       
+            /* Get current index */
+            cur_index = fi_ptr->index[imri];
+       
+            /* Check whether this index is in the list.
+             */
+            if (gi_ptr->cur_size[imri] == 1) {
+                index = ((cur_index == gi_ptr->default_index[imri]) ? 0 : -1);
+            }
+            else {
+                /* Search list of indices for 'cur_index'.  Search is 
+                   started at search_start[] and has maximum length of
+                   size[imri].
+                */
+                index = search_list(cur_index, 
+                                    gi_ptr->indices[imri],
+                                    gi_ptr->cur_size[imri],
+                                    gi_ptr->search_start[imri]);
+            }
+
+            /* If it is not, then add it */
+            if (index < 0) {
+                if (G.Debug >= HI_LOGGING) {
+                    printf("Need to add index %d to %s list, %d/%d\n",
+                           cur_index, Mri_Names[imri],
+                           gi_ptr->cur_size[imri],
+                           gi_ptr->max_size[imri]);
+                }
+
+                /* Check whether we can add a new index */
+                if (gi_ptr->cur_size[imri] >= gi_ptr->max_size[imri]) {
+                    gi_ptr->max_size[imri]++;
+                    gi_ptr->indices[imri] = 
+                        realloc(gi_ptr->indices[imri],
+                                gi_ptr->max_size[imri] * sizeof(int));
+
+                    gi_ptr->coordinates[imri] = 
+                        realloc(gi_ptr->coordinates[imri],
+                                gi_ptr->max_size[imri] * sizeof(double));
+
+                    gi_ptr->widths[imri] = 
+                        realloc(gi_ptr->widths[imri],
+                                gi_ptr->max_size[imri] * sizeof(double));
+                }
+
+	 
+                /* Add the index and coordinate to the lists */
+                index = gi_ptr->cur_size[imri];
+                gi_ptr->search_start[imri] = index;
+                gi_ptr->indices[imri][index] = cur_index;
+                gi_ptr->coordinates[imri][index] = fi_ptr->coordinate[imri];
+                gi_ptr->widths[imri][index] = fi_ptr->width[imri];
+                gi_ptr->cur_size[imri]++;
+	 
+            }
+        }              /* Loop over Mri_Index */
+
+        // Update display window info
+        if (gi_ptr->window_min > fi_ptr->window_min) 
+            gi_ptr->window_min = fi_ptr->window_min;
+        if (gi_ptr->window_max < fi_ptr->window_max)
+            gi_ptr->window_max = fi_ptr->window_max;
+     
+    }  // Update general info for this file
+
+    // If we get to here, then we have a valid file
+    fi_ptr->valid = TRUE;
+    return;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_identification_info
+   @INPUT      : group_list - input data
+   @OUTPUT     : study_id
+   acq_id
+   rec_num
+   image_type
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to get image identification information.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static void 
+get_identification_info(Acr_Group group_list, 
+                        double *study_id, int *acq_id, 
+                        int *rec_num, int *image_type)
+{
+    int number_of_frames;
+    int number_of_averages;
+
+    if (study_id != NULL) {
+        // generate a study ID number from date & time:  yyyymmdd.hhmmss
+        // (should be unique enough for our application)
+        *study_id = (((float)acr_find_int(group_list, ACR_Study_date, 0)) +
+                     ((float)acr_find_int(group_list, ACR_Study_time, 0))/1e6);
+    }
+    if (acq_id != NULL) {
+
+        *acq_id = acr_find_int(group_list, ACR_Series, 0);
+
+        number_of_frames = 
+            acr_find_int(group_list, ACR_Acquisitions_in_series, 1);
+
+        number_of_averages = 
+            acr_find_int(group_list, ACR_Nr_of_averages, 1);
+
+        /* Determine if measurement loop was used (rhoge) -
+
+        if so, we replace the different series numbers with
+        ACR_Study_time, which is the same for all frames in a run.
+        This will aid in grouping the files later on.  
+
+        Criteria used for identification of meast loop:
+
+        1) more than one dynamic scan
+
+        2) number of dynamic scans NOT equal to nominal number of signal
+        averages (if they're equal, we assume acquisition loop scan)
+
+        WARNING:  it is possible that someone might use the
+        measurement loop do serial scans which each have multiple signal
+        averages.  If NSA = the number of measts. in this case, then
+        the scan will not be recognized as a Meast loop scan and the
+        different frames will be placed in different series.  To fix
+        this, we'd really need to look at the series numbers of
+        future and past files.  It's also unlikely to happen but I'm
+        sure it will... 
+
+        This also means we should NOT correct the number of signal
+        averages on the sending side */
+
+
+        /*      if ((number_of_frames > 1) || (*acq_id == 0)) { (orig test) */
+
+        if ( (G.file_type == N3DCM) &&
+             (number_of_frames > 1) &&
+             (number_of_frames != number_of_averages)) { 
+
+            *acq_id = acr_find_int(group_list, ACR_Study_time, 0);
+
+        }
+    }
+    if (rec_num != NULL)
+        *rec_num = 0;
+    if (image_type != NULL)
+        *image_type = 0;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_intensity_info
+   @INPUT      : group_list - input data
+   @OUTPUT     : fi_ptr - file-specific info
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to get intensity information from a group list
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static void
+get_intensity_info(Acr_Group group_list, File_Info *fi_ptr)
+{
+    double window_centre, window_width;
+    double rescale_intercept, rescale_slope;
+    int ivalue;                 /* 0000 for unsigned, 0001 for signed */
+    int imin, imax;             /* Default minimum and maximum values */
+
+    /* Get pixel storage information */
+    fi_ptr->bits_alloc = acr_find_short(group_list, ACR_Bits_allocated, 0);
+    fi_ptr->bits_stored = acr_find_short(group_list, ACR_Bits_stored, 0);
+
+    /* bert- properly set the minimum and maximum pixel values depending
+     * on whether or not this file specifies signed pixel values.
+     */
+    ivalue = acr_find_short(group_list, ACR_Pixel_representation, -1);
+
+    if (ivalue == ACR_PIXEL_REP_SIGNED) {
+        imin = -(1 << (fi_ptr->bits_stored - 1));
+        imax = (1 << (fi_ptr->bits_stored - 1)) - 1;
+    }
+    else {
+        imin = 0;
+        imax = (1 << fi_ptr->bits_stored) - 1;
+    }
+
+    if (G.useMinMax) {
+        // Get pixel value information
+        // I think this might wrongly assume that the ACR values min/max
+        // apply to the whole volume - it actually appears that they apply
+        // to the current slice.
+
+        fi_ptr->pixel_min = acr_find_short(group_list, 
+                                           ACR_Smallest_pixel_value, imin);
+
+        fi_ptr->pixel_max = acr_find_short(group_list,
+                                           ACR_Largest_pixel_value, imax);
+
+    }
+    else {
+        /* for now, use bits_stored to determine dynamic range
+         * DICOM info on largest pixel applies to first slice, 
+         * not whole volume - this caused problems (roundoff?)
+         * in Siemens Numaris 4 scans
+         */
+        fi_ptr->pixel_min = imin;
+        fi_ptr->pixel_max = imax;
+    }
+
+    /* Get the rescale intercept and slope.  If they are not present,
+     * we use the default values of 0.0 for the intercept and 1.0 for
+     * the slope.
+     */
+    rescale_intercept = acr_find_double(group_list, ACR_Rescale_intercept, 0);
+    rescale_slope = acr_find_double(group_list, ACR_Rescale_slope, 1);
+
+    /* If the rescale slope is set to zero, force the default value of 
+     * one and issue a warning.
+     */
+    if (rescale_slope == 0.0) {
+        printf("WARNING: File contains a rescale slope value of zero.\n");
+        rescale_slope = 1.0;
+    }
+
+    fi_ptr->slice_min = fi_ptr->pixel_min * rescale_slope + rescale_intercept;
+    fi_ptr->slice_max = fi_ptr->pixel_max * rescale_slope + rescale_intercept;
+
+    /* Get window min and max */
+    window_centre = (fi_ptr->slice_max + fi_ptr->slice_min) / 2.0;
+    window_width  = fi_ptr->slice_max - fi_ptr->slice_min;
+    window_centre = 
+        acr_find_double(group_list, ACR_Window_centre, window_centre);
+    window_width = 
+        acr_find_double(group_list, ACR_Window_width, window_width);
+    fi_ptr->window_min = window_centre - window_width / 2.0;
+    fi_ptr->window_max = window_centre + window_width / 2.0; 
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_coordinate_info
+   @INPUT      : group_list - input data
+   sizes - size of each spatial dimension
+   @OUTPUT     : fi_ptr - file-specific info
+   volume_to_world - volume index to world coordinate index mapping
+   dircos - direction cosines for spatial dimensions
+   steps - step sizes for spatial dimensions
+   starts - start positions for spatial dimensions (for a slice)
+   coordinate - coordinate of centre of slice
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to get coordinate information for a slice from 
+   a group list
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+#define SPECIAL_CASE_IMA 1
+
+#define DARRAY_SIZE 2
+
+static void
+get_coordinate_info(Acr_Group group_list, 
+                    File_Info *fi_ptr,
+                    Orientation *orientation,
+                    World_Index volume_to_world[VOL_NDIMS],
+                    const int sizes[VOL_NDIMS],
+                    double dircos[VOL_NDIMS][WORLD_NDIMS],
+                    double steps[VOL_NDIMS],
+                    double starts[VOL_NDIMS],
+                    double coordinate[WORLD_NDIMS])
+{
+    Volume_Index ivolume;
+    World_Index iworld;
+    Acr_Element element;
+    int found_dircos[VOL_NDIMS];
+    int found_coordinate;
+    double frame_time;
+    double start_time;
+    double magnitude;
+    double largest;
+    double darray[DARRAY_SIZE];
+    double dbl_tmp1, dbl_tmp2;
+    int result;
+
+    double RowColVec[6]; /* row/column unit vectors in public dicom element */
+
+    const Orientation orientation_list[WORLD_NDIMS] = {
+        SAGITTAL, CORONAL, TRANSVERSE
+    };
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("get_coordinate_info(%lx, ...)\n", (unsigned long) group_list);
+    }
+
+    /* Initialize a few things... */
+    for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+        found_dircos[ivolume] = FALSE;
+    }
+    found_coordinate = FALSE;
+
+#ifdef SPECIAL_CASE_IMA
+    /* TODO: For now this appears to be necessary.  In cases I don't fully
+     * understand, the IMA file's simulated image orientation does not
+     * give the correct direction cosines.  This appears to be an issue
+     * that may be related to the handedness of the coordinate system or
+     * some similar issue.
+     */
+    if (G.file_type == N3DCM || G.file_type == IMA) {
+        Acr_Element_Id dircos_elid[VOL_NDIMS];
+
+        /* Set direction cosine element ids. Note that the reversal of
+           rows and columns is intentional - their idea of the meaning
+           of theses labels is different from ours. (Their row vector
+           points along the row and not along the row dimension.) */
+
+        dircos_elid[VSLICE] = SPI_Image_normal;
+        dircos_elid[VROW] = SPI_Image_column;
+        dircos_elid[VCOLUMN] = SPI_Image_row;
+     
+        /* Get direction cosines
+         */
+        for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+            element = acr_find_group_element(group_list, dircos_elid[ivolume]);
+            if (element == NULL) {
+                continue;
+            }
+            if (acr_get_element_numeric_array(element, WORLD_NDIMS, dircos[ivolume])
+                != WORLD_NDIMS) {
+                continue;
+            }
+            /* negate the X and Z coordinates
+             */
+            convert_numa3_coordinate(dircos[ivolume]);
+            found_dircos[ivolume] = TRUE;
+        }
+    }
+    else {
+#endif
+        /* read in row/col vectors:
+         */
+        element = acr_find_group_element(group_list, 
+                                         ACR_Image_orientation_patient);
+        if (element == NULL) {
+            /* If we failed to find the newer, better patient orientation
+             * information, try to use the obsolete information if present.
+             */
+            element = acr_find_group_element(group_list,
+                                             ACR_Image_orientation_patient_old);
+        }
+        if (element == NULL) {
+            printf("WARNING: Failed to find image orientation!\n");
+        }
+        else if ((result = acr_get_element_numeric_array(element, 6, 
+                                                         RowColVec)) != 6) {
+            printf("WARNING: Failed to read image orientation! (%d, '%s')\n", 
+                   result, acr_get_element_string(element));
+        }
+        else {
+            dircos[VCOLUMN][XCOORD] = RowColVec[0];
+            dircos[VCOLUMN][YCOORD] = RowColVec[1];
+            dircos[VCOLUMN][ZCOORD] = RowColVec[2];
+
+            dircos[VROW][XCOORD] = RowColVec[3];
+            dircos[VROW][YCOORD] = RowColVec[4];
+            dircos[VROW][ZCOORD] = RowColVec[5];
+
+            found_dircos[VCOLUMN] = TRUE;
+            found_dircos[VROW] = TRUE;
+
+            convert_dicom_coordinate(dircos[VROW]);
+            convert_dicom_coordinate(dircos[VCOLUMN]);
+
+            /* slice direction unit vector is cross product of row,
+               col vectors:
+             */
+            dircos[VSLICE][XCOORD] = 
+                dircos[VCOLUMN][YCOORD] * dircos[VROW][ZCOORD] -
+                dircos[VCOLUMN][ZCOORD] * dircos[VROW][YCOORD];
+
+            dircos[VSLICE][YCOORD] = 
+                dircos[VCOLUMN][ZCOORD] * dircos[VROW][XCOORD] -
+                dircos[VCOLUMN][XCOORD] * dircos[VROW][ZCOORD];
+
+            dircos[VSLICE][ZCOORD] = 
+                dircos[VCOLUMN][XCOORD] * dircos[VROW][YCOORD] -
+                dircos[VCOLUMN][YCOORD] * dircos[VROW][XCOORD];
+            found_dircos[VSLICE] = TRUE;
+        }
+#ifdef SPECIAL_CASE_IMA
+    }
+#endif
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("dircos %f %f %f %f %f %f %f %f %f\n",
+               dircos[VSLICE][XCOORD],
+               dircos[VSLICE][YCOORD],
+               dircos[VSLICE][ZCOORD],
+               dircos[VROW][XCOORD],
+               dircos[VROW][YCOORD],
+               dircos[VROW][ZCOORD],
+               dircos[VCOLUMN][XCOORD],
+               dircos[VCOLUMN][YCOORD],
+               dircos[VCOLUMN][ZCOORD]);
+    }
+
+    /* Normalize the direction cosines
+     */
+    for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+        magnitude = 0.0;
+        for (iworld=0; iworld < WORLD_NDIMS; iworld++) {
+            magnitude += dircos[ivolume][iworld] * dircos[ivolume][iworld];
+        }
+        if (magnitude <= 0) {
+            found_dircos[ivolume] = FALSE;
+            continue;
+        }
+        magnitude = sqrt(magnitude);
+        for (iworld=0; iworld < WORLD_NDIMS; iworld++) {
+            dircos[ivolume][iworld] /= magnitude;
+        }
+    }
+
+    /* If we don't find direction cosines, then assume transverse volume
+     */
+    if (!found_dircos[VSLICE] || !found_dircos[VROW] || 
+        !found_dircos[VCOLUMN]) {
+
+        if (G.Debug) {
+            printf("Using default direction cosines\n");
+        }
+
+        for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+            for (iworld = 0; iworld < WORLD_NDIMS; iworld++) {
+                dircos[ivolume][iworld] = 
+                    ((ivolume == (WORLD_NDIMS-iworld-1)) ? -1.0 : 0.0);
+            }
+        }
+    }
+
+    /* Figure out volume index to world index mapping and sign of direction
+     * cosines - the code below figures out the primary direction in x,y,z
+     * of each volume coordinate (row,col,slice)
+     */
+    for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+        largest = -1.0;
+        for (iworld = 0; iworld < WORLD_NDIMS; iworld++) {
+            magnitude = dircos[ivolume][iworld];
+            if (magnitude < 0.0) magnitude = -magnitude;
+            if (magnitude > largest) {
+                largest = magnitude;
+                volume_to_world[ivolume] = iworld;
+            }
+        }
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" Volume_to_world slice=%s row=%s column=%s\n",
+               World_Names[volume_to_world[VSLICE]],
+               World_Names[volume_to_world[VROW]],
+               World_Names[volume_to_world[VCOLUMN]]);
+    }
+
+    /* Get orientation (depends on primary direction of slice normal)
+     */
+    *orientation = orientation_list[volume_to_world[VSLICE]];
+    if (G.Debug >= HI_LOGGING) {
+        printf(" Orientation is %s\n",
+               (*orientation == SAGITTAL) ? "SAGITTAL" : 
+               (*orientation == CORONAL) ? "CORONAL" : "TRANSVERSE");
+    }
+
+    /* Get step information
+     */
+    for (ivolume=0; ivolume < DARRAY_SIZE; ivolume++) {
+        darray[ivolume] = -DBL_MAX;
+    }
+
+    /* note ACR_Pixel_size should now be called Pixel_spacing
+     */
+    element = acr_find_group_element(group_list, ACR_Pixel_size);
+    if (element != NULL) {
+        acr_get_element_numeric_array(element, DARRAY_SIZE, darray);
+    }
+
+    if (darray[0] == -DBL_MAX) 
+        darray[0] = 1.0;
+    if (darray[1] == -DBL_MAX) 
+        darray[1] = darray[0];
+
+    steps[VCOLUMN] = darray[0];
+    steps[VROW] = darray[1];    /* anisotropic resolution? */
+
+    /* Figure out the slice thickness.  It could be from either one of
+     * two possible places in the file.
+     */
+    dbl_tmp1 = acr_find_double(group_list, ACR_Slice_thickness, 0.0);
+    dbl_tmp2 = acr_find_double(group_list, ACR_Spacing_between_slices, 0.0);
+
+    if (dbl_tmp1 == 0.0) {
+        if (dbl_tmp2 == 0.0) {
+            if (G.Debug >= HI_LOGGING) {
+                printf("Using default slice thickness of 1.0\n");
+            }
+            steps[VSLICE] = 1.0;
+        }
+        else {
+            if (G.Debug >= HI_LOGGING) {
+                printf("Using (0018,0088) for slice thickness\n");
+            }
+            steps[VSLICE] = dbl_tmp2;
+        }
+    }
+    else if (dbl_tmp2 == 0.0) {
+        if (G.Debug >= HI_LOGGING) {
+            printf("Using (0018,0050) for slice thickness\n");
+        }
+        steps[VSLICE] = dbl_tmp1;
+    }
+    else {
+        if (G.Debug && !NEARLY_EQUAL(dbl_tmp1, dbl_tmp2)) {
+            printf("WARNING: slice thickness conflict: ");
+            printf("old = %.10f, new = %.10f\n", dbl_tmp1, dbl_tmp2);
+        }
+        steps[VSLICE] = dbl_tmp2;
+    }
+
+    /* Make sure that direction cosines point the right way (dot
+     * product of direction cosine and axis is positive) and that step
+     * has proper sign.
+     */
+    for (ivolume = 0; ivolume < VOL_NDIMS; ivolume++) {
+        iworld = volume_to_world[ivolume];
+        if (dircos[ivolume][iworld] < 0.0) {
+            if (G.Debug >= HI_LOGGING) {
+                printf("Swapping direction of %s %s\n", 
+                       Volume_Names[ivolume],
+                       World_Names[iworld]);
+            }
+            steps[ivolume] *= -1.0;
+            for (iworld = 0; iworld < WORLD_NDIMS; iworld++) {
+                dircos[ivolume][iworld] *= -1.0;
+            }
+        }
+    }
+
+    /* Find 3D coordinate of slice - ACR_Image_position_patient gives
+     * the *corner* of the slice!
+     *
+     * Start by assuming that we didn't find it.
+     */
+    found_coordinate = FALSE;
+    for (iworld = 0; iworld < WORLD_NDIMS; iworld++) {
+        coordinate[iworld] = 0.0;
+    }
+
+    if (G.opts & OPTS_NO_LOCATION) {
+        /* If the coordinates are untrustworthy, just generate something
+         * reasonable for the slice coordinate.  Ignore the rest.
+         */
+        coordinate[volume_to_world[VSLICE]] = 
+            (steps[VSLICE] * fi_ptr->index[SLICE]);
+        found_coordinate = TRUE;
+    }
+    else {
+        element = acr_find_group_element(group_list, 
+                                         ACR_Image_position_patient);
+        if (element == NULL) {
+            element = acr_find_group_element(group_list, 
+                                             ACR_Image_position_patient_old);
+        }
+        if (element == NULL) {
+            printf("WARNING: Failed to find image position\n");
+        }
+        else if ((result = acr_get_element_numeric_array(element, 
+                                                         WORLD_NDIMS, 
+                                                         coordinate)) != WORLD_NDIMS) {
+            printf("WARNING: Failed to read image position (%d, '%s')\n", 
+                   result, acr_get_element_string(element));
+        }
+        else {
+            found_coordinate = TRUE;
+        }
+        if (!found_coordinate) {
+            /* Last gasp - try to interpret the slice location as our slice
+             * position.  It might work.
+             */
+            if (!found_coordinate) {
+                coordinate[volume_to_world[VSLICE]] = 
+                    acr_find_double(group_list, ACR_Slice_location, 1.0);
+            }
+        
+            found_coordinate = TRUE;
+        }
+    }
+
+    convert_dicom_coordinate(coordinate);
+
+    /* Work out start positions in volume coordinates
+     */
+    for (ivolume=0; ivolume < VOL_NDIMS; ivolume++) {
+       
+        if (found_coordinate && 
+            found_dircos[VSLICE] && 
+            found_dircos[VROW] &&
+            found_dircos[VCOLUMN]) {
+            starts[ivolume] = 
+                coordinate[XCOORD] * dircos[ivolume][XCOORD] +
+                coordinate[YCOORD] * dircos[ivolume][YCOORD] +
+                coordinate[ZCOORD] * dircos[ivolume][ZCOORD];
+        }
+        else {
+            starts[ivolume] = 0.0;
+        }
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" coordinate %f %f %f, start %f %f %f\n", 
+               coordinate[XCOORD], coordinate[YCOORD], coordinate[ZCOORD],
+               starts[VROW], starts[VCOLUMN], starts[VSLICE]);
+    }
+
+    /* Find position along each dimension
+     */
+    fi_ptr->coordinate[SLICE] = starts[VSLICE];
+    fi_ptr->coordinate[ECHO] = 
+        acr_find_double(group_list, ACR_Echo_time, 0.0) / MS_PER_SECOND;
+
+
+    /* Get the dimension width for time, if available.  The units are in
+     * milliseconds in DICOM, whereas we use seconds in MINC.
+     */
+    fi_ptr->width[TIME] = acr_find_double(group_list,
+                                          ACR_Actual_frame_duration,
+                                          0.0) / MS_PER_SECOND;
+
+    /* PET scan times (bert)
+     */
+    start_time = acr_find_double(group_list, ACR_Frame_reference_time, -1.0);
+    frame_time = acr_find_double(group_list, ACR_Actual_frame_duration, -1.0);
+    if (start_time > 0.0 && frame_time > 0.0) {
+        frame_time = start_time / 1000.0; /* Convert msec to seconds. */
+    }
+    else {
+        /* time section (rhoge)
+         * now assume that time has been fixed when file was read
+         */
+        start_time = acr_find_double(group_list, ACR_Series_time, 0.0);
+        frame_time = acr_find_double(group_list, ACR_Acquisition_time, 0.0);
+        start_time = convert_time_to_seconds(start_time);
+        frame_time = convert_time_to_seconds(frame_time) - start_time;
+
+        /* check for case where scan starts right before midnight,
+         * but frame is after midnight
+         */
+        if (frame_time < 0.0) {
+            frame_time += SECONDS_PER_DAY;
+        }
+    }
+    fi_ptr->coordinate[TIME] = frame_time;
+
+    /* end of time section */
+
+    fi_ptr->coordinate[PHASE] = 0.0;
+    fi_ptr->coordinate[CHEM_SHIFT] = 0.0;
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : convert_numa3_coordinate
+   @INPUT      : coordinate
+   @OUTPUT     : coordinate
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to convert a coordinate to the correct orientation
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : made version specific to Numaris 3 SPI data (rhoge)
+   ---------------------------------------------------------------------------- */
+static void 
+convert_numa3_coordinate(double coordinate[WORLD_NDIMS])
+{
+    coordinate[XCOORD] = -coordinate[XCOORD];
+    coordinate[ZCOORD] = -coordinate[ZCOORD];
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : convert_dicom_coordinate
+   @INPUT      : coordinate
+   @OUTPUT     : coordinate
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to convert a coordinate to the correct orientation
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : made new dicom version (rhoge)
+   ---------------------------------------------------------------------------- */
+static void
+convert_dicom_coordinate(double coordinate[WORLD_NDIMS])
+{
+    /* Allow the user to override this, if only for debugging purposes...
+     */
+    if (G.opts & OPTS_KEEP_COORD) {
+        return;
+    }
+
+    coordinate[XCOORD] = -coordinate[XCOORD];
+    coordinate[YCOORD] = -coordinate[YCOORD];
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_general_header_info
+   @INPUT      : group_list - input data
+   @OUTPUT     : gi_ptr - general information about files
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to extract general header information from a group list
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+static void
+get_string_field(char *out_str, Acr_Group group_list, 
+                 Acr_Element_Id element_id)
+{
+    strncpy(out_str, acr_find_string(group_list, element_id, ""), 
+            STRING_T_LEN);
+}
+                 
+void
+get_general_header_info(Acr_Group group_list, General_Info *gi_ptr)
+{
+    int length;
+    char *string;
+
+    if (G.Debug) {
+        printf("SOP Class UID: %s\n",
+               acr_find_string(group_list, ACR_SOP_Class_UID, ""));
+        printf("Images in acquisition: %d\n", 
+               acr_find_int(group_list, ACR_Images_in_acquisition, -1));
+        printf("Acquisitions in series: %d\n", 
+               acr_find_int(group_list, ACR_Acquisitions_in_series, -1));
+        printf("3D raw partitions: %d\n", 
+               acr_find_int(group_list, SPI_Number_of_3D_raw_partitions_nominal, -1));
+    }
+    /* Get intensity units */
+    strncpy(gi_ptr->units, "", STRING_T_LEN);
+
+    /* Get patient info */
+    get_string_field(gi_ptr->patient.name, group_list, ACR_Patient_name);
+
+    get_string_field(gi_ptr->patient.identification,
+                     group_list, ACR_Patient_identification);
+    get_string_field(gi_ptr->patient.birth_date,
+                     group_list, ACR_Patient_birth_date);
+
+    get_string_field(gi_ptr->patient.age,
+                     group_list, ACR_Patient_age);
+
+    string = acr_find_string(group_list, ACR_Patient_sex, "");
+    if (*string == 'M') 
+        strncpy(gi_ptr->patient.sex, MI_MALE, STRING_T_LEN);
+    else if (*string == 'F') 
+        strncpy(gi_ptr->patient.sex, MI_FEMALE, STRING_T_LEN);
+    else if (*string == 'O') 
+        strncpy(gi_ptr->patient.sex, MI_OTHER, STRING_T_LEN);
+    else 
+        strncpy(gi_ptr->patient.sex, "", STRING_T_LEN);
+
+    gi_ptr->patient.weight = 
+        acr_find_double(group_list, ACR_Patient_weight, -DBL_MAX);
+
+    /* added by rhoge - registration timing info */
+    get_string_field(gi_ptr->patient.reg_date,
+                     group_list, ACR_Study_date);
+
+    get_string_field(gi_ptr->patient.reg_time, 
+                     group_list, ACR_Study_time);
+
+    /* Get study info */
+    get_string_field(gi_ptr->study.start_time, 
+                     group_list, ACR_Study_date);
+
+    length = strlen(gi_ptr->study.start_time);
+    gi_ptr->study.start_time[length] = ' ';
+    length++;
+    strncpy(&gi_ptr->study.start_time[length], 
+            acr_find_string(group_list, ACR_Study_time, ""), STRING_T_LEN - length);
+    string = acr_find_string(group_list, ACR_Modality, "");
+    if (strcmp(string, ACR_MODALITY_MR) == 0)
+        strncpy(gi_ptr->study.modality, MI_MRI, STRING_T_LEN);
+    else if (strcmp(string, ACR_MODALITY_PT) == 0)
+        strncpy(gi_ptr->study.modality, MI_PET, STRING_T_LEN);
+    get_string_field(gi_ptr->study.manufacturer, 
+                     group_list, ACR_Manufacturer);
+    get_string_field(gi_ptr->study.model, 
+                     group_list, ACR_Manufacturer_model);
+    gi_ptr->study.field_value = 
+        acr_find_double(group_list, ACR_Magnetic_field_strength, -DBL_MAX);
+    get_string_field(gi_ptr->study.software_version, 
+                     group_list, ACR_Software_versions);
+    get_string_field(gi_ptr->study.serial_no, 
+                     group_list, ACR_Device_serial_number);
+    get_string_field(gi_ptr->study.calibration_date, 
+                     group_list, ACR_Calibration_date);
+    get_string_field(gi_ptr->study.institution, 
+                     group_list, ACR_Institution_id);
+    get_string_field(gi_ptr->study.station_id, 
+                     group_list, ACR_Station_id);
+    get_string_field(gi_ptr->study.referring_physician, 
+                     group_list, ACR_Referring_physician);
+    get_string_field(gi_ptr->study.performing_physician, 
+                     group_list, ACR_Performing_physician);
+    get_string_field(gi_ptr->study.operator, 
+                     group_list, ACR_Operators_name);
+    get_string_field(gi_ptr->study.procedure, 
+                     group_list, ACR_Procedure_description);
+    sprintf(gi_ptr->study.study_id, "%.6f",gi_ptr->study_id);
+
+    /* Acquisition id modified by rhoge to get rid of first digit that 
+       is not required for identification of run */
+    /*   sprintf(gi_ptr->study.acquisition_id, "%d_%d",
+         acr_find_int(group_list, ACR_Series, 0), gi_ptr->acq_id); */
+    sprintf(gi_ptr->study.acquisition_id, "%d", gi_ptr->acq_id);
+
+    /* Get acquisition information */
+
+    get_string_field(gi_ptr->acq.scan_seq, group_list, ACR_Sequence_name);
+    get_string_field(gi_ptr->acq.protocol_name, group_list, ACR_Protocol_name);
+    get_string_field(gi_ptr->acq.receive_coil, group_list, 
+                     ACR_Receive_coil_name);
+    get_string_field(gi_ptr->acq.transmit_coil, group_list, 
+                     ACR_Transmit_coil_name);
+
+    gi_ptr->acq.rep_time = 
+        acr_find_double(group_list, ACR_Repetition_time, -DBL_MAX);
+    if (gi_ptr->acq.rep_time != -DBL_MAX)
+        gi_ptr->acq.rep_time /= 1000.0;
+
+    gi_ptr->acq.echo_time = 
+        acr_find_double(group_list, ACR_Echo_time, -DBL_MAX);
+    if (gi_ptr->acq.echo_time != -DBL_MAX)
+        gi_ptr->acq.echo_time /= 1000.0;
+
+    gi_ptr->acq.echo_number = 
+        acr_find_double(group_list, ACR_Echo_number, -DBL_MAX);
+
+    gi_ptr->acq.inv_time = 
+        acr_find_double(group_list, ACR_Inversion_time, -DBL_MAX);
+    if (gi_ptr->acq.inv_time != -DBL_MAX)
+        gi_ptr->acq.inv_time /= 1000.0;
+    gi_ptr->acq.b_value = 
+        acr_find_double(group_list, EXT_Diffusion_b_value, -DBL_MAX);
+    gi_ptr->acq.flip_angle = 
+        acr_find_double(group_list, ACR_Flip_angle, -DBL_MAX);
+    gi_ptr->acq.slice_thickness = 
+        acr_find_double(group_list, ACR_Slice_thickness, -DBL_MAX);
+    gi_ptr->acq.num_slices = 
+        acr_find_double(group_list, ACR_Images_in_acquisition, -DBL_MAX);
+    gi_ptr->acq.num_dyn_scans = 
+        acr_find_double(group_list, ACR_Acquisitions_in_series, -DBL_MAX);
+    gi_ptr->acq.num_avg = 
+        acr_find_double(group_list, ACR_Nr_of_averages, -DBL_MAX);
+    gi_ptr->acq.imaging_freq = 
+        acr_find_double(group_list, ACR_Imaging_frequency, -DBL_MAX);
+    if (gi_ptr->acq.imaging_freq != -DBL_MAX)
+        gi_ptr->acq.imaging_freq *= 1e6;
+    get_string_field(gi_ptr->acq.imaged_nucl, 
+                     group_list, ACR_Imaged_nucleus);
+    gi_ptr->acq.win_center = 
+        acr_find_double(group_list, ACR_Window_centre, -DBL_MAX);
+    gi_ptr->acq.win_width = 
+        acr_find_double(group_list, ACR_Window_width, -DBL_MAX);
+
+    gi_ptr->acq.num_phase_enc_steps = 
+        acr_find_double(group_list, ACR_Number_of_phase_encoding_steps, -DBL_MAX);
+    gi_ptr->acq.percent_sampling = 100 * 
+        acr_find_double(group_list, ACR_Percent_sampling, -DBL_MAX);
+
+    gi_ptr->acq.percent_phase_fov = 100 *
+        acr_find_double(group_list, ACR_Percent_phase_field_of_view, -DBL_MAX);
+
+    gi_ptr->acq.pixel_bandwidth = 
+        acr_find_double(group_list, ACR_Pixel_bandwidth, -DBL_MAX);
+
+    gi_ptr->acq.sar = acr_find_double(group_list, ACR_SAR, -DBL_MAX);
+
+    get_string_field(gi_ptr->acq.mr_acq_type, 
+                     group_list, ACR_MR_acquisition_type);
+
+    get_string_field(gi_ptr->acq.image_type, group_list, ACR_Image_type);
+    if (G.Debug) {
+        if (strstr(gi_ptr->acq.image_type, "MOSAIC") != NULL) {
+            printf("This appears to be a Mosaic image\n");
+        }
+    }
+
+    get_string_field(gi_ptr->acq.phase_enc_dir, 
+                     group_list, ACR_Phase_encoding_direction);
+
+    strncpy(gi_ptr->acq.comments, "", STRING_T_LEN);
+
+    /* Siemens Numaris 4 specific!
+     */
+
+#if 0
+    gi_ptr->acq.MrProt = strdup(acr_find_string(group_list, EXT_MrProt_dump,
+                                                ""));
+#else
+    gi_ptr->acq.MrProt = strdup("");
+#endif
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : convert_time_to_seconds
+   @INPUT      : dicom_time
+   @OUTPUT     : (none)
+   @RETURNS    : real time in seconds from beginning of day
+   @DESCRIPTION: Routine to convert dicom seconds (decimal hhmmss.xxxxx) to 
+   real seconds since the start of day.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static double
+convert_time_to_seconds(double dicom_time)
+{
+    /* Constants */
+#define DICOM_SECONDS_PER_HOUR 10000.0
+#define DICOM_SECONDS_PER_MINUTE 100.0
+
+    /* Variables */
+    double hh, mm, ss;
+
+    /* Get the components of the time */
+
+    hh = (int) (dicom_time / DICOM_SECONDS_PER_HOUR);
+    dicom_time -= hh * DICOM_SECONDS_PER_HOUR;
+    mm = (int) (dicom_time / DICOM_SECONDS_PER_MINUTE);
+    dicom_time -= mm * DICOM_SECONDS_PER_MINUTE;
+    ss = dicom_time;
+
+    /* Work out the number of seconds */
+
+    return (hh * 3600.0) + (mm * 60.0) + ss;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : get_siemens_dicom_image
+   @INPUT      : group_list - input data
+   @OUTPUT     : image - image data structure (user must free data)
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to get an image from a group list
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : November 25, 1993 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+void 
+get_siemens_dicom_image(Acr_Group group_list, Image_Data *image)
+{
+
+    /* Variables */
+    Acr_Element element;
+    int nrows, ncolumns;
+    int bits_alloc;
+    int bits_stored;
+    int image_group;
+    void *data = NULL;
+    long imagepix, ipix;
+    struct Acr_Element_Id elid;
+    nc_type datatype;
+
+    /* Get the image information */
+    bits_alloc = acr_find_short(group_list, ACR_Bits_allocated, 0);
+    bits_stored = acr_find_short(group_list, ACR_Bits_stored, bits_alloc);
+    nrows = acr_find_short(group_list, ACR_Rows, 0);
+    ncolumns = acr_find_short(group_list, ACR_Columns, 0);
+    image_group = acr_find_short(group_list, ACR_Image_location, 
+                                 ACR_IMAGE_GID);
+
+    /* Figure out type */
+    if (bits_alloc > CHAR_BIT)
+        datatype = NC_SHORT;
+    else 
+        datatype = NC_BYTE;
+
+    /* Set image info */
+    image->nrows = nrows;
+    image->ncolumns = ncolumns;
+    imagepix = nrows * ncolumns;
+    image->data = (unsigned short *) MALLOC(imagepix * sizeof(short));
+    image->free = TRUE;
+
+    /* Get image pointer */
+    elid.group_id = image_group;
+    elid.element_id = ACR_IMAGE_EID;
+    element = acr_find_group_element(group_list, &elid);
+    if (element == NULL) {
+        memset(image->data, 0, imagepix * sizeof(short));
+        return;
+    }
+    data = acr_get_element_data(element);
+
+    /* Convert the data according to type */
+
+    /* Look for byte data */
+    if (datatype == NC_BYTE) {
+        for (ipix=0; ipix < imagepix; ipix++) {
+            image->data[ipix] = *((unsigned char *) data + ipix);
+        }
+    }
+    else {
+
+        /* Look for unpacked short data */
+        if (bits_alloc == nctypelen(datatype) * CHAR_BIT) {
+            acr_get_short(acr_get_element_byte_order(element), 
+                          nrows*ncolumns, data, image->data);
+        }
+
+        /* Fill with zeros in any other case */
+        else {
+            memset(image->data, 0, imagepix * sizeof(short));
+        }
+    }
+
+    return;
+}
+
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : parse_dicom_groups
+   @INPUT      : group_list - list of acr-nema groups that make up object
+   @OUTPUT     : data_info - information about data object
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to parse dicom object
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : June 2001 (Rick Hoge)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+#define IDEFAULT (-1)
+
+void
+parse_dicom_groups(Acr_Group group_list, Data_Object_Info *di_ptr)
+{
+    Acr_Element element;
+    unsigned short AcqMat[4];
+    unsigned short freq_rows;
+    unsigned short freq_cols;
+    unsigned short phase_rows;
+    unsigned short phase_cols;
+    double slice_coord[WORLD_NDIMS];
+
+    /* Get info to construct unique identifiers for study, series/acq
+     * for file processing
+     */
+    get_identification_info(group_list,
+                            &(di_ptr->study_id), &(di_ptr->acq_id),
+                            &(di_ptr->rec_num), &(di_ptr->image_type));
+
+    /* Get number of echos, echo number, number of dynamic scans and 
+     * dynamic_scan_number
+     */
+
+    di_ptr->num_echoes = acr_find_int(group_list,
+                                      ACR_Echo_train_length, 
+                                      IDEFAULT);
+
+    di_ptr->echo_number = acr_find_int(group_list, 
+                                       ACR_Echo_number, 
+                                       IDEFAULT);
+
+    di_ptr->num_dyn_scans = acr_find_int(group_list, 
+                                         ACR_Acquisitions_in_series, 
+                                         IDEFAULT);
+
+    di_ptr->dyn_scan_number = acr_find_int(group_list, 
+                                           ACR_Acquisition, 
+                                           IDEFAULT);
+
+    di_ptr->global_image_number = acr_find_int(group_list, 
+                                               ACR_Image, 
+                                               IDEFAULT);
+
+    /* rhoge:
+       new info added to di_ptr by rhoge: nominal number of slices;
+       this is used in detection of a stream of files with the same
+       acquisition ID number in which there are more files than
+       slices.  If the number of signal averages is greater than one,
+       we will assume that this means the acquisition loop was used for
+       dynamic scanning.  
+
+       WARNINGS:  the same thing may need to be done with `number of
+       partitions' for it to work with 3D scans  */
+
+    di_ptr->num_slices_nominal = acr_find_int(group_list,
+                                              ACR_Images_in_acquisition,
+                                              IDEFAULT);
+
+    di_ptr->slice_number = acr_find_int(group_list,
+                                        SPI_Current_slice_number,
+                                        IDEFAULT);
+
+    di_ptr->slice_location = acr_find_double(group_list,
+                                             ACR_Slice_location,
+                                             0.0);
+
+    di_ptr->coord_found = 0;
+    element = acr_find_group_element(group_list, ACR_Image_position_patient);
+    if (element == NULL) {
+        element = acr_find_group_element(group_list,
+                                         ACR_Image_position_patient_old);
+    }
+    if (element != NULL) {
+        if (acr_get_element_numeric_array(element, WORLD_NDIMS, 
+                                          slice_coord) == WORLD_NDIMS) {
+            di_ptr->coord_found = 1;
+        }
+    }
+
+    /* identification info needed to generate unique session id
+     * for file names
+     */
+    di_ptr->study_date = acr_find_int(group_list, ACR_Study_date, 
+                                      IDEFAULT); 
+
+    di_ptr->study_time = acr_find_int(group_list, ACR_Study_time, 
+                                      IDEFAULT); 
+
+    di_ptr->scanner_serialno = acr_find_int(group_list, 
+                                            ACR_Device_serial_number, 
+                                            IDEFAULT); 
+
+    /* identification info needed to determine if mosaics used 
+     */
+
+    element = acr_find_group_element(group_list, ACR_Acquisition_matrix);
+
+    if (element != NULL) {
+        acr_get_element_short_array(element, 4, AcqMat);
+
+        freq_rows = AcqMat[0];
+        freq_cols = AcqMat[1];
+    
+        phase_rows = AcqMat[2];
+        phase_cols = AcqMat[3];
+
+        /* rows in acq matrix is larger of freq rows and freq columns:
+         */
+        di_ptr->acq_rows = ( freq_rows > freq_cols ? freq_rows : freq_cols );
+
+        /* all images are square, at this time 
+         */
+        di_ptr->acq_cols = di_ptr->acq_rows;
+    }
+    else {
+        di_ptr->acq_rows = IDEFAULT;
+        di_ptr->acq_cols = IDEFAULT;
+    }
+
+    di_ptr->rec_rows = acr_find_int(group_list, ACR_Rows, IDEFAULT);
+    di_ptr->rec_cols = acr_find_int(group_list, ACR_Columns, IDEFAULT);
+
+    di_ptr->num_mosaic_rows = acr_find_int(group_list, EXT_Mosaic_rows, 
+                                           IDEFAULT);
+    di_ptr->num_mosaic_cols = acr_find_int(group_list, EXT_Mosaic_columns, 
+                                           IDEFAULT);
+    di_ptr->num_slices_in_file = acr_find_int(group_list, EXT_Slices_in_file,
+                                              IDEFAULT);
+
+    /* sequence, protocol names (useful for debugging):
+     */
+
+    get_string_field(di_ptr->sequence_name, group_list, ACR_Sequence_name);
+    get_string_field(di_ptr->protocol_name, group_list, ACR_Protocol_name);
+    get_string_field(di_ptr->patient_name, group_list, ACR_Patient_name);
+    get_string_field(di_ptr->patient_id, group_list, ACR_Patient_identification);
+}
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dicom_read.h
@@ -0,0 +1,4 @@
+extern void get_siemens_dicom_image(Acr_Group group_list, Image_Data *image);
+extern void parse_dicom_groups(Acr_Group group_list, Data_Object_Info *di_ptr);
+extern void get_file_info(Acr_Group group_list, File_Info *file_info,
+                          General_Info *general_info);
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dicom_to_minc.c
@@ -0,0 +1,1823 @@
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : dicom_to_minc.c
+   @DESCRIPTION: Code to convert a list of DICOM files to minc 
+   format.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : January 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   * $Log: dicom_to_minc.c,v $
+   * Revision 1.13.2.1  2005-05-12 21:16:47  bert
+   * Initial checkin
+   *
+   * Revision 1.13  2005/05/09 15:33:20  bert
+   * Fix handing of descending mosaic sequences; don't print GEMS field missing warnings by default
+   *
+   * Revision 1.12  2005/04/28 17:38:06  bert
+   * Insert and retrieve width information when sorting a dimension
+   *
+   * Revision 1.11  2005/04/21 22:31:29  bert
+   * Copy SPI_Magnetic_field_strength to standard field in copy_spi_to_acr(); Relax some tests to avoid spurious warnings
+   *
+   * Revision 1.10  2005/04/20 23:25:50  bert
+   * Add copy_spi_to_acr() function, minor name and comment changes
+   *
+   * Revision 1.9  2005/04/20 17:48:16  bert
+   * Copy SPI_Number_of_slices_nominal to ACR_Image_in_acquisition for Siemens
+   *
+   * Revision 1.8  2005/04/18 21:04:25  bert
+   * Get rid of old is_reversed behavior, always use most natural sort of the image. Also tried to fix listing function somewhat.
+   *
+   * Revision 1.7  2005/04/05 21:55:33  bert
+   * Update handling of Siemens ASCCONV to reflect value of uc2DInterpolation field for mosaic images.  Additional cleanup of mosaic code and minor tweak to suppress GEMS warning message for PET data.
+   *
+   * Revision 1.6  2005/03/29 20:20:42  bert
+   * Add checks for GE Medical Systems proprietary files
+   *
+   * Revision 1.5  2005/03/14 22:26:40  bert
+   * Dump the entire coordinate array for each MRI dimension after sorting.  Also detect GE scans.
+   *
+   * Revision 1.4  2005/03/13 19:35:11  bert
+   * Lots of changes for dealing with some proprietary Philips stuff
+   *
+   * Revision 1.3  2005/03/03 18:59:15  bert
+   * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+   *
+   * Revision 1.2  2005/03/02 20:16:24  bert
+   * Latest changes and cleanup
+   *
+   * Revision 1.1  2005/02/17 16:38:10  bert
+   * Initial checkin, revised DICOM to MINC converter
+   *
+   * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+   * Leili's dicom server for sonata
+   *
+   * Revision 1.18  2002/09/26 15:24:33  rhoge
+   * Before was only skipping time sort for multi-slice N4 mosaics.  Turns out
+   * this was also causing failure on single-slice scans.
+   * Changed slices>1 to slices>0 so that now N4 dicom scans never get sorted
+   * on their (apparently nonsensical) time value.  The if statement should
+   * really be reworked, and should keep an eye on this.  Seems like EPI
+   * time series sequences never sort properly on 'time'.
+   *
+   * Revision 1.17  2002/09/25 17:25:43  rhoge
+   * changed public void's to public int's
+   *
+   * Revision 1.16  2002/05/08 19:32:40  rhoge
+   * fixed handling of diffusion scans with separate series for each average
+   *
+   * Revision 1.15  2002/05/01 21:29:34  rhoge
+   * removed MrProt from minc header - encountered files with large strings,
+   * causing seg faults
+   *
+   * Revision 1.14  2002/04/30 12:36:35  rhoge
+   * fixes to handle current (and hopefully final) diffusion sequence
+   *
+   * Revision 1.13  2002/04/26 03:27:03  rhoge
+   * fixed MrProt problem - replaced fixed lenght char array with malloc
+   *
+   * Revision 1.12  2002/04/08 03:40:56  rhoge
+   * fixed mosaic extraction for non-square scans and 3D scans.
+   * added some new dicom elements
+   *
+   * Revision 1.11  2002/03/27 19:38:08  rhoge
+   * small comment change
+   *
+   * Revision 1.10  2002/03/27 18:57:50  rhoge
+   * added diffusion b value
+   *
+   * Revision 1.9  2002/03/23 13:17:53  rhoge
+   * added support for Bourget network pushed dicom files, cleaned up
+   * file check and read_numa4_dicom vr check/assignment
+   *
+   * Revision 1.8  2002/03/22 19:19:36  rhoge
+   * Numerous fixes -
+   * - handle Numaris 4 Dicom patient name
+   * - option to cleanup input files
+   * - command option
+   * - list-only option
+   * - debug mode
+   * - user supplied name, idstr
+   * - anonymization
+   *
+   * Revision 1.7  2002/03/21 13:31:56  rhoge
+   * updated comments
+   *
+   * Revision 1.6  2002/03/19 22:10:16  rhoge
+   * removed time sorting for N4DCM mosaics - time is random for mosaics
+   *
+   * Revision 1.5  2002/03/19 13:13:56  rhoge
+   * initial working mosaic support - I think time is scrambled though.
+   *
+   * Revision 1.4  2001/12/31 18:27:21  rhoge
+   * modifications for dicomreader processing of Numaris 4 dicom files - at
+   * this point code compiles without warning, but does not deal with
+   * mosaiced files.  Also will probably not work at this time for Numaris
+   * 3 .ima files.  dicomserver may also not be functional...
+   *
+   * Revision 1.3  2000/12/14 21:37:11  rhoge
+   * log message cleanup
+   *
+   * Revision 1.2  2000/12/14 21:36:22  rhoge
+   * changes to restore measurement loop support that was broken by changes
+   * to provide acquisition loop support
+   *
+   * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+   * imported sources to CVS repository on amoeba
+   * -now support Siemens acquisition loop scans with and without correction
+   *  on sending side
+   *
+   * Revision 6.1  1999/10/29 17:51:59  neelin
+   * Fixed Log keyword
+   *
+   * Revision 6.0  1997/09/12 13:24:27  neelin
+   * Release of minc version 0.6
+   *
+   * Revision 5.0  1997/08/21  13:25:26  neelin
+   * Release of minc version 0.5
+   *
+   * Revision 4.0  1997/05/07  20:06:20  neelin
+   * Release of minc version 0.4
+   *
+   * Revision 1.1  1997/03/04  20:56:47  neelin
+   * Initial revision
+   *
+   @COPYRIGHT : Copyright 1997 Peter Neelin, McConnell Brain Imaging
+   Centre, Montreal Neurological Institute, McGill University.
+   Permission to use, copy, modify, and distribute this software and
+   its documentation for any purpose and without fee is hereby
+   granted, provided that the above copyright notice appear in all
+   copies.  The author and McGill University make no representations
+   about the suitability of this software for any purpose.  It is
+   provided "as is" without express or implied warranty.
+   ---------------------------------------------------------------------------- */
+
+static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/dicom_to_minc.c,v 1.13.2.1 2005-05-12 21:16:47 bert Exp $";
+#include "dcm2mnc.h"
+#include <math.h>
+
+const char *World_Names[WORLD_NDIMS] = { "X", "Y", "Z" };
+const char *Volume_Names[VOL_NDIMS] = { "Slice", "Row", "Column" };
+const char *Mri_Names[MRI_NDIMS] = {"Slice", "Echo", "Time", "Phase", "ChmSh"};
+
+/* Private structure definitions. */
+
+/* multi-image (mosaic) info */
+typedef struct {
+    int packed;
+    mosaic_seq_t mosaic_seq;
+    int size[2];
+    int big[2];
+    int grid[2];
+    int pixel_size;
+    Acr_Element big_image;
+    Acr_Element small_image;
+    int sub_images;
+    int slice_count;
+    double normal[WORLD_NDIMS];
+    double step[WORLD_NDIMS];
+    double position[WORLD_NDIMS];
+} Mosaic_Info;
+
+/* Structure for sorting dimensions */
+typedef struct {
+   int identifier;
+   int original_index;
+   double value;
+   double width;
+} Sort_Element;
+
+/* Private function definitions */
+static int mosaic_init(Acr_Group, Mosaic_Info *, int);
+static void mosaic_cleanup(Acr_Group, Mosaic_Info *);
+static int mosaic_modify_group_list(Acr_Group, Mosaic_Info *, int, int);
+
+static void free_info(General_Info *gi_ptr, File_Info *fi_ptr, 
+                      int num_files);
+static int dimension_sort_function(const void *v1, const void *v2);
+static void sort_dimensions(General_Info *gi_ptr);
+static int prot_find_string(Acr_Element Protocol, const char *name,
+                            char *value);
+static char *dump_protocol_text(Acr_Element Protocol);
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : dicom_to_minc
+   @INPUT      : num_files - number of image files
+   file_list - list of file names
+   minc_file - name of minc file to create, or NULL to make one up.
+   clobber - if TRUE, then open the output with NC_CLOBBER
+   file_prefix - string providing any directory or prefix 
+   for internally generated filename (if it is a directory,
+   then it must contain the last "/")
+   @OUTPUT     : output_file_name - returns a pointer to an internal area
+   containing the file name of the created file if minc_file
+   is NULL, or simply a pointer to minc_file. If NULL, then
+   nothing is returned.
+   @RETURNS    : EXIT_SUCCESS if no error, EXIT_FAILURE on error.
+   @DESCRIPTION: Routine to convert a list of Siemens dicom files to minc 
+   format.
+   @METHOD     : 
+   @GLOBALS    :
+   @CALLS      : 
+   @CREATED    : November 25, 1993 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+int
+dicom_to_minc(int num_files, 
+              const char *file_list[], 
+              const char *minc_file,
+              int clobber,
+              const char *file_prefix, 
+              char **output_file_name)
+{
+    Acr_Group group_list;     /* List of ACR/NEMA groups & elements */
+    File_Info *fi_ptr;          /* Array of per-file information */
+    General_Info gi;     /* General (common) DICOM file information */
+    int max_group;              /* Maximum group number to read */
+    Image_Data image;           /* Actual image data */
+    int icvid;                  /* MINC Image Conversion Variable */
+    int ifile;                  /* File index */
+    Mri_Index imri;             /* MRI axis index */
+    char *out_file_name;        /* Output MINC filename */
+    int isep;                   /* Loop counter */
+    const Loop_Type loop_type = NONE; /* MINC loop type always none for now */
+    int subimage;               /* Loop counter for MOSAIC images per file */
+    int iimage;                 /* Loop counter for all files/images */
+    int num_images_allocated;   /* Total number of slices (>= # files) */
+    Mosaic_Info mi;             /* Mosaic (multi-image) information */
+    int n_slices_in_file;
+
+    /* Allocate space for the file information */
+    fi_ptr = malloc(num_files * sizeof(*fi_ptr));
+    CHKMEM(fi_ptr);
+
+    num_images_allocated = num_files;
+
+    /* Last group needed for first pass
+     */
+    max_group = ACR_IMAGE_GID - 1;
+
+    /* Add all control characters as numeric array separators to handle 
+     * odd behaviour with Siemens dicom files
+     */
+    for (isep = 0; isep < 31; isep++) {
+        acr_element_numeric_array_separator(isep);
+    }
+
+    /* Initialize some values for general info */
+    gi.initialized = FALSE;
+    gi.group_list = NULL;
+    for (imri = 0; imri < MRI_NDIMS; imri++) {
+        gi.indices[imri] = NULL;
+        gi.coordinates[imri] = NULL;
+        gi.widths[imri] = NULL;
+    }
+
+    /* Loop through file list getting information
+     * (note that we have to duplicate the handling
+     * of multiple images per file in this loop
+     * to accumulate dimension sizes correctly)
+
+     * need separate counter for images, since some files may
+     * contain more than one image!
+     */
+    iimage = 0;
+
+    for (ifile = 0; ifile < num_files; ifile++) {
+        if (G.Debug >= HI_LOGGING) {
+            printf("\nFile %s\n", file_list[ifile]);
+        }
+
+        if (!G.Debug) {
+            progress(ifile, num_files, "-Parsing series info");
+        }
+
+        /* Read the file
+         */
+        if (G.file_type == N4DCM) {
+            group_list = read_numa4_dicom(file_list[ifile], max_group);
+        } 
+        else if (G.file_type == IMA) {
+            group_list = siemens_to_dicom(file_list[ifile], max_group);
+        }
+
+        if (group_list == NULL) {
+            fprintf(stderr, "Error parsing file '%s' on 1st pass.\n",
+                    file_list[ifile]);
+            exit(-1);
+        }
+
+        if (G.opts & OPTS_NO_MOSAIC) {
+            n_slices_in_file = 1;
+        }
+        else {
+            n_slices_in_file = acr_find_int(group_list, EXT_Slices_in_file, 1);
+        }
+
+        /* initialize big and small images, if mosaic
+         */
+        if (n_slices_in_file > 1) {
+
+            mosaic_init(group_list, &mi, FALSE);
+
+            num_images_allocated += n_slices_in_file - 1;
+
+            fi_ptr = realloc(fi_ptr, num_images_allocated * sizeof(*fi_ptr));
+            CHKMEM(fi_ptr);
+        }
+
+        /* loop over subimages in mosaic
+         */
+        for (subimage = 0; subimage < n_slices_in_file; subimage++) {
+
+            /* Modify the group list for this image if mosaic
+             */
+            if (n_slices_in_file > 1) {
+                mosaic_modify_group_list(group_list, &mi, subimage, FALSE);
+            }
+
+            /* Get file-specific information
+             */
+            get_file_info(group_list, &fi_ptr[iimage], &gi);
+
+            /* increment iimage here
+             */
+            iimage++;
+        }
+
+        /* Delete the group list
+         */
+        acr_delete_group_list(group_list);
+
+        /* cleanup mosaic struct if used
+         */
+        if (n_slices_in_file > 1) {
+            mosaic_cleanup(group_list, &mi);
+        }
+    }
+
+    /* Sort the dimensions */
+    sort_dimensions(&gi);
+
+    /* Create the output file
+     */
+    if (gi.initialized) {
+        icvid = create_minc_file(minc_file,
+                                 clobber,
+                                 &gi,
+                                 file_prefix,
+                                 &out_file_name,
+                                 loop_type);
+    }
+    if (output_file_name != NULL) {
+        *output_file_name = out_file_name;
+    }
+
+    /* Check that we found the general info and that the minc file was
+     * created okay
+     */
+    if ((!gi.initialized) || (icvid == MI_ERROR)) {
+        if (gi.initialized) {
+            fprintf(stderr, "Error creating MINC file %s.\n", out_file_name);
+        }
+        free_info(&gi, fi_ptr, num_files);
+        free(fi_ptr);
+        return EXIT_FAILURE;
+    }
+
+    if (G.Debug) {
+        printf("Writing %d images to MINC file\n", num_files);
+    }	  
+
+    /* Last group needed for second pass
+     * we now have to read up to and including the image, 
+     * since image pointers are needed in mosaic_init
+     */
+    max_group = ACR_IMAGE_GID;
+
+    /* Loop through the files again and put images into the minc file
+     */
+    iimage = 0;
+    for (ifile = 0; ifile < num_files; ifile++) {
+
+        if (!G.Debug) {
+            progress(ifile, num_files, "-Creating minc file");
+        }
+
+        /* Check that we have a valid file 
+         */
+        if (!fi_ptr[ifile].valid) {
+            printf("WARNING: file %s was marked invalid\n", 
+                   file_list[ifile]);
+            continue;
+        }
+     
+        /* Read the file 
+         */
+        if (G.file_type == N4DCM) {
+            group_list = read_numa4_dicom(file_list[ifile], max_group);
+        }
+        else if (G.file_type == IMA) {
+            group_list = siemens_to_dicom(file_list[ifile], max_group);
+        }
+       
+        if (group_list == NULL) {
+            fprintf(stderr, "Error parsing file '%s' during 2nd pass.\n",
+                    file_list[ifile]);
+            exit(-1);
+        }
+
+        /* initialize big and small images, if mosaic
+         */
+        if (n_slices_in_file > 1) {
+            mosaic_init(group_list, &mi, TRUE);
+        }
+
+        /* loop over subimages in mosaic
+         */
+        for (subimage = 0; subimage < n_slices_in_file; subimage++) {
+
+            /* Modify the group list for this image if mosaic
+             */
+            if (n_slices_in_file > 1) {
+                mosaic_modify_group_list(group_list, &mi, 
+                                              subimage, TRUE);
+            }
+       
+            /* Get image
+             */
+            get_siemens_dicom_image(group_list, &image);
+       
+            /* Save the image and any other information
+             */
+            save_minc_image(icvid, &gi, &fi_ptr[iimage], &image);
+
+            /* increment image counter
+             */
+            iimage++;
+        }
+     
+        /* Delete the group list
+         */
+        acr_delete_group_list(group_list);
+
+        /* cleanup mosaic struct if used
+         */
+        if (n_slices_in_file > 1) {
+            mosaic_cleanup(group_list, &mi);
+        }
+     
+        /* Free the image data */
+        if ((image.data != NULL) && (image.free)) {
+            free(image.data);
+        }
+    }
+
+    /* Close the output file */
+    close_minc_file(icvid);
+
+    /* Free the gi and fi_ptr stuff */
+    free_info(&gi, fi_ptr, num_files);
+    free(fi_ptr);
+
+    return EXIT_SUCCESS;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : read_std_dicom
+   @INPUT      : filename - name of siemens Numaris 4 `dicom' file to read
+                 max_group - maximum group number to read
+   @OUTPUT     : (none)
+   @RETURNS    : group list read in from file
+   @DESCRIPTION: Routine to read in a group list from a file.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : December 18, 2001 (Rick Hoge)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+Acr_Group
+read_std_dicom(const char *filename, int max_group)
+{
+    FILE *fp;
+    Acr_File *afp;
+    Acr_Group group_list;
+    int status;
+
+    /* Open the file
+     */
+    fp = fopen(filename, "rb");
+    if (fp == NULL) {
+        return NULL;
+    }
+
+    /* Connect to input stream
+     */
+    afp = acr_file_initialize(fp, 0, acr_stdio_read);
+    if (afp == NULL) {
+        return NULL;
+    }
+
+    if (acr_test_dicom_file(afp) != ACR_OK) {
+        return NULL;
+    }
+
+    // Read in group list
+    status = acr_input_group_list(afp, &group_list, max_group);
+    if (status != ACR_END_OF_INPUT && status != ACR_OK) {
+        return NULL;
+    }
+
+    // Close the file
+    acr_file_free(afp);
+    fclose(fp);
+
+    return (group_list);
+}
+
+static Acr_Group 
+add_siemens_info(Acr_Group group_list)
+{
+    /* needed for group repair - some essential info
+     * only available in ascii dump of MrProt structure
+     */
+    Acr_Element protocol; 
+    Acr_Element element;
+    int mosaic_rows, mosaic_cols;
+    short subimage_size[4];
+    int subimage_rows, subimage_cols;
+    int num_slices, num_partitions;
+    int num_encodings;
+    int enc_ix;
+    string_t str_buf;
+    char *str_ptr;
+    int interpolation_flag;
+
+    /* now fix the group list to provide essential info
+     * via standard dicom elements
+     * (this lets the rest of the code be more reusable)
+
+     * Note that these parameters are mostly dimension lengths,
+     * and are not usually supplied in standard DICOM implementations.
+     * We could do without them, except that the use of mosaics for
+     * multi-slice data makes at least the number of slices necessary.
+     * For such elements, we will spoof our own `private' entries
+     * using Numaris 3.5 coordinates.  These should not be used elsewhere
+     * in the code unless there's no other way!  Basically things
+     * should be done as follows:
+
+     * 1) use actual element in public dicom group, if possible
+     * 2) if not, then get info from MrProt and insert as 
+     *    correct public dicom element
+     * 3) if no public element exists, use an SPI element (careful!)
+     * 4) if no SPI element exists, use and EXT element (careful!)
+     */
+
+    /* read in Protocol group */
+
+    protocol = acr_find_group_element(group_list, SPI_Protocol);
+    if (protocol == NULL) {
+        if (G.Debug >= HI_LOGGING) {
+            printf("No Siemens protocol structure found...\n");
+        }
+        return group_list;
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("Incorporating Siemens protocol structure...\n");
+    }
+
+    /* Add number of dynamic scans:
+     */
+    prot_find_string(protocol, "lRepetitions", str_buf);
+    acr_insert_numeric(&group_list, ACR_Acquisitions_in_series,
+                       atoi(str_buf) + 1);
+
+    /* add number of echoes:
+     */
+    prot_find_string(protocol, "lContrasts", str_buf);
+    acr_insert_numeric(&group_list, SPI_Number_of_echoes, atoi(str_buf));
+
+    /* Add receiving coil (for some reason this isn't in generic groups)
+     */
+    prot_find_string(protocol,
+                     "sCOIL_SELECT_MEAS.asList[0].sCoilElementID.tCoilID",
+                     str_buf);
+    acr_insert_string(&group_list, ACR_Receive_coil_name, str_buf);
+
+    /* add MrProt dump
+     */
+    str_ptr = dump_protocol_text(protocol);
+    acr_insert_string(&group_list, EXT_MrProt_dump, str_ptr);
+    free(str_ptr);
+
+    /* add number of slices: (called `Partitions' for 3D) */
+    prot_find_string(protocol, "sSliceArray.lSize", str_buf);
+    num_slices = atoi(str_buf);
+        
+    prot_find_string(protocol, "sKSpace.lPartitions", str_buf);
+    num_partitions = atoi(str_buf);
+
+    /* This is a hack based upon the observation that for at least some
+     * conversions, this value seems to give the true number of slices
+     * rather than the sKSpace.lPartitions value (bert)
+     */
+    prot_find_string(protocol, "sKSpace.lImagesPerSlab", str_buf);
+    if (str_buf[0] != '\0') {
+        int num_images_per_slab = atoi(str_buf);
+        if (num_images_per_slab > num_partitions) {
+            num_partitions = num_images_per_slab;
+        }
+    }
+    
+    /* NOTE:  for some reason, lPartitions > 1 even for 2D scans
+     * (e.g. EPI, scouts)
+     */
+    if (!strncmp(acr_find_string(group_list, ACR_MR_acquisition_type,""),
+                 "3D", 2)) {
+        /* Use partitions if 3D.
+         * (note that this gets more complicated if the 3D scan
+         *  is mosaiced - see below)
+         */
+        acr_insert_numeric(&group_list, SPI_Number_of_slices_nominal, 1);
+        acr_insert_numeric(&group_list, 
+                           SPI_Number_of_3D_raw_partitions_nominal, 
+                           num_partitions);
+    } 
+    else {
+        /* use slices for 2D
+         */
+        acr_insert_numeric(&group_list, SPI_Number_of_slices_nominal, 
+                           num_slices);
+        acr_insert_numeric(&group_list, 
+                           SPI_Number_of_3D_raw_partitions_nominal, 1);
+    }
+
+    str_ptr = acr_find_string(group_list, ACR_Image_type, "");
+    if (strstr(str_ptr, "MOSAIC") != NULL) {
+    /* Now figure out mosaic rows and columns, and put in EXT shadow group
+     * Check for interpolation - will require 2x scaling of rows and columns.
+     */
+    prot_find_string(protocol, "sKSpace.uc2DInterpolation", str_buf);
+    interpolation_flag = strtol(str_buf, NULL, 0);
+
+    /* Assign defaults in case something goes wrong below...
+     */
+    subimage_rows = 0;
+    subimage_cols = 0;
+
+    /* Compute mosaic rows and columns
+     * Here is a hack to handle non-square mosaiced images
+     *
+     * WARNING: as far as I can tell, the phase-encoding dir (row/col)
+     * is reversed for mosaic EPI scans (don't know if this is a
+     * mosaic thing, an EPI thing, or whatever).  
+     * Get the array of sizes: freq row/freq col/phase row/phase col
+     */
+
+    element = acr_find_group_element(group_list, ACR_Acquisition_matrix);
+    if (element == NULL) {
+        printf("WARNING: Can't find acquisition matrix\n");
+    }
+    else if (acr_get_element_short_array(element, 4, subimage_size) != 4) {
+        printf("WARNING: Can't read acquisition matrix\n");
+    }
+    else {
+        if (G.Debug >= HI_LOGGING) {
+            printf(" * Acquisition matrix %d %d %d %d\n",
+                   subimage_size[0],
+                   subimage_size[1],
+                   subimage_size[2],
+                   subimage_size[3]);
+        }
+        /* Get subimage dimensions, assuming the OPPOSITE of the
+         * reported phase-encode direction!!
+         */
+        str_ptr = acr_find_string(group_list, ACR_Phase_encoding_direction,"");
+        if (!strncmp(str_ptr, "COL", 3)) {
+            subimage_rows = subimage_size[3];
+            subimage_cols = subimage_size[0];
+        }
+        else if (!strncmp(str_ptr, "ROW", 3)) {
+            subimage_rows = subimage_size[2];
+            subimage_cols = subimage_size[1];
+        }
+        else {
+            printf("WARNING: Unknown phase encoding direction '%s'\n",
+                   str_ptr);
+        }
+
+        /* If interpolation, multiply rows and columns by 2 */
+        if (interpolation_flag) {
+            subimage_rows *= 2;
+            subimage_cols *= 2;
+        }
+    }
+
+    /* If these are not set or still zero, assume this is NOT a mosaic
+     * format file.
+     */
+    if (subimage_rows == 0 || subimage_cols == 0) {
+        subimage_rows = acr_find_int(group_list, ACR_Rows, 1);
+        subimage_cols = acr_find_int(group_list, ACR_Columns, 1);
+        mosaic_rows = 1;
+        mosaic_cols = 1;
+    }
+    else {
+        if (G.Debug >= HI_LOGGING) {
+            printf("Assuming MOSAIC, %dx%d\n", 
+                   subimage_rows, subimage_cols);
+        }
+        mosaic_rows = acr_find_int(group_list, ACR_Rows, 1) / subimage_rows;
+        mosaic_cols = acr_find_int(group_list, ACR_Columns, 1) / subimage_cols;
+    }
+
+    acr_insert_numeric(&group_list, EXT_Mosaic_rows, mosaic_rows);
+    acr_insert_numeric(&group_list, EXT_Mosaic_columns, mosaic_cols);
+
+    if (mosaic_rows * mosaic_cols > 1) {
+
+        str_ptr = acr_find_string(group_list, ACR_MR_acquisition_type, "");
+             
+        /* assume any mosaiced file contains all slices
+         * (we now support mosaics for 2D and 3D acquisitions,
+         *  so we may need to use partitions instead of slices)
+         */
+
+        if (!strncmp(str_ptr, "2D", 2)) {
+            acr_insert_numeric(&group_list, EXT_Slices_in_file, num_slices);
+            acr_insert_numeric(&group_list, 
+                               SPI_Number_of_slices_nominal, num_slices);
+        } 
+
+        /* if 3D mosaiced scan, write number of partitions to number of 
+         * slices in dicom group 
+         */
+        else if (!strncmp(str_ptr, "3D", 2)) {
+            acr_insert_numeric(&group_list, EXT_Slices_in_file, 
+                               num_partitions);
+            acr_insert_numeric(&group_list, SPI_Number_of_slices_nominal, 
+                               num_partitions);
+            /* also have to provide slice spacing - in case of 3D it's same
+             * as slice thickness (and not provided in dicom header!)
+             */
+            acr_insert_numeric(&group_list, ACR_Spacing_between_slices,
+                               acr_find_double(group_list, 
+                                               ACR_Slice_thickness, 1.0));
+        }
+    } 
+    else {
+        acr_insert_numeric(&group_list, EXT_Slices_in_file, 1);
+    }
+
+    /* Correct the rows and columns values -
+     * These will reflect those of the subimages in the mosaics
+     * NOT the total image dimensions
+     */
+    acr_insert_short(&group_list, EXT_Sub_image_columns, subimage_cols);
+    acr_insert_short(&group_list, EXT_Sub_image_rows, subimage_rows);
+
+    /* should also correct the image position here? */
+    }
+
+    /* correct dynamic scan info if diffusion scan:
+     *
+     * assumptions:
+     *
+     *  - diffusion protocol indicated by sDiffusion.ucMode = 0x4
+     *  - there are 7 shots for DTI (b=0 + 6 encodings)
+     *  - b=0 scan has sequence name "ep_b0"
+     *  - encoded scans have seq names "ep_b700#1, ep_b700#2, ..." etc.
+     *
+     * actions:
+     * 
+     *  - change number of dynamic scans to 7
+     *  - modify dynamic scan index to encoding index
+     */
+    prot_find_string(protocol, "sDiffusion.ucMode", str_buf);
+    if (!strcmp(str_buf, "0x4")) {
+
+        /* try to get b value */
+        prot_find_string(protocol, "sDiffusion.alBValue[1]", str_buf);
+        acr_insert_numeric(&group_list, EXT_Diffusion_b_value,
+                           atoi(str_buf));
+
+        /* if all averages in one series: */
+        prot_find_string(protocol, "ucOneSeriesForAllMeas", str_buf);
+        if (!strcmp(str_buf, "0x1")) {
+
+            num_encodings = 7; /* for now assume 7 shots in diffusion scan */
+
+            /* number of 'time points' */
+            acr_insert_numeric(&group_list, ACR_Acquisitions_in_series, 
+                               num_encodings*
+                               acr_find_double(group_list,
+                                               ACR_Nr_of_averages, 1));
+
+            /* time index of current scan: */
+                
+            /* In the current scheme, the unencoded scan has a
+             * sequence name like "ep_b0" while the subsequent six
+             * diffusion encodings have names like "ep_b700#1" we
+             * could use this to come up with indices for an encoding
+             * dimension
+             */
+            str_ptr = strstr(acr_find_string(group_list,
+                                             ACR_Sequence_name,""), "#");
+            if (str_ptr == NULL) {
+                enc_ix = 0;
+            } 
+            else {
+                enc_ix = atoi(str_ptr + sizeof(char));
+            }
+                
+            /* however with the current sequence, we get usable
+             * time indices from floor(global_image_num/num_slices)
+             */
+            acr_insert_numeric(&group_list, ACR_Acquisition, 
+                               (acr_find_int(group_list, ACR_Image, 1)-1) / 
+                               num_slices);
+
+        } 
+        else { /* averages in different series - no special handling needed? */
+
+            num_encodings = 7; /* for now assume 7 shots in diffusion scan */
+
+            /* number of 'time points' */
+            acr_insert_numeric(&group_list, ACR_Acquisitions_in_series,
+                               num_encodings);
+                
+            /* For multi-series scans, we DO USE THIS BECAUSE global
+             * image number may be broken!!
+             */
+            str_ptr = strstr(acr_find_string(group_list,
+                                             ACR_Sequence_name, ""), "#");
+            if (str_ptr == NULL) {
+                enc_ix = 0;
+            } 
+            else {
+                enc_ix = atoi(str_ptr + sizeof(char));
+            }
+            acr_insert_numeric(&group_list, ACR_Acquisition, enc_ix);
+        }
+    } // end of diffusion scan handling
+    return (group_list);
+}
+
+#define PMS_SET_CREATOR(el, cr) \
+     (el)->element_id = ((el)->element_id & 0xff) + ((cr)->element_id << 8)
+
+static Acr_Group
+add_philips_info(Acr_Group group_list)
+{
+    struct Acr_Element_Id creator_id;
+    Acr_Group pms_group;
+    Acr_Element pms_element;
+    Acr_Element pms_element_list;
+    char *str_ptr;
+    int slice_count;
+    int slice_index;
+
+    /* To use the Philips proprietary group, we have to figure out the
+     * DICOM private creator ID in use.  The group ID is always 0x2001,
+     * but the upper eight bits of the element ID are somewhat variable.
+     * To tell what they are, we have to search through the element ID's
+     * from 0x0001-0x00ff and find one that contains the text
+     * "PHILIPS IMAGING DD 001" or "Philips Imaging DD 001".  The value
+     * of this element is then used for the upper eight bits of all
+     * subsequent Philips private element ID's.
+     */
+    pms_group = acr_find_group(group_list, PMS_PRIVATE_GROUP_ID);
+    if (pms_group != NULL) {
+        pms_element_list = acr_get_group_element_list(pms_group);
+        creator_id.group_id = PMS_PRIVATE_GROUP_ID;
+        creator_id.vr_code = ACR_VR_LO;
+        for (creator_id.element_id = 0x0001; 
+             creator_id.element_id <= 0x00ff; 
+             creator_id.element_id++) {
+            pms_element = acr_find_element_id(pms_element_list, &creator_id);
+            if (pms_element != NULL) {
+                str_ptr = acr_get_element_string(pms_element);
+                if (str_ptr != NULL && 
+                    (!strcmp(str_ptr, "Philips Imaging DD 001") ||
+                     !strcmp(str_ptr, "PHILIPS IMAGING DD 001"))) {
+                    /* Found it!!! */
+                    break;
+                }
+            }
+        }
+    }
+    if (creator_id.element_id > 0xff) {
+        printf("WARNING: Can't find Philips private creator ID.\n");
+    }
+    else {
+        if (G.Debug >= HI_LOGGING) {
+            printf("Found Philips private creator ID at %#x\n", 
+                   creator_id.element_id);
+        }
+
+        PMS_SET_CREATOR(PMS_Number_of_Slices_MR, &creator_id);
+        slice_count = acr_find_int(group_list, PMS_Number_of_Slices_MR, -1);
+        if (slice_count < 0) {
+            printf("WARNING: Can't find Philips slice count\n");
+        }
+        else {
+            acr_insert_short(&group_list, ACR_Images_in_acquisition, 
+                             slice_count);
+        }
+        PMS_SET_CREATOR(PMS_Slice_Number_MR, &creator_id);
+        slice_index = acr_find_int(group_list, PMS_Slice_Number_MR, -1);
+        if (slice_index < 0) {
+            printf("WARNING: Can't find Philips slice index\n");
+        }
+        else {
+            /* TODO: It is really quite gross that we have to resort to
+             * using a Siemens-proprietary field to tell the rest of the
+             * code which slice we are on.  But such is life, for now...
+             */
+            acr_insert_numeric(&group_list, SPI_Current_slice_number,
+                               (double) slice_index);
+        }
+    }
+    return (group_list);
+}
+
+Acr_Group
+add_gems_info(Acr_Group group_list)
+{
+    char *tmp_str;
+    int image_count;
+    int image_index;
+    double tr;
+    int ok;
+
+    ok = 1;
+    tmp_str = acr_find_string(group_list, GEMS_Acqu_private_creator_id, "");
+    if (strcmp(tmp_str, "GEMS_ACQU_01")) {
+        ok = 0;
+    }
+
+    tmp_str = acr_find_string(group_list, GEMS_Sers_private_creator_id, "");
+    if (strcmp(tmp_str, "GEMS_SERS_01")) {
+        ok = 0;
+    }
+
+    if (!ok) {
+        /* Warn only for non-PET things.  We know the PET scanner doesn't
+         * rely on this proprietary nonsense.
+         */
+        tmp_str = acr_find_string(group_list, ACR_Modality, "");
+        if (strcmp(tmp_str, "PT") && G.Debug) {
+            printf("WARNING: GEMS data not found\n");
+        }
+    }
+
+    tmp_str = acr_find_string(group_list, ACR_Image_type, "");
+    image_index = acr_find_int(group_list, ACR_Image, -1);
+    image_count = acr_find_int(group_list, GEMS_Images_in_series, -1);
+    tr = acr_find_double(group_list, ACR_Repetition_time, 0.0);
+
+    /* If we found a valid image count in the proprietary field, copy it
+     * into the standard field if the standard field is not already set.
+     */
+    if (image_count > 0 &&
+        acr_find_int(group_list, ACR_Images_in_acquisition, -1) < 0) {
+        acr_insert_long(&group_list, ACR_Images_in_acquisition, image_count);
+    }
+
+    /* Do this only for EPI images for now 
+     */
+    if (strstr(tmp_str, "\\EPI") != NULL &&
+        image_index >= 0 &&
+        image_count > 0 &&
+        tr != 0.0) {
+        int frame_count = acr_find_int(group_list, 
+                                       GEMS_Fast_phases, -1);
+        if (frame_count > 0) {
+            if (acr_find_int(group_list, ACR_Acquisitions_in_series, -1) < 0) {
+                acr_insert_long(&group_list, ACR_Acquisitions_in_series,
+                                frame_count);
+            }
+        }
+
+        if (acr_find_double(group_list, ACR_Frame_reference_time, -1.0) < 0) {
+            acr_insert_numeric(&group_list, ACR_Frame_reference_time,
+                               ((image_index - 1) / image_count) * tr);
+        }
+        if (acr_find_double(group_list, ACR_Actual_frame_duration, -1.0) < 0) {
+            acr_insert_numeric(&group_list, ACR_Actual_frame_duration,
+                               tr);
+        }
+
+        if (G.Debug >= HI_LOGGING) {
+            printf("EPI slice %d timing information: %f, %f\n", 
+                   image_index, ((image_index - 1) / image_count) * tr,
+                   tr);
+        }
+    }
+    return (group_list);
+}
+
+
+Acr_Group 
+copy_spi_to_acr(Acr_Group group_list)
+{
+    int itemp;
+    double dtemp;
+
+    itemp = acr_find_int(group_list, SPI_Number_of_slices_nominal, 0);
+    if (itemp != 0) {
+        acr_insert_numeric(&group_list, ACR_Images_in_acquisition, itemp);
+    }
+
+    itemp = acr_find_int(group_list, SPI_Number_of_echoes, 0);
+    if (itemp != 0) {
+        acr_insert_numeric(&group_list, ACR_Echo_train_length, itemp);
+    }
+
+    dtemp = acr_find_double(group_list, SPI_Magnetic_field_strength, 0);
+    if (dtemp != 0.0) {
+        acr_insert_numeric(&group_list, ACR_Magnetic_field_strength, dtemp);
+    }
+    return (group_list);
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : read_numa4_dicom
+   @INPUT      : filename - read a standard DICOM file
+   max_group - maximum group number to read
+   @OUTPUT     : (none)
+   @RETURNS    : group list read in from file
+   @DESCRIPTION: Routine to read in a group list from a file.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : December 18, 2001 (Rick Hoge)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+Acr_Group
+read_numa4_dicom(const char *filename, int max_group)
+{
+    Acr_Group group_list;
+    char *str_ptr;
+
+    group_list = read_std_dicom(filename, max_group);
+    if (group_list == NULL) {
+        return NULL;
+    }
+
+    /* Check the manufacturer.  If it is one we know, try to interpret
+     * the private/proprietary data if present.  This is converted to
+     * standard DICOM fields whereever it makes sense to do so.
+     */
+    str_ptr = acr_find_string(group_list, ACR_Manufacturer, "");
+    if (strstr(str_ptr, "SIEMENS") != NULL ||
+        strstr(str_ptr, "Siemens") != NULL) {
+
+        group_list = add_siemens_info(group_list);
+
+        /* Now copy proprietary fields into the correct places in the 
+         * standard groups.
+         */
+        group_list = copy_spi_to_acr(group_list);
+
+    }
+    else if (strstr(str_ptr, "Philips") != NULL) {
+        group_list = add_philips_info(group_list);
+    }
+    else if (strstr(str_ptr, "GEMS") != NULL ||
+             strstr(str_ptr, "GE MEDICAL") != NULL) {
+        group_list = add_gems_info(group_list);
+    }
+    return (group_list);
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : free_info
+   @INPUT      : gi_ptr
+   fi_ptr
+   num_files
+   @OUTPUT     : (none)
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to free contents of general and file info structures.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : November 26, 1993 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+
+static void
+free_info(General_Info *gi_ptr, File_Info *fi_ptr, int num_files)
+{
+    Mri_Index imri;
+
+    /* Free the general info pointers */
+    for (imri = 0; imri < MRI_NDIMS; imri++) {
+        if (gi_ptr->indices[imri] != NULL) {
+            free(gi_ptr->indices[imri]);
+        }
+        if (gi_ptr->coordinates[imri] != NULL) {
+            free(gi_ptr->coordinates[imri]);
+        }
+        if (gi_ptr->widths[imri] != NULL) {
+            free(gi_ptr->widths[imri]);
+        }
+    }
+
+    /* Free the group list */
+    if (gi_ptr->group_list != NULL) {
+        acr_delete_group_list(gi_ptr->group_list);
+    }
+
+    return;
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : search_list
+   @INPUT      : value
+   list_ptr
+   list_length
+   start_index - point from which search should start
+   @OUTPUT     : (none)
+   @RETURNS    : Index in list where value is found, or -1 is value not found.
+   @DESCRIPTION: Routine to search a list for a value, returning the index
+   into the list. If the value is not found, then -1 is returned.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+int
+search_list(int value, const int *list_ptr, int list_length, int start_index)
+{
+    int index;
+
+    /* If nothing on list, just return. */
+    if (list_length <= 0) {
+        return (-1);
+    }
+
+    /* If starting point is invalid, start at zero.
+     */
+    if ((start_index >= list_length) || (start_index < 0)) {
+        start_index = 0;
+    }
+
+    /* Loop over indices, wrapping at the end of the list */
+    index = start_index;
+    do {
+        if (list_ptr[index] == value) {
+            return index;       /* Found it. */
+        }
+        index++;
+        if (index >= list_length) {
+            index = 0;
+        }
+    } while (index != start_index);
+
+    return -1;                  /* Search failed. */
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : sort_dimensions
+   @INPUT      : gi_ptr
+   @OUTPUT     : gi_ptr
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to sort the MRI dimensions according to their 
+   coordinates. It also fills in the step and start values for 
+   the SLICE dimension.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static void
+sort_dimensions(General_Info *gi_ptr)
+{
+    Mri_Index imri;
+    Sort_Element *sort_array;
+    int nvalues;
+    int i;
+
+    /* Sort the dimensions, if needed.
+     */
+    for (imri = 0; imri < MRI_NDIMS; imri++) {
+        /* Sort each dimension iff the size is greater than 1 and it is not
+         * a time dimension in an N4 mosaic.
+         */
+        if (gi_ptr->cur_size[imri] <= 1 ||
+            /* Don't sort on time for N4 mosaics (TODO: Why not??)
+             */
+            ((G.file_type == N4DCM) &&
+             (imri == TIME) && 
+             (gi_ptr->num_slices_in_file > 1))) {
+            if (G.Debug >= HI_LOGGING) {
+                printf("Not sorting %s dimension\n", Mri_Names[imri]);
+            }
+            continue;
+        }
+            
+        if (G.Debug >= HI_LOGGING) {
+            printf("Sorting %s dimension\n", Mri_Names[imri]);
+        }
+
+        /* Set up the array for sorting.
+         */
+        nvalues = gi_ptr->cur_size[imri];
+        sort_array = malloc(nvalues * sizeof(*sort_array));
+        CHKMEM(sort_array);
+        for (i = 0; i < nvalues; i++) {
+            sort_array[i].identifier = gi_ptr->indices[imri][i];
+            sort_array[i].original_index = i;
+            sort_array[i].value = gi_ptr->coordinates[imri][i];
+            sort_array[i].width = gi_ptr->widths[imri][i];
+        }
+
+        /* Sort the array.
+         */
+        qsort((void *) sort_array, (size_t) nvalues, sizeof(*sort_array), 
+              dimension_sort_function);
+
+        /* Copy the information back into the appropriate arrays 
+         */
+        for (i = 0; i < nvalues; i++) {
+            gi_ptr->indices[imri][i] = sort_array[i].identifier;
+            gi_ptr->coordinates[imri][i] = sort_array[i].value;
+            gi_ptr->widths[imri][i] = sort_array[i].width;
+        }
+
+        if (G.Debug >= HI_LOGGING) {
+            /* Print out all of the information about this dimension.
+             */
+            printf(" nvalues %d min %f max %f\n",
+                   nvalues, 
+                   gi_ptr->coordinates[imri][0],
+                   gi_ptr->coordinates[imri][nvalues - 1]);
+            for (i = 0; i < nvalues; i++) {
+                printf("%3d %6d %8.3f\n", 
+                       i,
+                       gi_ptr->indices[imri][i],
+                       gi_ptr->coordinates[imri][i]);
+            }
+        }
+        
+        /* Free the temporary array we used to sort the coordinate axis.
+         */
+        free(sort_array);
+
+        /* Now verify that the slice coordinate array looks sane.  We
+         * don't complain about things like missing time slices, since
+         * many PET scanners produce irregular timings.
+         */
+        if (nvalues >= 2 && imri == SLICE) {
+            double delta = (gi_ptr->coordinates[imri][1] - 
+                            gi_ptr->coordinates[imri][0]);
+
+            for (i = 1; i < nvalues; i++) {
+                if (!fcmp(delta, 
+                          (gi_ptr->coordinates[imri][i] - 
+                           gi_ptr->coordinates[imri][i - 1]),
+                          1.0e-3)) {
+                    printf("WARNING: Missing data for %s dimension\n",
+                           Mri_Names[imri]);
+                    printf("   slice # %d %.12f %.12f\n",
+                           i, 
+                           delta,
+                           (gi_ptr->coordinates[imri][i] -
+                            gi_ptr->coordinates[imri][i - 1]));
+                }
+            }
+        }
+
+        /* Update slice step and start.
+         */
+        if (imri == SLICE) {
+            if (gi_ptr->coordinates[imri][0] != 
+                gi_ptr->coordinates[imri][nvalues-1]) {
+                double dbl_tmp1;
+                double dbl_tmp2;
+
+                dbl_tmp1 = gi_ptr->step[gi_ptr->slice_world];
+                dbl_tmp2 = (gi_ptr->coordinates[imri][nvalues - 1] -
+                            gi_ptr->coordinates[imri][0]) / 
+                    ((double) gi_ptr->cur_size[imri] - 1.0);
+
+                /* OK, so now we have to figure out who wins the great
+                 * battle to become the slice step value.  If the value
+                 * we have been assuming up until now is the same as the
+                 * calculated value with only a sign change, or if the
+                 * assumed value is the default (1.0), we adopt the 
+                 * calculated value.
+                 */
+                if (!fcmp(dbl_tmp1, dbl_tmp2, 2.0e-5)) {
+                    printf("WARNING: calculated slice width (%.10f) disagrees with file's slice width (%.10f)\n", dbl_tmp2, dbl_tmp1);
+                    if (dbl_tmp1 == 1.0) {
+                        gi_ptr->step[gi_ptr->slice_world] = dbl_tmp2;
+                    }
+                }
+                
+            }
+            gi_ptr->start[gi_ptr->slice_world] = gi_ptr->coordinates[imri][0];
+            if (G.Debug >= HI_LOGGING) {
+                printf("Set slice %d step to %f, start to %f\n",
+                       gi_ptr->slice_world,
+                       gi_ptr->step[gi_ptr->slice_world],
+                       gi_ptr->start[gi_ptr->slice_world]);
+            }
+        } /* If slice dimension */
+    } /* for all mri dimensions */
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : dimension_sort_function
+   @INPUT      : v1, v2 - values to compare
+   @OUTPUT     : (none)
+   @RETURNS    : -1, 0 or 1 if v1 < v2, v1 == v2 or v1 > v2
+   @DESCRIPTION: Function to compare to array elements for sorting. Elements are
+   compared first on value, then on their original array index
+   (this tries to preserve the original sequence).
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : February 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   ---------------------------------------------------------------------------- */
+static int
+dimension_sort_function(const void *v1, const void *v2)
+{
+    Sort_Element *value1, *value2;
+
+    value1 = (Sort_Element *) v1;
+    value2 = (Sort_Element *) v2;
+
+    if (value1->value < value2->value)
+        return -1;
+    else if (value1->value > value2->value)
+        return 1;
+    else if (value1->original_index < value2->original_index)
+        return -1;
+    else if (value1->original_index > value2->original_index)
+        return 1;
+    else
+        return 0;
+}
+
+int
+prot_find_string(Acr_Element elem_ptr, const char *name_str, char *value)
+{
+    static const char prot_head[] = "### ASCCONV BEGIN ###";
+    long cur_offset;
+    long max_offset;
+    char *field_ptr;
+    int  ix1, ix2;
+
+    max_offset = elem_ptr->data_length - sizeof(prot_head);
+
+    // Scan through the element containing the protocol, to find the 
+    // ASCII dump of the MrProt structure.
+    //
+    for (cur_offset = 0; cur_offset < max_offset; cur_offset++) {
+        if (!memcmp(elem_ptr->data_pointer + cur_offset,
+                    prot_head, sizeof(prot_head) - 1)) {
+            break;
+        }
+    }
+
+    /* bail if we didn't find the protocol
+     */
+    if (cur_offset == max_offset) {
+        return (0);
+    }
+
+    field_ptr = strstr(elem_ptr->data_pointer + cur_offset, name_str);
+    if (field_ptr != NULL) {
+        sscanf(field_ptr, "%*s %*s %s", value);
+        ix1 = 0;
+        for (ix2 = 0; value[ix2] != '\0'; ix2++) {
+            if (value[ix2] != '"') {
+                value[ix1++] = value[ix2];
+            }
+        }
+    } 
+    else {
+        strcpy(value, "0");
+    }
+    return (1);
+}
+
+static char *
+dump_protocol_text(Acr_Element elem_ptr)
+{
+    const char prot_head[] = "### ASCCONV BEGIN ###";
+    const char prot_tail[] = "### ASCCONV END ###";
+    char *output = malloc(elem_ptr->data_length);
+    int prot_found = FALSE;
+    long cur_offset;
+    long max_offset;
+
+    CHKMEM(output);
+
+    // scan throught the group containing the protocol, to find the 
+    // ascii dump of the MrProt structure
+    max_offset = elem_ptr->data_length - sizeof (prot_head);
+
+    for (cur_offset = 0; cur_offset < max_offset; cur_offset++) {
+        if (!memcmp(elem_ptr->data_pointer + cur_offset,
+                    prot_head, sizeof(prot_head) - 1)) {
+            prot_found = TRUE;
+            break;
+        }
+    }
+
+    if (prot_found) {
+        int ix1 = 0;
+        char *tmp_ptr = elem_ptr->data_pointer + cur_offset;
+
+        for ( ; cur_offset < max_offset; cur_offset++) {
+            if (!memcmp(tmp_ptr, prot_tail, sizeof(prot_tail) - 1)) {
+                break;      
+            }
+            if (*tmp_ptr != '"') {
+                output[ix1++] = *tmp_ptr;
+            }
+            tmp_ptr++;
+        }
+        output[ix1] = '\0';
+    }
+    return (output);
+}
+
+static int 
+mosaic_init(Acr_Group group_list, Mosaic_Info *mi_ptr, int load_image)
+{
+    int group_id, element_id;
+    int grid_size;
+    long new_image_size;
+    void *data;
+    Acr_Element element;
+    int i;
+    double pixel_spacing[2];
+    double separation;
+    double RowColVec[6];
+    double dircos[VOL_NDIMS][WORLD_NDIMS];
+    char *str_tmp;
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("mosaic_init(%lx, %lx, %d)\n",
+               (unsigned long) group_list, (unsigned long) mi_ptr,
+               load_image);
+    }
+
+    str_tmp = acr_find_string(group_list, SPI_Order_of_slices, "");
+    if (!strncmp(str_tmp, "INTERLEAVED", 11)) {
+        mi_ptr->mosaic_seq = MOSAIC_SEQ_INTERLEAVED;
+    }
+    else if (!strncmp(str_tmp, "ASCENDING", 9)) {
+        mi_ptr->mosaic_seq = MOSAIC_SEQ_ASCENDING;
+    }
+    else if (!strncmp(str_tmp, "DESCENDING", 10)) {
+        mi_ptr->mosaic_seq = MOSAIC_SEQ_DESCENDING;
+    }
+    else {
+        mi_ptr->mosaic_seq = G.mosaic_seq;
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" ordering is %s\n", str_tmp);
+    }
+
+    /* Get some basic image information.
+     * big[0/1] is number of columns/rows in whole mosaic.
+     */
+    mi_ptr->big[0] = acr_find_int(group_list, ACR_Columns, 1);
+    mi_ptr->big[1] = acr_find_int(group_list, ACR_Rows, 1);
+    mi_ptr->pixel_size = 
+        (acr_find_int(group_list, ACR_Bits_allocated, 16) - 1) / 8 + 1;
+
+    /* Get the image size
+     * (size[0/1] is number of columns/rows in a single slice)
+     */
+    mi_ptr->size[0] = acr_find_short(group_list, EXT_Sub_image_columns, 1);
+    mi_ptr->size[1] = acr_find_short(group_list, EXT_Sub_image_rows, 1);
+
+    // Get the grid shape, checking that it is not too big if specified
+    mi_ptr->grid[0] = mi_ptr->big[0] / mi_ptr->size[0];
+    mi_ptr->grid[1] = mi_ptr->big[1] / mi_ptr->size[1];
+    if ((mi_ptr->grid[0] < 1) || (mi_ptr->grid[0] < 1)) {
+        fprintf(stderr, "Grid too small: %d x %d\n",
+                mi_ptr->grid[0], mi_ptr->grid[1]);
+        exit(EXIT_FAILURE);
+    }
+
+    // Check whether we need to do anything (1x1 grid may be the whole image)
+    grid_size = mi_ptr->grid[0] * mi_ptr->grid[1];
+    if ((grid_size == 1) &&
+        (mi_ptr->size[0] == mi_ptr->big[0]) &&
+        (mi_ptr->size[1] == mi_ptr->big[1])) {
+        /* had to remove this as now ANY images acquired with 
+           the mosaic sequence need special treatment */
+        mi_ptr->packed = FALSE;
+        return 1;
+    }
+
+    /* Update the number of image rows and columns
+     */
+    acr_insert_short(&group_list, ACR_Rows, mi_ptr->size[1]);
+    acr_insert_short(&group_list, ACR_Columns, mi_ptr->size[0]);
+
+    /* Get image image index info (number of slices in file)
+     */
+    mi_ptr->slice_count = acr_find_int(group_list, EXT_Slices_in_file, 1);
+
+    /* sub_images is now just the number of mosaic elements, even if
+     * they don't all contain slices 
+     */
+    mi_ptr->sub_images = mi_ptr->grid[0] * mi_ptr->grid[1];
+
+
+    /* get the pixel size
+     */
+    element = acr_find_group_element(group_list, ACR_Pixel_size);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, 2, pixel_spacing) != 2)) {
+        if (G.Debug) {
+            printf("WARNING: Can't get pixel size element\n");
+        }
+    }
+
+    /* Get step between slices
+     */
+    separation = acr_find_double(group_list, ACR_Slice_thickness, 0.0);
+    if (separation == 0.0) {
+        separation = acr_find_double(group_list, ACR_Spacing_between_slices, 
+                                     1.0);
+    }
+
+    /* get image normal vector
+     * (need to compute based on dicom field, which gives
+     *  unit vectors for row and column direction)
+     * TODO: This code (and other code in this function) could probably
+     * be broken out and made redundant with other code in the converter.
+     */
+    element = acr_find_group_element(group_list, ACR_Image_orientation_patient);
+    if (element != NULL) {
+        acr_get_element_numeric_array(element, WORLD_NDIMS * 2, RowColVec);
+   
+        memcpy(dircos[VCOLUMN], RowColVec, sizeof(RowColVec[0]) * WORLD_NDIMS);
+        memcpy(dircos[VROW], &RowColVec[3], sizeof(RowColVec[0]) * WORLD_NDIMS);
+   
+        /* compute slice normal as cross product of row/column unit vectors
+         * (should check for unit length?)
+         */
+        mi_ptr->normal[XCOORD] = 
+            dircos[VCOLUMN][YCOORD] * dircos[VROW][ZCOORD] -
+            dircos[VCOLUMN][ZCOORD] * dircos[VROW][YCOORD];
+   
+        mi_ptr->normal[YCOORD] = 
+            dircos[VCOLUMN][ZCOORD] * dircos[VROW][XCOORD] -
+            dircos[VCOLUMN][XCOORD] * dircos[VROW][ZCOORD];
+   
+        mi_ptr->normal[ZCOORD] = 
+            dircos[VCOLUMN][XCOORD] * dircos[VROW][YCOORD] -
+            dircos[VCOLUMN][YCOORD] * dircos[VROW][XCOORD];
+    }
+    else {
+        if (G.Debug) {
+            printf("WARNING: No image orientation found\n");
+        }
+    }
+
+    /* compute slice-to-slice step vector
+     */
+    for (i = 0; i < WORLD_NDIMS; i++) {
+        mi_ptr->step[i] = separation * mi_ptr->normal[i];
+    }
+
+    /* Get position and correct to first slice
+     */
+    element = acr_find_group_element(group_list, ACR_Image_position_patient);
+    if (element == NULL) {
+        element = acr_find_group_element(group_list, 
+                                         ACR_Image_position_patient_old);
+    }
+    if (element != NULL) {
+        acr_get_element_numeric_array(element, WORLD_NDIMS, 
+                                      mi_ptr->position);
+    }
+    else {
+        if (G.Debug) {
+            printf("WARNING: No image position found\n");
+        }
+        mi_ptr->position[XCOORD] = mi_ptr->position[YCOORD] = 
+            mi_ptr->position[ZCOORD] = 0.0;
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" step %.3f %.3f %.3f position %.3f %.3f %.3f\n",
+               mi_ptr->step[0],
+               mi_ptr->step[1],
+               mi_ptr->step[2],
+               mi_ptr->position[0],
+               mi_ptr->position[1],
+               mi_ptr->position[2]);
+    }
+
+    if (mi_ptr->mosaic_seq != MOSAIC_SEQ_INTERLEAVED) {
+        /* Numaris 4 mosaic correction:
+         * - position given is edge of huge slice constructed as if 
+         *   real slice was at center of mosaic
+         * - mi_ptr->big[0,1] are number of columns and rows of mosaic
+         * - mi_ptr->size[0,1] are number of columns and rows of sub-image
+         */
+
+        for (i = 0; i < WORLD_NDIMS; i++) {
+            /* Correct offset from mosaic Center
+             */
+            mi_ptr->position[i] += (double)
+                ((dircos[VCOLUMN][i] * mi_ptr->big[0] * pixel_spacing[0]/2.0) +
+                 (dircos[VROW][i] * mi_ptr->big[1] * pixel_spacing[1]/2));
+            
+            /* Move from center to corner of slice
+             */
+            mi_ptr->position[i] -= 
+                ((dircos[VCOLUMN][i] * mi_ptr->size[0] * pixel_spacing[0]/2.0) +
+                 (dircos[VROW][i] * mi_ptr->size[1] * pixel_spacing[1]/2.0));
+        }
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" corrected position %.3f %.3f %.3f\n",
+               mi_ptr->position[0],
+               mi_ptr->position[1],
+               mi_ptr->position[2]);
+    }
+
+    if (load_image) {
+
+        /* Steal the image element from the group list
+         */
+        mi_ptr->big_image = acr_find_group_element(group_list, ACR_Pixel_data);
+        if (mi_ptr->big_image == NULL) {
+            fprintf(stderr, "Couldn't find an image\n");
+            exit(EXIT_FAILURE);
+        }
+        group_id = acr_get_element_group(mi_ptr->big_image);
+        element_id = acr_get_element_element(mi_ptr->big_image);
+        acr_group_steal_element(acr_find_group(group_list, group_id),
+                                mi_ptr->big_image);
+        
+        /* Add a small image
+         */
+        new_image_size = 
+            mi_ptr->size[0] * mi_ptr->size[1] * mi_ptr->pixel_size;
+        data = malloc(new_image_size);
+        CHKMEM(data);
+        mi_ptr->small_image = acr_create_element(group_id, element_id,
+                                                 acr_get_element_vr(mi_ptr->big_image),
+                                                 new_image_size, data);
+        acr_set_element_vr(mi_ptr->small_image,
+                           acr_get_element_vr(mi_ptr->big_image));
+        acr_set_element_byte_order(mi_ptr->small_image,
+                                   acr_get_element_byte_order(mi_ptr->big_image));
+        acr_set_element_vr_encoding(mi_ptr->small_image,
+                                    acr_get_element_vr_encoding(mi_ptr->big_image));
+        acr_insert_element_into_group_list(&group_list, mi_ptr->small_image);
+    }
+
+    /* Return number of sub-images in this image */
+    return mi_ptr->sub_images;
+}
+
+static int 
+mosaic_modify_group_list(Acr_Group group_list, Mosaic_Info *mi_ptr,
+                         int iimage, int load_image)
+{
+    int irow;
+    int idim;
+    int nbyte;
+    int isub;
+    int jsub;
+    char *new;
+    char *old;
+    long old_offset;
+    long new_offset;
+    double position[WORLD_NDIMS];
+    string_t string;
+    int islice;
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("mosaic_modify_group_list(%lx, %lx, %d, %d)\n",
+               (unsigned long)group_list, (unsigned long)mi_ptr,
+               iimage, load_image);
+    }
+
+    /* Figure out what to do based upon the mosaic sequencing.
+     */
+    switch (mi_ptr->mosaic_seq) {
+    case MOSAIC_SEQ_INTERLEAVED:
+        /* For interleaved sequences, we have to map the odd slices to
+         * the range slice_count/2..slice_count-1 and the even slices
+         * from zero to slice_count/2-1
+         */
+        if (iimage & 1) {       /* Odd?? */
+            islice = (mi_ptr->slice_count / 2) + (iimage / 2);
+        }
+        else {
+            islice = iimage / 2;
+        }
+        break;
+
+    default:
+        /* Otherwise, just use the image number without modification for
+         * ascending or unknown slice ordering.
+         */
+        islice = iimage;
+        break;
+    }
+
+    /* Check the image number 
+     */
+    if ((iimage < 0) || (iimage > mi_ptr->sub_images)) {
+        fprintf(stderr, "Invalid image number to send: %d of %d\n",
+                iimage, mi_ptr->sub_images);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Update the index
+     */
+    acr_insert_numeric(&group_list, SPI_Current_slice_number, (double) iimage);
+
+    /* Update the position
+     */
+    for (idim = 0; idim < WORLD_NDIMS; idim++) {
+        position[idim] = mi_ptr->position[idim] + 
+            (double) iimage * mi_ptr->step[idim];
+    }
+
+    /* If the sequence is descending, invert the slice coordinate.
+     * This involves subtracting the step * index from the mosaic
+     * slice position.
+     */
+    if (mi_ptr->mosaic_seq == MOSAIC_SEQ_DESCENDING) {
+        position[ZCOORD] = mi_ptr->position[ZCOORD] - 
+            (double) islice * mi_ptr->step[ZCOORD];
+    }
+
+    sprintf(string, "%.15g\\%.15g\\%.15g", 
+            position[XCOORD], position[YCOORD], position[ZCOORD]);
+    acr_insert_string(&group_list, SPI_Image_position, string);
+    acr_insert_string(&group_list, ACR_Image_position_patient, string);
+
+    if (G.Debug >= HI_LOGGING) {
+        printf(" position %s\n", string);
+    }
+
+    if (load_image) {
+        /* Figure out the sub-image indices 
+         */
+        isub = islice % mi_ptr->grid[0];
+        jsub = islice / mi_ptr->grid[0];
+
+        /* Get pointers
+         */
+        old = acr_get_element_data(mi_ptr->big_image);
+        new = acr_get_element_data(mi_ptr->small_image);
+
+        /* Copy the image
+         */
+        nbyte = mi_ptr->size[0] * mi_ptr->pixel_size;
+        for (irow = 0; irow < mi_ptr->size[1]; irow++) {
+            old_offset = isub * mi_ptr->size[0] +
+                (jsub * mi_ptr->size[1] + irow) * mi_ptr->big[0];
+            old_offset *= mi_ptr->pixel_size;
+            new_offset = (irow * mi_ptr->size[0]) * mi_ptr->pixel_size;
+            memcpy(&new[new_offset], &old[old_offset], nbyte);
+        }
+
+        /* Reset the byte order and VR encoding. This will be modified on each
+         * send according to what the connection needs.
+         */
+        acr_set_element_byte_order(mi_ptr->small_image,
+                                   acr_get_element_byte_order(mi_ptr->big_image));
+        acr_set_element_vr_encoding(mi_ptr->small_image,
+                                    acr_get_element_vr_encoding(mi_ptr->big_image));
+    }
+    return 1;
+
+}
+
+static void 
+mosaic_cleanup(Acr_Group group_list, Mosaic_Info *mi_ptr)
+{
+    if (mi_ptr->packed && mi_ptr->big_image != NULL) {
+        acr_delete_element(mi_ptr->big_image);
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/dicom_to_minc.h
@@ -0,0 +1,246 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : dicom_to_minc.h
+@DESCRIPTION: Header file for dicom_to_minc.h
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : January 28, 1997 (Peter Neelin)
+@MODIFIED   : 
+ * $Log: dicom_to_minc.h,v $
+ * Revision 1.4.2.1  2005-05-12 21:16:47  bert
+ * Initial checkin
+ *
+ * Revision 1.4  2005/04/28 17:10:22  bert
+ * Added width information to General_Info and File_Info structures
+ *
+ * Revision 1.3  2005/04/20 23:14:32  bert
+ * Remove unnecessary fields, add copy_spi_to_acr() function definition
+ *
+ * Revision 1.2  2005/03/02 18:25:13  bert
+ * Add Mri_Names and Volume_Names
+ *
+ * Revision 1.1  2005/02/17 16:38:10  bert
+ * Initial checkin, revised DICOM to MINC converter
+ *
+ * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+ * Leili's dicom server for sonata
+ *
+ * Revision 1.6  2002/04/26 03:27:03  rhoge
+ * fixed MrProt problem - replaced fixed lenght char array with malloc
+ *
+ * Revision 1.5  2002/04/08 17:26:34  rhoge
+ * added additional sequence info to minc header
+ *
+ * Revision 1.4  2002/03/27 18:57:50  rhoge
+ * added diffusion b value
+ *
+ * Revision 1.3  2002/03/19 13:13:57  rhoge
+ * initial working mosaic support - I think time is scrambled though.
+ *
+ * Revision 1.2  2001/12/31 18:27:21  rhoge
+ * modifications for dicomreader processing of Numaris 4 dicom files - at
+ * this point code compiles without warning, but does not deal with
+ * mosaiced files.  Also will probably not work at this time for Numaris
+ * 3 .ima files.  dicomserver may also not be functional...
+ *
+ * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+ * imported sources to CVS repository on amoeba
+ *
+ * Revision 6.1  1999/10/29 17:51:59  neelin
+ * Fixed Log keyword
+ *
+ * Revision 6.0  1997/09/12 13:24:27  neelin
+ * Release of minc version 0.6
+ *
+ * Revision 5.0  1997/08/21  13:25:26  neelin
+ * Release of minc version 0.5
+ *
+ * Revision 4.0  1997/05/07  20:06:20  neelin
+ * Release of minc version 0.4
+ *
+ * Revision 1.1  1997/03/04  20:56:47  neelin
+ * Initial revision
+ *
+@COPYRIGHT  :
+              Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+#include <minc.h>
+
+/* General constants */
+#define SECONDS_PER_MINUTE 60
+#define MINUTES_PER_HOUR 60
+#define SECONDS_PER_HOUR (MINUTES_PER_HOUR*SECONDS_PER_MINUTE)
+#define HOURS_PER_DAY 24
+#define SECONDS_PER_DAY (HOURS_PER_DAY*SECONDS_PER_HOUR)
+#define MS_PER_SECOND 1000
+#define COORDINATE_EPSILON (100.0*FLT_EPSILON)
+
+/* Default value for ncopts */
+#define NCOPTS_DEFAULT NC_VERBOSE
+
+/* MINC variable for dicom elements */
+#define DICOM_ROOT_VAR "dicom_groups"
+
+/* Possible MRI dimensions */
+typedef enum { SLICE = 0, ECHO, TIME, PHASE, CHEM_SHIFT, MRI_NDIMS } Mri_Index;
+
+extern const char *Mri_Names[MRI_NDIMS];
+
+/* World dimensions */
+typedef enum { XCOORD = 0, YCOORD, ZCOORD, WORLD_NDIMS } World_Index;
+
+extern const char *World_Names[WORLD_NDIMS];
+
+/* Volume dimensions */
+typedef enum { VSLICE = 0, VROW, VCOLUMN, VOL_NDIMS } Volume_Index;
+
+extern const char *Volume_Names[VOL_NDIMS];
+
+/* Orientations */
+typedef enum {TRANSVERSE = 0, SAGITTAL, CORONAL, NUM_ORIENTATIONS} Orientation;
+
+/* Structure for general info about files */
+typedef struct {
+    int initialized;
+    double study_id;
+    int acq_id;                 /* Time of scan */
+    int rec_num;
+    string_t image_type_string;
+    int nrows;
+    int ncolumns;
+    int default_index[MRI_NDIMS]; /* Index for dimensions with size == 1 */
+    int cur_size[MRI_NDIMS]; /* Size of dimension across these files */
+    int max_size[MRI_NDIMS]; /* Size of dimension across acquisition */
+    int *indices[MRI_NDIMS]; /* List of indices found for each dimension.
+                                Only allocated when size > 1 */ /*  */
+    int search_start[MRI_NDIMS]; /* Indices into lists for starting searches */
+    double *coordinates[MRI_NDIMS]; /* Array indicating coordinate of each
+                                       index in indices array */
+    double *widths[MRI_NDIMS];  /* Array indicating width of each index in
+                                   indices array */
+    int image_index[MRI_NDIMS];  /* Mapping from MRI dim to output image dim */
+    World_Index slice_world;
+    World_Index row_world;
+    World_Index column_world;
+    double step[WORLD_NDIMS];
+    double start[WORLD_NDIMS];
+    double dircos[WORLD_NDIMS][WORLD_NDIMS];
+    nc_type datatype;           /* netCDF (and therefore MINC) datatype */
+    int is_signed;              /* TRUE of 2's compliment data */
+    double pixel_min;
+    double pixel_max;
+    string_t units;
+    double window_min;
+    double window_max;
+    int num_mosaic_rows;
+    int num_mosaic_cols;
+    int num_slices_in_file;
+    int sub_image_rows;
+    int sub_image_columns;
+    struct {
+        string_t name;
+        string_t identification;
+        string_t birth_date;
+        string_t age;
+        string_t sex;
+        string_t reg_date;
+        string_t reg_time;
+        double weight;
+    } patient;
+    struct {
+        string_t start_time;
+        string_t modality;
+        string_t manufacturer;
+        string_t model;
+        double  field_value;
+        string_t software_version;
+        string_t serial_no;
+        string_t calibration_date;
+        string_t institution;
+        string_t station_id;
+        string_t referring_physician;
+        string_t performing_physician;
+        string_t operator;
+        string_t procedure;
+        string_t study_id;
+        string_t acquisition_id;
+    } study;
+    struct {
+        string_t scan_seq;
+        string_t protocol_name;
+        string_t receive_coil;
+        string_t transmit_coil;
+        double rep_time;
+        double slice_thickness;
+        double num_slices;
+        double echo_time;
+        double echo_number;
+        double inv_time;
+        double b_value;
+        double flip_angle;
+        double num_avg;
+        double num_dyn_scans;
+        double imaging_freq;
+        string_t imaged_nucl;
+        double  win_center;
+        double  win_width;
+        double  num_phase_enc_steps;
+        double  percent_sampling;
+        double  percent_phase_fov;
+        double  pixel_bandwidth;
+        string_t phase_enc_dir;
+        string_t mr_acq_type;
+        string_t image_type;
+        double  sar;
+        string_t comments;
+        char *MrProt;           // Siemens Numaris 4 specific
+    } acq;
+    Acr_Group group_list;
+} General_Info;
+
+/* Structure for file-specific info */
+typedef struct {
+   int valid;
+   int bits_alloc;
+   int bits_stored;
+   int index[MRI_NDIMS];
+   double pixel_max;
+   double pixel_min;
+   double slice_max;
+   double slice_min;
+   double window_max;
+   double window_min;
+   double coordinate[MRI_NDIMS];
+   double width[MRI_NDIMS];     /* Sample width along each MRI dimension */
+} File_Info;
+
+/* Structure for storing the actual image data */
+typedef struct {
+    int free;
+    int nrows;
+    int ncolumns;
+    unsigned short *data;
+} Image_Data;
+
+/* function definitions */
+extern int dicom_to_minc(int num_files, 
+                         const char **file_list, 
+                         const char *minc_file, 
+                         int clobber,
+                         const char *file_prefix, 
+                         char **output_file_name);
+extern Acr_Group read_std_dicom(const char *filename, int max_group);
+extern Acr_Group read_numa4_dicom(const char *filename, int max_group);
+extern int search_list(int value, const int *list_ptr, int list_length, 
+                       int start_index);
+extern Acr_Group copy_spi_to_acr(Acr_Group group_list);
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/ext_element_defs.h
@@ -0,0 +1,36 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : ext_element_defs.h
+@DESCRIPTION: Element definitions for extra elements needed for mosaics, etc.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : December 2001 (Rick Hoge)
+@MODIFIED   : 
+@COPYRIGHT  :
+              Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* Element id's for EXT */
+/* bert- These appear to be completely nonstandard - I believe they were 
+ * created by Peter and Rick to facilitate communication among the various
+ * pieces of Siemens Mosaic handling code.  They do not represent any 
+ * externally defined DICOM standard and therefore they may conflict with 
+ * other manufacturer's proprietary fields.
+ */
+GLOBAL_ELEMENT(EXT_Mosaic_rows                        , 0x0023, 0x0001, LO);
+GLOBAL_ELEMENT(EXT_Mosaic_columns                     , 0x0023, 0x0002, LO);
+GLOBAL_ELEMENT(EXT_Slices_in_file                     , 0x0023, 0x0003, LO);
+GLOBAL_ELEMENT(EXT_Sub_image_rows                     , 0x0023, 0x0004, US);
+GLOBAL_ELEMENT(EXT_Sub_image_columns                  , 0x0023, 0x0005, US);
+GLOBAL_ELEMENT(EXT_MrProt_dump                        , 0x0023, 0x0006, LO);
+GLOBAL_ELEMENT(EXT_Diffusion_b_value                  , 0x0023, 0x0007, LO);
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/gems_element_defs.h
@@ -0,0 +1,35 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : gems_element_defs.h
+@DESCRIPTION: Element definitions for GE Medical Systems
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 14, 2005
+@MODIFIED   : 
+@COPYRIGHT  :
+              Copyright (C) 2005 Robert D. Vincent, 
+              McConnell Brain Imaging Centre,
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* This information was derived from the publically available "Advance(TM)
+ * 4.05 Conformance Statement for DICOM V3.0" from GE Medical Systems,
+ * copyright 2000 by GE Medical Systems.
+ */
+
+GLOBAL_ELEMENT(GEMS_Acqu_private_creator_id, 0x0019, 0x0010, SH);
+GLOBAL_ELEMENT(GEMS_Frame_acq_start        , 0x0019, 0x106c, DT);
+GLOBAL_ELEMENT(GEMS_Frame_acq_duration     , 0x0019, 0x106d, SL);
+GLOBAL_ELEMENT(GEMS_Image_slice_number     , 0x0019, 0x10a6, SL);
+GLOBAL_ELEMENT(GEMS_Fast_phases            , 0x0019, 0x10f2, SS);
+
+GLOBAL_ELEMENT(GEMS_Sers_private_creator_id, 0x0025, 0x0010, SH);
+GLOBAL_ELEMENT(GEMS_Images_in_series       , 0x0025, 0x1007, SL);
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/minc_file.c
@@ -0,0 +1,1088 @@
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : minc_file.c
+   @DESCRIPTION: Code to do minc file handling.
+   @METHOD     : 
+   @GLOBALS    : 
+   @CALLS      : 
+   @CREATED    : January 28, 1997 (Peter Neelin)
+   @MODIFIED   : 
+   * $Log: minc_file.c,v $
+   * Revision 1.6.2.1  2005-05-12 21:16:48  bert
+   * Initial checkin
+   *
+   * Revision 1.6  2005/04/29 23:09:06  bert
+   * Write sample-width information to file for irregular time dimensions
+   *
+   * Revision 1.5  2005/04/20 23:15:06  bert
+   * Don't save attributes that are no longer set
+   *
+   * Revision 1.4  2005/04/18 16:21:42  bert
+   * Add debugging information for intensity scaling
+   *
+   * Revision 1.3  2005/03/13 19:34:21  bert
+   * Minor change to avoid core dump with strange files
+   *
+   * Revision 1.2  2005/03/03 18:59:15  bert
+   * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+   *
+   * Revision 1.1  2005/02/17 16:38:10  bert
+   * Initial checkin, revised DICOM to MINC converter
+   *
+   * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+   * Leili's dicom server for sonata
+   *
+   * Revision 1.12  2002/04/29 15:24:53  rhoge
+   * removed (mode_t) cast in minc_file - would not build on SGI's
+   *
+   * Revision 1.11  2002/04/08 17:26:34  rhoge
+   * added additional sequence info to minc header
+   *
+   * Revision 1.10  2002/03/27 18:57:50  rhoge
+   * added diffusion b value
+   *
+   * Revision 1.9  2002/03/22 19:19:36  rhoge
+   * Numerous fixes -
+   * - handle Numaris 4 Dicom patient name
+   * - option to cleanup input files
+   * - command option
+   * - list-only option
+   * - debug mode
+   * - user supplied name, idstr
+   * - anonymization
+   *
+   * Revision 1.8  2002/03/19 22:10:16  rhoge
+   * removed time sorting for N4DCM mosaics - time is random for mosaics
+   *
+   * Revision 1.7  2002/03/19 13:13:56  rhoge
+   * initial working mosaic support - I think time is scrambled though.
+   *
+   * Revision 1.6  2001/12/31 18:27:21  rhoge
+   * modifications for dicomreader processing of Numaris 4 dicom files - at
+   * this point code compiles without warning, but does not deal with
+   * mosaiced files.  Also will probably not work at this time for Numaris
+   * 3 .ima files.  dicomserver may also not be functional...
+   *
+   * Revision 1.5  2001/02/26 22:22:37  rhoge
+   * added scanner serial number to minc file naming
+   *
+   * Revision 1.4  2001/02/26 13:38:22  rhoge
+   * made `existing directory' warning conditional on logging
+   *
+   * Revision 1.3  2000/12/15 01:04:46  rhoge
+   * make sure acquisition_id (series no) is 6 digit hhmmss string for meas loop
+   *
+   * Revision 1.2  2000/12/14 21:19:22  rhoge
+   * added code to compute time spacing if measurement loop dynamic
+   * scanning has been detected
+   *
+   * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+   * imported sources to CVS repository on amoeba
+   *
+   * Revision 6.1  1999/10/29 17:51:55  neelin
+   * Fixed Log keyword
+   *
+   * Revision 6.0  1997/09/12 13:24:27  neelin
+   * Release of minc version 0.6
+   *
+   * Revision 5.0  1997/08/21  13:25:26  neelin
+   * Release of minc version 0.5
+   *
+   * Revision 4.0  1997/05/07  20:06:20  neelin
+   * Release of minc version 0.4
+   *
+   * Revision 1.1  1997/03/04  20:56:47  neelin
+   * Initial revision
+   *
+   @COPYRIGHT  :
+   Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+   Montreal Neurological Institute, McGill University.
+   Permission to use, copy, modify, and distribute this
+   software and its documentation for any purpose and without
+   fee is hereby granted, provided that the above copyright
+   notice appear in all copies.  The author and McGill University
+   make no representations about the suitability of this
+   software for any purpose.  It is provided "as is" without
+   express or implied warranty.
+---------------------------------------------------------------------------- */
+static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/minc_file.c,v 1.6.2.1 2005-05-12 21:16:48 bert Exp $";
+
+#include "dcm2mnc.h"
+
+#include <sys/stat.h>
+#include <ctype.h>
+
+/* Define mri dimension names */
+static char *mri_dim_names[] = {
+    NULL, "echo_time", MItime, "phase_number", "chemical_shift", NULL};
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : create_minc_file
+   @INPUT      : minc_file - name of file to create. If NULL, a name is 
+   generated internally.
+   clobber - if TRUE, any existing file will be overwritten.
+   general_info - information for creating the file.
+   file_prefix - string providing any directory or prefix 
+   for internally generated filename (if it is a directory,
+   then it must contain the last "/")
+   @OUTPUT     : output_file_name - returns a pointer to an internal area
+   containing the file name of the created file if minc_file
+   is NULL, or simply a pointer to minc_file. If NULL, then
+   nothing is returned.
+   @RETURNS    : id of image conversion variable (MI_ERROR in case of error).
+   @DESCRIPTION: Routine to create the minc file.
+   @METHOD     : 
+   @GLOBALS    : 
+   CALLS       : 
+   @CREATED    : November 26, 1993 (Peter Neelin)
+   @MODIFIED   : rhoge - modified to create directory for session
+   ---------------------------------------------------------------------------- */
+int
+create_minc_file(const char *minc_file, 
+                 int clobber,
+                 General_Info *general_info,
+                 const char *file_prefix, 
+                 char **output_file_name,
+                 Loop_Type loop_type)
+{
+    static char temp_name[256];
+    char patient_name[256];
+    char reg_time[256];
+    char temp_str[256];
+    const char *filename;
+    int minc_clobber;
+    int mincid, icvid;
+    Mri_Index imri;
+    char scan_label[MRI_NDIMS][20];
+
+    /* added by rhoge for study directory, new naming conventions: */
+
+    char full_path[256];
+
+    /* Prefixes for creating file name */
+    static char *scan_prefix[MRI_NDIMS] = 
+        {"sl", "e", "d", "p", "cs"};
+
+    /* Turn off fatal errors */
+    ncopts = NCOPTS_DEFAULT;
+
+    /* Create the file name if needed */
+    if (minc_file != NULL) {
+        filename = minc_file;
+    }
+    else {
+        /* Get patient name */
+        /******************************************/
+        /* Changed by Leili from "string_to_initials" to "string_to_filename" */
+        /* based on people's request at MNI */ 
+        if (G.Name[0] != '\0') {
+            strcpy(patient_name, G.Name);
+        } 
+        else {
+            string_to_filename(general_info->patient.name, patient_name,
+                               sizeof(patient_name));
+        }
+
+        if (strlen(patient_name) == 0) {
+            strcpy(patient_name, "no_name");
+        }
+
+        /******************************************/
+        /* Get Study Time */
+        string_to_filename(general_info->patient.reg_time, temp_str,
+                           sizeof(temp_str));
+        /* truncate to first 6 chars (hhmmss) */
+        strncpy(reg_time, temp_str, 6);
+        if (strlen(reg_time) == 0) {
+            strcpy(reg_time, "no_time");
+        }
+        reg_time[6]='\0'; /* terminate with null (strncpy does not) */
+
+        /* Get strings for echo number, etc. */
+        for (imri=0; imri < MRI_NDIMS; imri++) {
+            if ((general_info->cur_size[imri] < general_info->max_size[imri]) &&
+                (general_info->cur_size[imri] == 1)) {
+                sprintf(scan_label[imri], "%s%d", scan_prefix[imri],
+                        general_info->default_index[imri]);
+            }
+            else {
+                strcpy(scan_label[imri], "");
+            }
+        }
+
+        /* rhoge:  add session directory to prefix */
+      
+        strcpy(full_path, file_prefix);
+
+        sprintf(temp_name, "%s_%s_%s/",
+                patient_name,
+                general_info->patient.reg_date,
+                reg_time);
+        strcat(full_path, temp_name);
+
+
+        /* if measurement loop, make sure that acquisition_id is
+           a 6 digit (hhmmss) string with leading zero if needed */
+
+        if (loop_type == MEAS) {
+
+            sprintf(general_info->study.acquisition_id, "%06d",
+                    general_info->acq_id);
+
+        }
+
+        /* Create file name */
+        /* changed by leili, omitted the scanner info, changed - to _ */
+        sprintf(temp_name, "%s%s_%s_%s_%s%s%s%s%s%s_mri.mnc", 
+                full_path,
+                patient_name,
+                general_info->patient.reg_date,
+                reg_time,
+                general_info->study.acquisition_id,
+                scan_label[SLICE],
+                scan_label[ECHO],
+                scan_label[TIME],
+                scan_label[PHASE],
+                scan_label[CHEM_SHIFT]);
+        filename = temp_name;
+
+        if (G.Debug) {
+            printf("MINC file name:  %s\n", filename);
+            printf("File prefix:     %s\n", full_path);
+            printf("Patient name:    %s\n", patient_name);
+            printf("Study ID:        %s\n", 
+                   general_info->study.study_id);
+            printf("Acquisition ID:  %s\n", 
+                   general_info->study.acquisition_id);
+            printf("Registration date:  %s\n", 
+                   general_info->patient.reg_date);
+            printf("Registration time:  %s\n", 
+                   general_info->patient.reg_time);
+            printf("Rows %d columns %d slices %d/%d\n",
+                   general_info->nrows,
+                   general_info->ncolumns,
+                   general_info->cur_size[SLICE],
+                   general_info->max_size[SLICE]);
+            if (general_info->max_size[TIME] != 1) {
+                printf("Time axis length: %d/%d\n", 
+                       general_info->cur_size[TIME],
+                       general_info->max_size[TIME]);
+            }
+        }
+    }
+
+    /* create the session directory if none exists */
+
+    if (mkdir(full_path, 0777) && G.Debug) {
+        printf("Directory %s exists...\n", full_path);
+    }
+
+    /* Set output file name */
+    if (output_file_name != NULL) {
+        *output_file_name = (char *) filename;
+    }
+
+    /* Set the clobber value */
+    if (clobber) 
+        minc_clobber = NC_CLOBBER;
+    else 
+        minc_clobber = NC_NOCLOBBER;
+
+    /* Create the file */
+    mincid = micreate((char *) filename, minc_clobber);
+    if (mincid == MI_ERROR) {
+        return MI_ERROR;
+    }
+
+    /* Set up variables */
+    setup_minc_variables(mincid, general_info, loop_type);
+
+    /* Put the file in data mode */
+    ncsetfill(mincid, NC_NOFILL);
+    if (ncendef(mincid) == MI_ERROR) {
+        return MI_ERROR;
+    }
+
+    /* Create the icv */
+    icvid = miicv_create();
+
+    /* Set the type and range */
+    miicv_setint(icvid, MI_ICV_TYPE, NC_SHORT);
+    if (general_info->is_signed)
+        miicv_setstr(icvid, MI_ICV_SIGN, MI_SIGNED);
+    else
+        miicv_setstr(icvid, MI_ICV_SIGN, MI_UNSIGNED);
+    miicv_setdbl(icvid, MI_ICV_VALID_MIN, general_info->pixel_min);
+    miicv_setdbl(icvid, MI_ICV_VALID_MAX, general_info->pixel_max);
+
+    /* Attach the icv */
+    miicv_attach(icvid, mincid, ncvarid(mincid, MIimage));
+
+    return icvid;
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : minc_set_spacing
+   @INPUT      : mincid
+                 varid
+                 imri
+                 gi_ptr
+   @OUTPUT     : (nothing)
+   @RETURNS    : (nothing)
+   @DESCRIPTION: This function checks the given MRI dimension (most typically
+                 the TIME dimension) to see if it has a "regular" structure.
+                 If so, the MINC file is updated accordingly.  If not, the
+                 function creates a "xxxx-width" variable corresponding to the
+                 dimension which will contain the width information from this
+                 dimension.  NOTE: At present only the time-width variable 
+                 is defined by MINC.
+   @METHOD     : 
+   @GLOBALS    : 
+   CALLS       : 
+   @CREATED    : April 27, 2005 (Bert Vincent)
+   @MODIFIED   :
+   ----------------------------------------------------------------------------
+ */
+
+static void 
+minc_set_spacing(int mincid, int varid, Mri_Index imri, General_Info *gi_ptr)
+{
+    double sum;                 /* Sum of differences for computing average */
+    double avg;                 /* Average */
+    double diff;                /* Difference between adjacent coordinates */
+    double step;                /* Step size from widths */
+    int regular;                /* TRUE if dimension is regular */
+    int index;                  /* Loop/array index */
+    long length;                /* Length of this dimension (> 1) */
+
+    regular = TRUE;
+
+    length = gi_ptr->cur_size[imri];
+
+    /* First, see if the widths were set, and if so, if they are consistent.
+     */
+    for (index = 1; index < length; index++) {
+        if (gi_ptr->widths[imri][0] != gi_ptr->widths[imri][index]) {
+            regular = FALSE;
+            break;
+        }
+    }
+
+    /* OK, now set the step value according to the widths, if possible.
+     */
+    if (regular) {
+        step = gi_ptr->widths[imri][0];
+
+        /* Now calculate the average value for the coordinate spacing.
+         */
+        sum = 0.0;
+        for (index = 1; index < length; index++) {
+            sum += gi_ptr->coordinates[imri][index] - 
+                gi_ptr->coordinates[imri][index-1];
+        }
+
+        avg = sum / length;     /* compute mean */
+
+        if (step != 0.0 && avg != step) {
+            printf("WARNING: Sample width %f not equal to average delta %f\n",
+                   step, avg);
+        }
+
+        step = avg;             /* Use the average anyway. */
+
+        /* Check for uniformity of spacing */
+
+        for (index = 1; index < length; index++) {
+
+            /* Calculate the difference between two adjacent locations,
+             * less the average step value.
+             */
+
+            diff = gi_ptr->coordinates[imri][index] -
+                gi_ptr->coordinates[imri][index - 1] - step;
+        
+            if (diff < 0.0) {
+                diff = -diff;
+            }
+            if (step != 0.0) {
+                diff /= step;
+            }
+            if (diff > COORDINATE_EPSILON) {
+                regular = FALSE;
+                break;
+            }
+        }
+    }
+    else {
+        /* We have widths provided for us, so use them to calculate the
+         * average step size.
+         */
+        for (index = 0; index < length; index++) {
+            sum += gi_ptr->widths[imri][index];
+        }
+        step = sum / length;
+    }
+
+    /*
+     * Write the step value.  According to the MINC specifications, it is 
+     * always valid to store a step value even for irregular dimensions. 
+     * The step should always equal the average spacing of the dimension.
+     */
+    miattputdbl(mincid, varid, MIstep, step);
+
+    if (regular) {
+        miattputstr(mincid, varid, MIspacing, MI_REGULAR);
+    }
+    else {
+        miattputstr(mincid, varid, MIspacing, MI_IRREGULAR);
+
+        /* Create the <dimension-name>-width variable.  At present, this
+         * is only a valid operation if the dimension in question is the
+         * time dimension. MINC does not define a width variable for any of
+         * the other, non-standard dimensions.  So for now this code is 
+         * very much a special case.
+         */
+        if (imri == TIME) {
+            int dimid;
+
+            dimid = ncdimid(mincid, MItime);
+            if (dimid >= 0) {
+                micreate_std_variable(mincid, MItime_width, NC_DOUBLE,
+                                      1, &dimid);
+            }
+        }
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : setup_minc_variables
+   @INPUT      : mincid
+   general_info
+   @OUTPUT     : general_info
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to setup minc variables.
+   @METHOD     : 
+   @GLOBALS    : 
+   CALLS       : 
+   @CREATED    : November 26, 1993 (Peter Neelin)
+   @MODIFIED   :
+   ---------------------------------------------------------------------------- */
+void setup_minc_variables(int mincid, General_Info *general_info,
+                          Loop_Type loop_type)
+{
+    Mri_Index imri;
+    Volume_Index ivol;
+    World_Index iworld;
+    int ndims;
+    int dim[MAX_VAR_DIMS];
+    long dimsize;
+    char *dimname;
+    int varid, imgid, dicomvar;
+    double valid_range[2];
+    char name[MAX_NC_NAME];
+    int index;
+    int regular;
+    double separation, diff;
+    Acr_Group cur_group;
+    Acr_Element cur_element;
+    int length;
+    char *data;
+    nc_type datatype;
+    int is_char;
+    int ich;
+
+    /* Define the spatial dimension names */
+    static char *spatial_dimnames[WORLD_NDIMS] = {MIxspace, MIyspace, MIzspace};
+
+    /* Create the dimensions from slowest to fastest */
+
+    ndims=0;
+    /* Create the non-spatial dimensions (from slowest to fastest) */
+    for (imri=MRI_NDIMS-1; (int) imri > SLICE; imri--) {
+
+        /* for the TIME dimension, check if we have acquisition-loop
+           dynamic scan OR a `corrected' dynamic scan */
+
+        if ( (imri==TIME) &&
+             ((loop_type!=NONE) || (general_info->acq.num_dyn_scans>1)) ) { 
+
+            /* for Siemens scans using the signal averaging loop for
+               multiple time points we use the TR as the time step */
+
+            dimsize = general_info->cur_size[TIME];
+            if (general_info->cur_size[TIME] > 1) {
+                dimname = mri_dim_names[TIME];
+                dim[ndims] = ncdimdef(mincid, dimname, dimsize);
+
+                varid = micreate_std_variable(mincid, dimname, NC_DOUBLE, 1, 
+                                              &dim[ndims]);
+                miattputstr(mincid, varid, MIspacing, MI_REGULAR);
+                miattputstr(mincid, varid, MIunits, "s");
+                if (loop_type == MEAS) {
+                    /* if Meas loop, time step is not equal to TR, and
+                       frames should have time values (rhoge) */
+
+                    minc_set_spacing(mincid, varid, TIME, general_info);
+                } else {
+
+                    /* assume ACQ loop and use TR for time step */
+                    miattputdbl(mincid, varid, MIstep,
+                                general_info->acq.rep_time);
+                }
+                miattputdbl(mincid, varid, MIstart,0);
+
+                general_info->image_index[TIME] = ndims;
+                ndims++;
+            }
+
+        } else { /* NORMAL CODE */
+
+            dimsize = general_info->cur_size[imri];
+            if (general_info->cur_size[imri] > 1) {
+                dimname = mri_dim_names[imri];
+                dim[ndims] = ncdimdef(mincid, dimname, dimsize);
+                if (imri == TIME) {
+                    varid = micreate_std_variable(mincid, dimname, NC_DOUBLE, 1, 
+                                                  &dim[ndims]);
+                    miattputstr(mincid, varid, MIunits, "s");
+                    minc_set_spacing(mincid, varid, TIME, general_info);
+                }
+                else if (imri == ECHO) {
+                    varid = ncvardef(mincid, dimname, NC_DOUBLE, 1, &dim[ndims]);
+                    miattputstr(mincid, varid, MIvartype, MI_DIMENSION);
+                    miattputstr(mincid, varid, MIspacing, MI_IRREGULAR);
+                    miattputstr(mincid, varid, MIunits, "s");
+                }
+                general_info->image_index[imri] = ndims;
+                ndims++;
+            }
+        }
+    }
+
+    /* Next the spatial dimensions */
+    for (ivol = 0; ivol < VOL_NDIMS; ivol++) {
+        switch (ivol) {
+        case VSLICE: 
+            dimsize = general_info->cur_size[SLICE];
+            iworld = general_info->slice_world;
+            break;
+        case VROW: 
+            dimsize = general_info->nrows;
+            iworld = general_info->row_world;
+            break;
+        case VCOLUMN: 
+            dimsize = general_info->ncolumns;
+            iworld = general_info->column_world;
+            break;
+        default:
+            fprintf(stderr, "Should not happen!!");
+            exit(-1);
+        }
+        dimname = spatial_dimnames[iworld];
+        dim[ndims] = ncdimdef(mincid, dimname, dimsize);
+        if (ivol == VSLICE) {
+            varid = micreate_std_variable(mincid, dimname, NC_DOUBLE, 
+                                          1, &dim[ndims]);
+            /* Check for regular slices */
+            regular = TRUE;
+            separation = general_info->step[general_info->slice_world];
+            for (index=1; index < general_info->cur_size[SLICE]; index++) {
+                diff = general_info->coordinates[SLICE][index] -
+                    general_info->coordinates[SLICE][index-1] - separation;
+                if (diff < 0.0) diff = -diff;
+                if (separation != 0.0) diff /= separation;
+                if (diff > COORDINATE_EPSILON) {
+                    regular = FALSE;
+                    break;
+                }
+            }
+            if (regular)
+                miattputstr(mincid, varid, MIspacing, MI_REGULAR);
+        }
+        else
+            varid = micreate_std_variable(mincid, dimname, NC_LONG, 0, NULL);
+        miattputdbl(mincid, varid, MIstep, 
+                    general_info->step[iworld]);
+        miattputdbl(mincid, varid, MIstart, 
+                    general_info->start[iworld]);
+        miattputstr(mincid, varid, MIspacetype, MI_NATIVE);
+        ncattput(mincid, varid, MIdirection_cosines, 
+                 NC_DOUBLE, WORLD_NDIMS,
+                 general_info->dircos[iworld]);
+        if (ivol == VSLICE) {
+            general_info->image_index[SLICE] = ndims;
+        }
+        ndims++;
+    }
+
+    /* Set up image variable */
+    imgid = micreate_std_variable(mincid, MIimage, general_info->datatype,
+                                  ndims, dim);
+    if (general_info->is_signed)
+        miattputstr(mincid, imgid, MIsigntype, MI_SIGNED);
+    else
+        miattputstr(mincid, imgid, MIsigntype, MI_UNSIGNED);
+    valid_range[0] = general_info->pixel_min;
+    valid_range[1] = general_info->pixel_max;
+    ncattput(mincid, imgid, MIvalid_range, NC_DOUBLE, 2, valid_range);
+    miattputstr(mincid, imgid, MIcomplete, MI_FALSE);
+
+    /* Create image max and min variables */
+    varid = micreate_std_variable(mincid, MIimagemin, NC_DOUBLE, ndims-2, dim);
+    if (strlen(general_info->units) > 0)
+        miattputstr(mincid, varid, MIunits, general_info->units);
+    varid = micreate_std_variable(mincid, MIimagemax, NC_DOUBLE, ndims-2, dim);
+    if (strlen(general_info->units) > 0)
+        miattputstr(mincid, varid, MIunits, general_info->units);
+
+    /* Create the patient variable */
+    varid = micreate_group_variable(mincid, MIpatient);
+    if (strlen(general_info->patient.name) > 0) {
+        if (G.Anon) {
+            miattputstr(mincid, varid, MIfull_name, "anonymous");
+        } 
+        else {
+            miattputstr(mincid, varid, MIfull_name, 
+                        general_info->patient.name);
+        }
+    }
+    if (strlen(general_info->patient.identification) > 0)
+        miattputstr(mincid, varid, MIidentification, 
+                    general_info->patient.identification);
+    if (strlen(general_info->patient.birth_date) > 0)
+        miattputstr(mincid, varid, MIbirthdate, 
+                    general_info->patient.birth_date);
+    if (strlen(general_info->patient.age) > 0)
+        miattputstr(mincid, varid, "age", 
+                    general_info->patient.age);
+    if (strlen(general_info->patient.sex) > 0)
+        miattputstr(mincid, varid, MIsex, 
+                    general_info->patient.sex);
+    if (general_info->patient.weight != -DBL_MAX) 
+        miattputdbl(mincid, varid, MIweight, 
+                    general_info->patient.weight);
+
+    /* Create the study variable */
+    varid = micreate_group_variable(mincid, MIstudy);
+
+    /* rhoge: fixed date/time to reflect study */
+    if (strlen(general_info->patient.reg_date) > 0)
+        miattputstr(mincid, varid, "start_date", 
+                    general_info->patient.reg_date);
+    if (strlen(general_info->patient.reg_time) > 0)
+        miattputstr(mincid, varid, "start_time", 
+                    general_info->patient.reg_time);
+    if (strlen(general_info->study.modality) > 0)
+        miattputstr(mincid, varid, MImodality, 
+                    general_info->study.modality);
+    if (strlen(general_info->study.manufacturer) > 0)
+        miattputstr(mincid, varid, "manufacturer", 
+                    general_info->study.manufacturer);
+    if (strlen(general_info->study.model) > 0)
+        miattputstr(mincid, varid, "model", 
+                    general_info->study.model);
+    if (general_info->study.field_value != -DBL_MAX)
+        miattputdbl(mincid, varid, "field_value", 
+                    general_info->study.field_value);
+    if (strlen(general_info->study.software_version) > 0)
+        miattputstr(mincid, varid, "software_version", 
+                    general_info->study.software_version);
+    if (strlen(general_info->study.serial_no) > 0)
+        miattputstr(mincid, varid, "serial_no", 
+                    general_info->study.serial_no);
+    if (strlen(general_info->study.calibration_date) > 0)
+        miattputstr(mincid, varid, "calibration_date", 
+                    general_info->study.calibration_date);
+    if (strlen(general_info->study.institution) > 0)
+        miattputstr(mincid, varid, MIinstitution, 
+                    general_info->study.institution);
+    if (strlen(general_info->study.station_id) > 0)
+        miattputstr(mincid, varid, MIstation_id, 
+                    general_info->study.station_id);
+    if (strlen(general_info->study.referring_physician) > 0)
+        miattputstr(mincid, varid, MIreferring_physician, 
+                    general_info->study.referring_physician);
+
+    if (strlen(general_info->study.performing_physician) > 0)
+        miattputstr(mincid, varid, "performing_physician", 
+                    general_info->study.referring_physician);
+    if (strlen(general_info->study.operator) > 0)
+        miattputstr(mincid, varid, "operator", 
+                    general_info->study.operator);
+
+    if (strlen(general_info->study.procedure) > 0)
+        miattputstr(mincid, varid, MIprocedure, 
+                    general_info->study.procedure);
+    if (strlen(general_info->study.study_id) > 0)
+        miattputstr(mincid, varid, MIstudy_id, 
+                    general_info->study.study_id);
+
+    /* Create acquisition variable */
+    varid = micreate_group_variable(mincid, MIacquisition);
+    if (strlen(general_info->study.acquisition_id) > 0)
+        miattputstr(mincid, varid, "acquisition_id", 
+                    general_info->study.acquisition_id);
+    if (strlen(general_info->study.start_time) > 0)
+        miattputstr(mincid, varid, MIstart_time, 
+                    general_info->study.start_time);
+
+    if (strlen(general_info->acq.scan_seq) > 0)
+        miattputstr(mincid, varid, MIscanning_sequence, 
+                    general_info->acq.scan_seq);
+
+    if (strlen(general_info->acq.protocol_name) > 0)
+        miattputstr(mincid, varid, "protocol_name", 
+                    general_info->acq.protocol_name);
+    if (strlen(general_info->acq.receive_coil) > 0)
+        miattputstr(mincid, varid, "receive_coil", 
+                    general_info->acq.receive_coil);
+    if (strlen(general_info->acq.transmit_coil) > 0)
+        miattputstr(mincid, varid, "transmit_coil", 
+                    general_info->acq.transmit_coil);
+
+    if (general_info->acq.rep_time != -DBL_MAX)
+        miattputdbl(mincid, varid, MIrepetition_time, 
+                    general_info->acq.rep_time);
+    if ((general_info->acq.echo_time != -DBL_MAX) &&
+        (general_info->cur_size[ECHO] <= 1))
+        miattputdbl(mincid, varid, MIecho_time, 
+                    general_info->acq.echo_time);
+    if (general_info->acq.echo_number != -DBL_MAX)
+        miattputdbl(mincid, varid, "echo_number", 
+                    general_info->acq.echo_number);
+    if (general_info->acq.inv_time != -DBL_MAX)
+        miattputdbl(mincid, varid, MIinversion_time, 
+                    general_info->acq.inv_time);
+    if (general_info->acq.flip_angle != -DBL_MAX)
+        miattputdbl(mincid, varid, "flip_angle", 
+                    general_info->acq.flip_angle);
+    if (general_info->acq.slice_thickness != -DBL_MAX)
+        miattputdbl(mincid, varid, "slice_thickness", 
+                    general_info->acq.slice_thickness);
+    if (general_info->acq.num_slices != -DBL_MAX)
+        miattputdbl(mincid, varid, "num_slices", 
+                    general_info->acq.num_slices);
+    if (general_info->acq.b_value != -DBL_MAX)
+        miattputdbl(mincid, varid, "b_value", 
+                    general_info->acq.b_value);
+
+    /* add number of dynamic scans (rhoge) */
+    /* this will be relevant if we are receiving siemens scans that
+       have been `cleaned up' (and hence have the correct number of
+       dynamic scans inserted) */
+
+    if (general_info->acq.num_dyn_scans != -DBL_MAX)
+        miattputdbl(mincid, varid, "num_dyn_scans", 
+                    general_info->acq.num_dyn_scans);
+
+    if (general_info->acq.num_avg != -DBL_MAX)
+        miattputdbl(mincid, varid, MInum_averages, 
+                    general_info->acq.num_avg);
+
+    if (general_info->acq.imaging_freq != -DBL_MAX)
+        miattputdbl(mincid, varid, MIimaging_frequency, 
+                    general_info->acq.imaging_freq);
+    if (strlen(general_info->acq.imaged_nucl) > 0)
+        miattputstr(mincid, varid, MIimaged_nucleus, 
+                    general_info->acq.imaged_nucl);
+
+    if (general_info->acq.win_center != -DBL_MAX)
+        miattputdbl(mincid, varid, "window_center", 
+                    general_info->acq.win_center);
+
+    if (general_info->acq.win_width != -DBL_MAX)
+        miattputdbl(mincid, varid, "window_width", 
+                    general_info->acq.win_width);
+
+    if (general_info->acq.num_phase_enc_steps != -DBL_MAX)
+        miattputdbl(mincid, varid, "num_phase_enc_steps", 
+                    general_info->acq.num_phase_enc_steps);
+    if (general_info->acq.percent_sampling != -DBL_MAX)
+        miattputdbl(mincid, varid, "percent_sampling", 
+                    general_info->acq.percent_sampling);
+    if (general_info->acq.percent_phase_fov != -DBL_MAX)
+        miattputdbl(mincid, varid, "percent_phase_fov", 
+                    general_info->acq.percent_phase_fov);
+    if (general_info->acq.pixel_bandwidth != -DBL_MAX)
+        miattputdbl(mincid, varid, "pixel_bandwidth", 
+                    general_info->acq.pixel_bandwidth);
+    if (strlen(general_info->acq.phase_enc_dir) > 0)
+        miattputstr(mincid, varid, "phase_enc_dir", 
+                    general_info->acq.phase_enc_dir);
+    if (general_info->acq.sar != -DBL_MAX)
+        miattputdbl(mincid, varid, "SAR", 
+                    general_info->acq.sar);
+    if (strlen(general_info->acq.mr_acq_type) > 0)
+        miattputstr(mincid, varid, "mr_acq_type", 
+                    general_info->acq.mr_acq_type);
+    if (strlen(general_info->acq.image_type) > 0)
+        miattputstr(mincid, varid, "image_type", 
+                    general_info->acq.image_type);
+
+    if (strlen(general_info->acq.comments) > 0)
+        miattputstr(mincid, varid, MIcomments, 
+                    general_info->acq.comments);
+
+    // this is Siemens Numaris 4 specific!
+    if (strlen(general_info->acq.MrProt) > 0)
+        miattputstr(mincid, varid, "MrProt_dump", 
+                    general_info->acq.MrProt);
+
+    /* Create the dicom info variable */
+    varid = ncvardef(mincid, "dicominfo", NC_LONG, 0, NULL);
+    miattputstr(mincid, varid, MIvartype, MI_GROUP);
+    miattputstr(mincid, varid, MIvarid, 
+                "MNI DICOM information variable");
+    miadd_child(mincid, ncvarid(mincid, MIrootvariable), varid);
+    if (strlen(general_info->image_type_string) > 0)
+        miattputstr(mincid, varid, "image_type", 
+                    general_info->image_type_string);
+    miattputdbl(mincid, varid, "window_min", general_info->window_min);
+    miattputdbl(mincid, varid, "window_max", general_info->window_max);
+
+    /* Put group info in header */
+    cur_group = general_info->group_list;
+    dicomvar = ncvardef(mincid, DICOM_ROOT_VAR, NC_LONG, 0, NULL);
+    miattputstr(mincid, dicomvar, MIvartype, MI_GROUP);
+    miattputstr(mincid, dicomvar, MIvarid, "MNI DICOM variable");
+    miadd_child(mincid, ncvarid(mincid, MIrootvariable), dicomvar);
+    while (cur_group != NULL) {
+
+        /* Create variable for group */
+        sprintf(name, "dicom_0x%04x", acr_get_group_group(cur_group));
+        varid = ncvardef(mincid, name, NC_LONG, 0, NULL);
+        miattputstr(mincid, varid, MIvartype, MI_GROUP);
+        miattputstr(mincid, varid, MIvarid, "MNI DICOM variable");
+        miadd_child(mincid, dicomvar, varid);
+
+        /* Loop through elements of group */
+        cur_element = acr_get_group_element_list(cur_group);
+        while (cur_element != NULL) {
+            sprintf(name, "el_0x%04x", 
+                    acr_get_element_element(cur_element));
+            is_char = TRUE;
+            length = acr_get_element_length(cur_element);
+            data = acr_get_element_data(cur_element);
+            if (data == NULL) {
+                length = 0;
+            }
+            for (ich=0; ich < length; ich++) {
+                if (!isprint((int) data[ich])) {
+                    is_char = FALSE;
+                    break;
+                }
+            }
+            if (is_char)
+                datatype = NC_CHAR;
+            else
+                datatype = NC_BYTE;
+            ncattput(mincid, varid, name, datatype, length, data);
+         
+            cur_element = acr_get_element_next(cur_element);
+        }
+        cur_group = acr_get_group_next(cur_group);
+    }
+
+    /* Create the history attribute */
+    if (G.minc_history != NULL) {
+        miattputstr(mincid, NC_GLOBAL, MIhistory, G.minc_history);
+    }
+
+    return;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : save_minc_image
+   @INPUT      : icvid
+   general_info
+   file_info
+   image
+   @OUTPUT     : (none)
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to save the image in the minc file
+   @METHOD     : 
+   @GLOBALS    : 
+   CALLS       : 
+   @CREATED    : November 26, 1993 (Peter Neelin)
+   @MODIFIED   :
+   ---------------------------------------------------------------------------- */
+void
+save_minc_image(int icvid, General_Info *general_info, 
+                File_Info *file_info, Image_Data *image)
+{
+    int mincid;
+    long start[MAX_VAR_DIMS], count[MAX_VAR_DIMS];
+    int file_index, array_index;
+    int idim;
+    Mri_Index imri;
+    char *dimname;
+    unsigned short pvalue, pmax, pmin;
+    double dvalue, maximum, minimum, scale, offset;
+    long ipix, imagepix;
+
+    /* Get the minc file id */
+    miicv_inqint(icvid, MI_ICV_CDFID, &mincid);
+    
+    /* Create start and count variables */
+    idim = 0;
+    for (imri=MRI_NDIMS-1; (int) imri >= 0; imri--) {
+        if (general_info->image_index[imri] >= 0) {
+            file_index = general_info->image_index[imri];
+            if (general_info->cur_size[imri] > 1) {
+                array_index = search_list(file_info->index[imri], 
+                                          general_info->indices[imri],
+                                          general_info->cur_size[imri],
+                                          general_info->search_start[imri]);
+                if (array_index < 0) array_index = 0;
+                general_info->search_start[imri] = array_index;
+            }
+            else {
+                array_index = 0;
+            }
+            start[file_index] = array_index;
+            count[file_index] = 1;
+            idim++;
+        }
+    }
+    start[idim] = 0;
+    start[idim+1] = 0;
+    count[idim] = general_info->nrows;
+    count[idim+1] = general_info->ncolumns;
+
+    /* Write out slice position */
+    switch (general_info->slice_world) {
+    case XCOORD: dimname = MIxspace; break;
+    case YCOORD: dimname = MIyspace; break;
+    case ZCOORD: dimname = MIzspace; break;
+    default: dimname = MIzspace;
+    }
+    mivarput1(mincid, ncvarid(mincid, dimname), 
+              &start[general_info->image_index[SLICE]], 
+              NC_DOUBLE, NULL, &file_info->coordinate[SLICE]);
+
+    /* Write out time of slice, if needed */
+    if (general_info->cur_size[TIME] > 1) {
+        mivarput1(mincid, ncvarid(mincid, mri_dim_names[TIME]), 
+                  &start[general_info->image_index[TIME]], 
+                  NC_DOUBLE, NULL, &file_info->coordinate[TIME]);
+
+        /* If width information is present, save it to the appropriate
+         * location in the time-width variable.
+         */
+        if (file_info->width[TIME] != 0.0) {
+            int ncopts_prev;
+            int varid;
+
+            /* Since it is possible for width information to be present 
+             * in circumstances where we do not want to save it, the 
+             * time-width variable may not even exist when we get here.
+             * In order to avoid a nasty and unnecessary error message
+             * we have to disable netCDF errors here.
+             */
+            ncopts_prev = ncopts;
+            ncopts = 0;
+            varid = ncvarid(mincid, MItime_width); /* Get the variable id */
+            ncopts = ncopts_prev;
+
+            /* If the variable was created, update it as needed.
+             */
+            if (varid >= 0) {
+                mivarput1(mincid, varid, 
+                          &start[general_info->image_index[TIME]], 
+                          NC_DOUBLE, NULL, &file_info->width[TIME]);
+            }
+        }
+    }
+
+    /* Write out echo time of slice, if needed */
+    if (general_info->cur_size[ECHO] > 1) {
+        mivarput1(mincid, ncvarid(mincid, mri_dim_names[ECHO]), 
+                  &start[general_info->image_index[ECHO]], 
+                  NC_DOUBLE, NULL, &file_info->coordinate[ECHO]);
+    }
+
+    /* Search image for max and min */
+    imagepix = general_info->nrows * general_info->ncolumns;
+    pmax = 0;
+    pmin = USHRT_MAX;
+    for (ipix=0; ipix < imagepix; ipix++) {
+        pvalue = image->data[ipix];
+        if (pvalue > pmax) pmax = pvalue;
+        if (pvalue < pmin) pmin = pvalue;
+    }
+
+    /* Re-scale the images */
+    if (pmax > pmin)
+        scale = (general_info->pixel_max - general_info->pixel_min) /
+            ((double) pmax - (double) pmin);
+    else
+        scale = 0.0;
+
+    offset = general_info->pixel_min - scale * (double) pmin;
+    for (ipix=0; ipix < imagepix; ipix++) {
+        dvalue = image->data[ipix];
+        image->data[ipix] = dvalue * scale + offset;
+    }
+
+    /* Calculate new intensity max and min */
+    if (general_info->pixel_max > general_info->pixel_min)
+        scale = (file_info->slice_max - file_info->slice_min) /
+            (general_info->pixel_max - general_info->pixel_min);
+    else
+        scale = 0.0;
+
+    /* debugging info for slice intensity scaling
+     */
+    if (G.Debug >= HI_LOGGING) {
+        printf("global range: %.2f %.2f  file range: %.2f %.2f pmax: %u\n",
+               general_info->pixel_min,
+               general_info->pixel_max,
+               file_info->slice_min,
+               file_info->slice_max,
+               pmax);
+    }
+
+    offset = file_info->slice_min - scale * general_info->pixel_min;
+    minimum = (double) pmin * scale + offset;
+    maximum = (double) pmax * scale + offset;
+
+    /* Write out the max and min values */
+    mivarput1(mincid, ncvarid(mincid, MIimagemin), start, NC_DOUBLE,
+              NULL, &minimum);
+    mivarput1(mincid, ncvarid(mincid, MIimagemax), start, NC_DOUBLE,
+              NULL, &maximum);
+
+    /* Write out the image */
+    miicv_put(icvid, start, count, image->data);
+
+    return;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+   @NAME       : close_minc_file
+   @INPUT      : icvid - value returned by create_minc_file
+   @OUTPUT     : (none)
+   @RETURNS    : (nothing)
+   @DESCRIPTION: Routine to close the minc file.
+   @METHOD     : 
+   @GLOBALS    : 
+   CALLS       : 
+   @CREATED    : November 30, 1993 (Peter Neelin)
+   @MODIFIED   :
+   ---------------------------------------------------------------------------- */
+void
+close_minc_file(int icvid)
+{
+    int mincid;
+
+    /* Get the minc file id */
+    miicv_inqint(icvid, MI_ICV_CDFID, &mincid);
+
+    /* Write out the complete attribute */
+    miattputstr(mincid, ncvarid(mincid, MIimage), MIcomplete, MI_TRUE);
+
+    /* Close the file */
+    miclose(mincid);
+
+    miicv_free(icvid);
+}
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/minc_file.h
@@ -0,0 +1,11 @@
+extern int create_minc_file(const char *minc_file, 
+                            int clobber, 
+                            General_Info *general_info,
+                            const char *file_prefix, 
+                            char **output_file_name,
+			    Loop_Type loop_type);
+extern void setup_minc_variables(int mincid, General_Info *general_info,
+				 Loop_Type loop_type);
+extern void save_minc_image(int icvid, General_Info *general_info, 
+                            File_Info *file_info, Image_Data *image);
+extern void close_minc_file(int icvid);
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/numaris.txt
@@ -0,0 +1,179 @@
+Some Siemens-specific field definitions I found floating around the net.
+        
+// Identifying group    
+GROUP_LENGTH                    0x0009  0x0000  UL
+PRIVATE_CREATOR                 0x0009  0x0010  LO
+PRIVATE_CREATOR                 0x0009  0x0012  LO
+PRIVATE_CREATOR                 0x0009  0x0013  LO
+COMMENTS                        0x0009  0x1010  LO
+UNIQUE_IDENTIFIER               0x0009  0x1015  LO
+DATA_OBJECT_TYPE                0x0009  0x1040  US
+DATA_OBJECT_SUBTYPE             0x0009  0x1041  SH
+STORAGE_MODE                    0x0009  0x1210  CS
+EVALUATION_MASK_IMAGE           0x0009  0x1212  UL
+TABLE_ZERO_DATE                 0x0009  0x1226  DA
+TABLE_ZERO_TIME                 0x0009  0x1227  TM
+CPU_IDENTIFICATION_LABEL        0x0009  0x1316  LO
+HEADER_VERSION                  0x0009  0x1320  SH
+
+// Patient group    
+GROUP_LENGTH                    0x0011  0x0000  UL
+PRIVATE_CREATOR                 0x0011  0x0010  LO
+PRIVATE_CREATOR                 0x0011  0x0011  LO
+ORGAN                           0x0011  0x1010  LO
+REGISTRATION_DATE               0x0011  0x1110  DA
+REGISTRATION_TIME               0x0011  0x1111  TM
+USED_PATIENT_WEIGHT             0x0011  0x1123  DS
+
+// Acquisition group    
+GROUP_LENGTH                    0x0019  0x0000  UL
+PRIVATE_CREATOR                 0x0019  0x0010  LO
+PRIVATE_CREATOR                 0x0019  0x0012  LO
+PRIVATE_CREATOR                 0x0019  0x0014  LO
+PRIVATE_CREATOR                 0x0019  0x0015  LO
+NET_FREQUENCY                   0x0019  0x1010  IS
+MEASUREMENT_MODE                0x0019  0x1020  CS
+CALCULATION_MODE                0x0019  0x1030  CS
+NOISE_LEVEL                     0x0019  0x1050  IS
+NUMBER_OF_DATABYTES             0x0019  0x1060  IS
+AC_SCALE_VECTOR                 0x0019  0x1070  DS
+AC_ELEMENT_CONNECTED            0x0019  0x1080  LO
+TOTAL_MEASUREMENT_TIME_NOM      0x0019  0x1210  DS
+TOTAL_MEASUREMENT_TIME_CUR      0x0019  0x1211  DS
+START_DELAY_TIME                0x0019  0x1212  DS
+DWELL_TIME                      0x0019  0x1213  DS
+NUMBER_OF_PHASES                0x0019  0x1214  IS
+SEQUENCE_CONTROL_MASK           0x0019  0x1216  UL
+MEASUREMENT_STATUS_MASK         0x0019  0x1218  UL
+FOURIER_LINES_NOM               0x0019  0x1220  IS
+FOURIER_LINES_CUR               0x0019  0x1221  IS
+FOURIER_LINES_AFTER_ZERO        0x0019  0x1226  IS
+FIRST_FOURIER_LINE              0x0019  0x1228  IS
+ACQUISITION_COLUMNS             0x0019  0x1230  IS
+RECONSTRUCTION_COLUMNS          0x0019  0x1231  IS
+AC_ELEMENT_NUMBER               0x0019  0x1240  IS
+AC_ELEMENT_SELECT_MASK          0x0019  0x1241  UL
+AC_ELEMENT_DATA_MASK            0x0019  0x1242  UL
+AC_ELEMENT_TO_ADC_CONNECT       0x0019  0x1243  IS
+AC_ADC_PAIR_NUMBER              0x0019  0x1245  IS
+AC_COMBINATION_MASK             0x0019  0x1246  UL
+NUMBER_OF_AVERAGES              0x0019  0x1250  IS
+FLIP_ANGLE                      0x0019  0x1260  DS
+NUMBER_OF_PRESCANS              0x0019  0x1270  IS
+RAW_DATA_FILTER_TYPE            0x0019  0x1281  CS
+IMAGE_DATA_FILTER_TYPE          0x0019  0x1283  CS
+PHASE_CORRECTION_FILTER_TYPE    0X0019  0x1285  CS
+NORMALIZATION_FILTER_TYPE       0x0019  0x1287  CS
+SATURATION_REGIONS              0x0019  0x1290  IS
+IMAGE_ROTATION_ANGLE            0x0019  0x1294  DS
+COIL_ID_MASK                    0x0019  0x1296  UL
+COIL_CLASS_MASK                 0x0019  0x1297  UL
+COIL_POSITION                   0x0019  0x1298  DS
+MAGNETIC_FIELD_STRENGTH         0x0019  0x1412  DS
+ADC_VOLTAGE                     0x0019  0x1414  DS
+ADC_OFFSET                      0x0019  0x1416  DS
+TRANSMITTER_AMPLITUDE           0x0019  0x1420  DS
+NUMBER_OF_TRANS_AMPS            0x0019  0x1421  IS
+TRANSMITTER_CALIBRATION         0x0019  0x1424  DS
+RECEIVER_AMPLIFIER_GAIN         0x0019  0x1451  DS
+RECEIVER_PREAMP_GAIN            0x0019  0x1452  DS
+PHASE_GRADIENT_AMPLITUDE        0x0019  0x1470  DS
+READOUT_GRADIENT_AMPLITUDE      0x0019  0x1471  DS
+SELECTION_GRADIENT_AMPLITUDE    0x0019  0x1472  DS
+GRADIENT_DELAY_TIME             0x0019  0x1480  DS
+TOTAL_GRADIENT_DELAY_TIME       0x0019  0x1482  DS
+SENSITIVITY_CORRECTION_LABEL    0x0019  0x1490  LO
+RF_WATCHDOG_MASK                0x0019  0x14a0  IS
+RF_POWER_ERROR_INDICATOR        0x0019  0x14a2  DS
+SPECIFIC_ABSORPTION_RATE        0x0019  0x14a5  DS
+SPECIFIC_ENERGY_DOSE            0x0019  0x14a6  DS
+ADJUSTMENT_STATUS_MASK          0x0019  0x14b0  UL
+FLOW_SENSITIVITY                0x0019  0x14d1  DS
+CALCULATION_SUBMODE             0x0019  0x14d2  CS
+FIELD_OF_VIEW_RATIO             0x0019  0x14d3  DS
+BASE_RAW_MATRIX_SIZE            0x0019  0x14d4  IS
+2D_PHASE_OVERSAMPLING_LINES     0x0019  0x14d5  IS
+2D_PHASE_OVERSAMPLING_PART      0x0019  0x14d6  IS
+ECHO_LINE_POSITION              0x0019  0x14d7  IS
+ECHO_COLUMN_POSITION            0x0019  0x14d8  IS
+LINES_PER_SEGMENT               0x0019  0x14d9  IS
+PHASE_CODING_DIRECTION          0x0019  0x14da  CS
+PARAMETER_FILE_NAME             0x0019  0x1510  LO
+SEQUENCE_FILE_NAME              0x0019  0x1511  LO
+SEQUENCE_FILE_OWNER             0x0019  0x1512  LO
+SEQUENCE_DESCRIPTION            0x0019  0x1513  LO
+
+// Relationship group
+GROUP_LENGTH                    0x0021  0x0000  UL
+PRIVATE_CREATOR                 0x0021  0x0010  LO
+PRIVATE_CREATOR                 0x0021  0x0011  LO
+PRIVATE_CREATOR                 0x0021  0x0013  LO
+PRIVATE_CREATOR                 0x0021  0x0023  LO
+ZOOM                            0x0021  0x1010  DS
+TARGET                          0x0021  0x1011  DS
+ROI_MASK                        0x0021  0x1020  US
+FIELD_OF_VIEW                   0x0021  0x1120  DS
+IMAGE_MAGNIFICATION_FACTOR      0x0021  0x1122  DS
+IMAGE_SCROLL_OFFSET             0x0021  0x1124  DS
+IMAGE_PIXEL_OFFSET              0x0021  0x1126  IS
+VIEW_DIRECTION                  0x0021  0x1130  CS
+REST_DIRECTION                  0x0021  0x1132  CS
+IMAGE_POSITION                  0x0021  0x1160  DS
+IMAGE_NORMAL                    0x0021  0x1161  DS
+IMAGE_DISTANCE                  0x0021  0x1163  DS
+IMAGE_POSITIONING_HISTORY_MASK  0x0021  0x1165  US
+IMAGE_ROW                       0x0021  0x116a  DS
+IMAGE_COLUMN                    0x0021  0x116b  DS
+PATIENT_ORIENTATION_SET_1       0x0021  0x1170  CS
+PATIENT_ORIENTATION_SET_2       0x0021  0x1171  CS
+STUDY_TYPE                      0x0021  0x1182  SH
+PHASE_COR_ROW_SEQ               0x0021  0x1320	IS
+PHASE_COR_COL_SEQ               0x0021  0x1321  IS
+PHASE_CORRECTION_ROWS           0x0021  0x1322  IS
+PHASE_CORRECTION_COLUMNS        0x0021  0x1324  IS
+3D_RAW_PARTITIONS_NOMINAL       0x0021  0x1330  IS
+3D_RAW_PARTITIONS_CURRENT       0x0021  0x1331  IS
+IMAGE_PARTITIONS                0x0021  0x1334  IS
+PARTITION_NUMBER                0x0021  0x1336  IS
+SLAB_THICKNESS                  0x0021  0x1339  DS
+NUMBER_OF_SLICES_NOMINAL        0x0021  0x1340  IS
+NUMBER_OF_SLICES_CURRENT        0x0021  0x1341  IS
+CURRENT_SLICE_NUMBER            0x0021  0x1342  IS
+CURRENT_GROUP_NUMBER            0x0021  0x1343  IS
+CURRENT_SLICE_DISTANCE_FACTOR   0x0021  0x1344  DS
+ORDER_OF_SLICES                 0x0021  0x134f  ST
+SIGNAL_MASK                     0x0021  0x1350  IS
+EFFECTIVE_REPETITION_TIME       0x0021  0x1356  DS
+NUMBER_OF_ECHOES                0x0021  0x1370  IS
+SEQUENCE_TYPE                   0x0021  0x2300  CS
+VECTOR_SIZE_ORIGINAL            0x0021  0x2301  IS
+VECTOR_SIZE_EXTENDED            0x0021  0x2302  IS
+ACQUIRED_SPECTRAL_RANGE         0x0021  0x2303  DS
+VOI_POSITION                    0x0021  0x2304  DS
+VOI_SIZE                        0x0021  0x2305  DS
+CSI_MATRIX_SIZE_ORIGINAL        0x0021  0x2306  IS
+CSI_MATRIX_SIZE_EXTENDED        0x0021  0x2307  IS
+SPATIAL_GRID_SHIFT              0x0021  0x2308  DS
+SIGNAL_LIMITS_MINIMUM           0x0021  0x2309  DS
+SIGNAL_LIMITS_MAXIMUM           0x0021  0x2310  DS
+SPECTROSCOPY_INFO_MASK          0x0021  0x2311  IS
+AC_ADC_OFFSET                   0x0021  0x2330  DS
+AC_PREAMPLIFIER_GAIN            0x0021  0x2331  DS
+
+//  Image presentation group
+GROUP_LENGTH                    0x0029  0x0000  UL
+PRIVATE_CREATOR                 0x0029  0x0010  LO
+PRIVATE_CREATOR                 0x0029  0x0011  LO
+PRIVATE_CREATOR                 0x0029  0x0012  LO
+WINDOW_STYLE                    0x0029  0x1110  CS
+PIXEL_QUALITY_CODE              0x0029  0x1120  CS
+SORT_CODE                       0x0029  0x1152  IS
+PMTF_INFORMATION_1		0x0029  0x1131  LO
+PMTF_INFORMATION_2		0x0029  0x1132  UL
+PMTF_INFORMATION_3		0x0029  0x1133  UL
+PMTF_INFORMATION_4		0x0029  0x1134  CS
+
+// Device group
+GROUP_LENGTH                    0x0051  0x0000  UL
+PRIVATE_CREATOR                 0x0051  0x0010  LO
+IMAGE_TEXT                      0x0051  0x1010  LO
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/pms_element_defs.h
@@ -0,0 +1,85 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : pms_element_defs.h
+@DESCRIPTION: Element definitions for Philips Medical Systems (no, really)
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 11, 2005
+@MODIFIED   : 
+@COPYRIGHT  :
+              Copyright (C) 2005 Robert D. Vincent, 
+              McConnell Brain Imaging Centre,
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* This information was derived from the publically available "DICOM
+ * Conformance Statement" for the Philips Medical Systems MR Intera
+ * 10.1, 10 April 2003.
+ * 
+ * However, not all Philips scanners use the fixed element numbers
+ * implied here.  The upper eight bits of the element ID's are not
+ * entirely deterministic.  It is necessary to root around in the
+ * image for the private groups.
+ */
+
+#define PMS_PRIVATE_GROUP_ID 0x2001
+
+GLOBAL_ELEMENT(PMS_Chemical_Shift                     , 0x2001, 0x1001, FL);
+GLOBAL_ELEMENT(PMS_Chemical_Shift_Number_MR           , 0x2001, 0x1002, IS);
+GLOBAL_ELEMENT(PMS_Diffusion_B_Factor                 , 0x2001, 0x1003, FL);
+GLOBAL_ELEMENT(PMS_Diffusion_Direction                , 0x2001, 0x1004, CS);
+GLOBAL_ELEMENT(PMS_Image_Enhanced                     , 0x2001, 0x1006, CS);
+GLOBAL_ELEMENT(PMS_Image_Type_ED_ES                   , 0x2001, 0x1007, CS);
+GLOBAL_ELEMENT(PMS_Phase_number                       , 0x2001, 0x1008, IS);
+/* xx09 is present but not defined */
+GLOBAL_ELEMENT(PMS_Slice_Number_MR, /* Slice index in series */
+               0x2001, 0x100a, IS);
+GLOBAL_ELEMENT(PMS_Slice_Orientation, /* SAGITTAL, TRANSVERSAL, e.g. */
+               0x2001, 0x100b, CS);
+/* xx0c, xx0e, xx0f, xx10 are present but not defined */
+GLOBAL_ELEMENT(PMS_Diffusion_Echo_Time                , 0x2001, 0x1011, FL);
+GLOBAL_ELEMENT(PMS_Dynamic_Series                     , 0x2001, 0x1012, CS);
+GLOBAL_ELEMENT(PMS_EPI_Factor                         , 0x2001, 0x1013, SL);
+GLOBAL_ELEMENT(PMS_Number_of_Echoes                   , 0x2001, 0x1014, SL);
+GLOBAL_ELEMENT(PMS_Number_of_Locations                , 0x2001, 0x1015, SS);
+GLOBAL_ELEMENT(PMS_Number_of_PC_Locations             , 0x2001, 0x1016, SS);
+GLOBAL_ELEMENT(PMS_Number_of_Phases_MR                , 0x2001, 0x1017, SL);
+GLOBAL_ELEMENT(PMS_Number_of_Slices_MR                , 0x2001, 0x1018, SL);
+GLOBAL_ELEMENT(PMS_Partial_Matrix_Scanned             , 0x2001, 0x1019, CS);
+GLOBAL_ELEMENT(PMS_PC_Velocity                        , 0x2001, 0x101a, FL);
+GLOBAL_ELEMENT(PMS_Prepulse_Delay                     , 0x2001, 0x101b, FL);
+GLOBAL_ELEMENT(PMS_Prepulse_Type                      , 0x2001, 0x101c, CS);
+GLOBAL_ELEMENT(PMS_Reconstruction_Number              , 0x2001, 0x101d, IS);
+/* xx1e is present but not defined */
+GLOBAL_ELEMENT(PMS_Respiration_Sync                   , 0x2001, 0x101f, CS);
+GLOBAL_ELEMENT(PMS_Scanning_Technique_Description_MR  , 0x2001, 0x1020, CS);
+GLOBAL_ELEMENT(PMS_SPIR                               , 0x2001, 0x1021, CS);
+GLOBAL_ELEMENT(PMS_Water_Fat_Shift                    , 0x2001, 0x1022, FL);
+/* xx23 xx24 both present but undefined 
+   xx23 appears to be the flip angle, as in DICOM (0018,1314)
+ */
+GLOBAL_ELEMENT(PMS_Echo_Time_Display                  , 0x2001, 0x1025, SH);
+GLOBAL_ELEMENT(PMS_Number_of_Stack_Slices             , 0x2001, 0x102d, SS);
+GLOBAL_ELEMENT(PMS_Stack_Radial_Angle                 , 0x2001, 0x1032, FL);
+GLOBAL_ELEMENT(PMS_Stack_Radial_Axis                  , 0x2001, 0x1033, CS);
+GLOBAL_ELEMENT(PMS_Stack_Slice_Number                 , 0x2001, 0x1035, SS);
+GLOBAL_ELEMENT(PMS_Stack_Type                         , 0x2001, 0x1036, CS);
+/* xx52, xx5f both present but undefined */
+GLOBAL_ELEMENT(PMS_Number_of_Stacks                   , 0x2001, 0x1060, SL);
+GLOBAL_ELEMENT(PMS_Examination_Source                 , 0x2001, 0x1063, CS);
+
+/* additional undefined elements include:
+   xx60-xx62, xx6e, xx7b, xx81-xx8b, 9000
+
+   xx83 appears to be the imaging frequency, as in DICOM (0018,0084)
+   
+ */
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/progress.c
@@ -0,0 +1,55 @@
+
+// This function prints a text progress bar within a term window
+// Input arguments assume a for loop starting at zero:
+//
+//      for (index =  0; index < end; index++) { ...
+
+static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/progress.c,v 1.2.2.1 2005-05-12 21:16:48 bert Exp $";
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "progress.h"
+
+void
+progress(long index, int end, const char *message)
+{
+    int ix;
+    const int width = 50;
+    int nchars;
+
+    if (index == 0) {
+        printf("%-20.20s |<--", message);
+        for (ix = 0; ix < width; ix++) { 
+            printf(" ");
+        }
+        printf("|");
+        for (ix = 0; ix < width+1; ix++) { 
+            printf("\b");
+        }
+    } 
+    else if ((index > 0) && (index < end)) {
+
+        nchars = (((float)index/(float)(end-1)) * width) - 
+            floor(((float)(index-1)/(float)(end-1)) * width);
+
+        for (ix = 0; ix < nchars; ix++) {
+            printf("\b->");
+            fflush(stdout);
+        }
+
+        // print terminating newline at end if we're done
+        if (index == end-1) {
+            printf("\n");
+        }
+    } 
+    else {
+        fprintf(stderr,"PROGRESS:  bad input indices!\n");
+    }
+}
+
+
+
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/progress.h
@@ -0,0 +1,1 @@
+extern void progress(long index, int end, const char *message);
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/siemens_header_defs.h
@@ -0,0 +1,491 @@
+#ifndef _SIEMENS_HEADER_DEFS_H_
+#define _SIEMENS_HEADER_DEFS_H_ 1
+
+/* CONSTANTS */
+
+#define N_STRING 26
+#define N_AGE 4
+#define N_DIAGNOSIS 40
+#define N_NUCLEUS 8
+#define N_MANUFACTURER 8
+#define N_ORIENTATION 3
+#define N_PATIENTID 12
+#define N_SWVERSION 8
+
+typedef double flt64_t;
+
+/* ACR-NEMA specific types */
+
+/* Analogous to DICOM field (0028, 0030) */
+typedef struct pixel_spacing
+{
+    flt64_t row;
+    flt64_t col;
+} pixel_spacing_t;
+
+/* Analogous to DICOM fields (0028, 1050) and (0028, 1051) */
+typedef struct window
+{
+    int32_t x;
+    int32_t y;
+} window_t;
+
+/* IMA specific types */
+typedef struct ima_date
+{
+    int32_t year;               /* Full year including century */
+    int32_t month;              /* Month from 1(Jan) to 12(Dec) */
+    int32_t day;                /* Day of month from 1 to 31 */
+} ima_date_t;
+
+typedef struct ima_time
+{
+    int32_t hour;               /* Hour from 0 to 23 */
+    int32_t minute;             /* Minute from 0 to 59 */
+    int32_t second;             /* Second from 0 to 59 */
+    int32_t msec;               /* Milliseconds from 0 to 999 */
+} ima_time_t;
+
+typedef struct ima_vector
+{
+    flt64_t x;
+    flt64_t y;
+    flt64_t z;
+} ima_vector_t;
+
+typedef enum ima_slice_order
+{
+    SO_ASCENDING = 1,
+    SO_DESCENDING = 2,
+    SO_FREE = 3,
+    SO_INTERLEAVED = 4,
+    SO_NONE = 5
+} ima_slice_order_t;
+
+typedef enum ima_position
+{
+    PP_LEFT = 1,
+    PP_PRONE = 2,
+    PP_RIGHT = 3,
+    PP_SUPINE = 4,
+} ima_position_t;
+
+typedef enum
+{
+    RD_FEET = 1,
+    RD_HEAD = 2
+} ima_rest_direction_t;
+
+typedef enum
+{
+    VD_FEET = 1,
+    VD_HEAD = 2,
+    VD_AtoP = 3,
+    VD_LtoR = 4,
+    VD_PtoA = 5,
+    VD_RtoL = 6
+} ima_view_direction_t;
+
+typedef struct
+{
+    flt64_t height;
+    flt64_t width;
+} ima_field_of_view_t;
+
+typedef struct
+{
+    char y[N_ORIENTATION + 1]; /* up - down */
+    char x[N_ORIENTATION + 1]; /* left - right */
+    char z[N_ORIENTATION + 1]; /* back - front */
+} ima_orientation_t;
+
+/*
+ * Identifying information group 0x0008 
+ */
+struct ima_acr_0008             /* Item# FOffs SOffs */
+{
+    ima_date_t StudyDate;       /* 0020  0000 */
+    ima_date_t AcquisitionDate; /* 0022  000C */
+    ima_date_t ContentDate;     /* 0023  0018 */
+    ima_time_t StudyTime;       /* 0030  0024 */
+    ima_time_t AcquisitionTime; /* 0032  0034 */
+    ima_time_t ContentTime;     /* 0033  0044 */
+    char pad1[8];
+    int32_t Modality;           /* 0060   005C */
+    char Manufacturer[N_MANUFACTURER + 1]; /* 0070  0060  */
+    char InstitutionName[N_STRING + 1]; /* 0080 0069 */
+    char PhysicianName[N_STRING + 1]; /* 0090  0084 */
+    char StationName[N_STRING + 1]; /* 1010  009F */
+    char StudyDescription[N_STRING + 1]; /* 1030  00BA */
+    char pad2[N_STRING + 1];
+    char AdmittingDiagnoses[N_DIAGNOSIS + 1]; /* 1080  00F0 */
+    char ModelName[N_STRING + 1]; /* 1090  0119 */
+    char pad3[76];
+};
+
+
+/*
+ * Patient information group 0x0010
+ */
+struct ima_acr_0010             /* Item# FOffs SOffs */
+{
+    char PatientName[N_STRING + 1]; /* 0010  0300 */
+    char PatientID[N_PATIENTID + 1]; /* 0020  031B */
+    ima_date_t PatientDOB;      /* 0030  0328 */
+    int32_t PatientSex;         /* 0040  0334 */
+    char PatientBirthName[N_STRING + 1]; /* 1005  0338 */
+    char PatientAge[N_AGE + 1]; /* 1010  0353 */
+    flt64_t PatientSize;        /* 1020  0358 */
+    int32_t PatientWeight;      /* 1030  0360 */
+    char pad1[156];
+};
+
+/*
+ * Acquisition information group 0x0018
+ */
+struct ima_acr_0018
+{                               /* Item# FOffs SOffs */
+    char pad1[8];               /* Dummy padding */
+    flt64_t SliceThickness;     /* 0050  0608 */
+    char pad2[8];
+    flt64_t RepetitionTime;     /* 0080  0618 */
+    flt64_t EchoTime;           /* 0081  0620 */
+    flt64_t InversionTime;      /* 0082  0628 */
+    int32_t NumberOfAverages;   /* 0083  0630 */
+    char pad3[4];               /* Dummy padding */
+    flt64_t ImagingFrequency;   /* 0084  0638 */
+    char pad4[4];               /* 0085  0640 */
+    int32_t EchoNumber;         /* 0086  0644 */
+    int32_t DataCollectionDiameter; /* 0090  0648 */
+    char SerialNumber[N_STRING + 1]; /* 1000  064C */
+    char SoftwareVersion[N_SWVERSION + 1]; /* 1020 0667 */
+    char pad5[61];               /* Dummy padding */
+    ima_date_t CalibrationDate;  /* 1200  06B0 */
+    ima_time_t CalibrationTime;  /* 1201  06BC */
+    char pad6[N_STRING + 1];
+    char ReceiveCoilName[N_STRING + 1]; /* 1250  06E7 */
+    char pad7[N_STRING + 1];
+    ima_position_t PatientPosition; /* 5100  0720 */
+    char ImagedNucleus[N_NUCLEUS + 1]; /* 0085  0724 */
+    char pad8[80];              /* Pad to 384 bytes */
+};
+
+/*
+ * Relationship information group 0x0020
+ */
+struct ima_acr_0020
+{                               /* Item# FOffs */
+    int32_t StudyID;            /* 0010  0C80 */
+    char pad1[4];               /*  */
+    int32_t AcquisitionNumber;  /* 0012  0C88 */
+    int32_t InstanceNumber;     /* 0013  0C8C */
+    int32_t ImagePosition[3];   /* 0030  0C90 */
+    char pad2[4];               /* Dummy padding */
+    flt64_t ImageOrientation[6]; /* 0035  0C94 */
+    int32_t Location;           /* 0050  0CD0 */
+    int32_t Laterality;         /* 0060  0CD4 */
+    char pad3[4];
+    int32_t AcquisitionsInSeries; /* 1001  0CDC */
+    char pad4[416];             /* Pad to 512 bytes */
+};
+
+/*
+ * Image presentation Information group 0x0028
+ */
+struct ima_acr_0028
+{                               /* Item# FOffs */
+    int16_t ImageDimension;     /* 0005  1380 */
+    int16_t Rows;               /* 0010  1382 */
+    int16_t Columns;            /* 0011  1384 */
+    char pad1[2];
+    pixel_spacing_t PixelSpacing; /* 0030  1388 */
+    char pad2[8];
+    int16_t BitsAllocated;      /* 0100  13A0 */
+    int16_t BitsStored;         /* 0101  13A2 */
+    int16_t HighBit;            /* 0102  13A4 */
+    int16_t PixelRepresentation; /* 0103  13A6 */
+    window_t WindowCenter;      /* 1050  13A8 */
+    window_t WindowWidth;       /* 1051  13B0 */
+    int32_t RescaleIntercept;   /* 1052  13B8 */
+    int32_t RescaleSlope;       /* 1053  13BC */
+    char pad3[192];             /* Pad to 256 bytes */
+};
+
+/***** Siemens private group structures *****/
+
+/*
+ * Siemens acquisition group 0x0019 
+ */
+struct ima_siemens_0019
+{
+    char pad1[20];              /* Padding */
+    int32_t NumberOfDataBytes;  /* 1060 */
+    char pad2[140];
+    int32_t FourierLinesNominal; /* 1220 */
+    char pad3[4];
+    int32_t FourierLinesAfterZero; /* 1226 */
+    int32_t FirstMeasuredFourierLine; /* 1228 */
+    int32_t AcquisitionColumns; /* 1230 */
+    int32_t ReconstructionColumns; /* 1231 */
+    int32_t NumberOfAverages;   /* 1250 */
+    flt64_t FlipAngle;          /* 1260 */
+    int32_t NumberOfPrescans;   /* 1270 */
+    char pad4[116];             /* Dummy padding */
+    int32_t SaturationRegions;  /* 1290 */
+    char pad5[316];             /* Dummy padding */
+    flt64_t MagneticFieldStrength; /* 1412 */
+    char pad6[631];             /* Dummy padding */
+};
+
+/*
+ * Siemens Relationship group 0x0021
+ */ 
+struct ima_siemens_0021
+{
+    char pad1[32];              /* Dummy padding */
+    ima_field_of_view_t FieldOfView;    /* 1120  0EA0 */
+    ima_view_direction_t ViewDirection; /* 1130  0EB0 */
+    ima_rest_direction_t RestDirection; /* 1132  0EB4 */
+    ima_vector_t ImagePosition; /* 1160  0EB8 */
+    ima_vector_t ImageNormal;   /* 1161  0ED0 */
+    flt64_t ImageDistance;      /* 1163  0EE8 */
+    char pad3[8];               /* Dummy padding */
+    ima_vector_t ImageRow;      /* 116A  0EF8 */
+    ima_vector_t ImageColumn;   /* 116B 0F10 */
+    ima_orientation_t OrientationSet1; /* 1170 0F28 */
+    ima_orientation_t OrientationSet2; /* 1171 0F34 */
+    char StudyName[N_STRING + 1]; /* 1180 0F40 */
+    int32_t StudyType;          /* 1182 */
+    flt64_t ImageMagnificationFactor; /* 1122 */
+    char pad4[40];
+    int32_t NumberOf3DRawPartNom; /* 1330 */
+    int32_t NumberOf3DRawPartCur; /* 1331 */
+    int32_t NumberOf3DImaPart;  /* 1334 */
+    int32_t Actual3DImaPartNumber; /* 1336 */
+    char pad5[4];
+    int32_t NumberOfSlicesNom;  /* 1340 */
+    int32_t NumberOfSlicesCur;  /* 1341 */
+    int32_t CurrentSliceNumber; /* 1342 */
+    int32_t CurrentGroupNumber; /* 1343 */
+    char pad7[88];              /* Dummy padding */
+    int32_t NumberOfEchoes;     /* 1370 */
+    char pad9[32];              /* Dummy padding */
+    ima_slice_order_t SliceOrder; /* 134F */
+    char pad10[4];              /* Dummy padding */
+    flt64_t SlabThickness;      /* 1339 */
+    char pad11[829];            /* Padding */
+};
+
+/* this is a work in progress, based on David Clunie's website */
+
+#define PATIENT_NUMBER_SIZE 12
+#define PATIENT_DATE_SIZE 11
+#define PATIENT_POSITION_SIZE 11
+#define IMAGE_NUMBER_SIZE 11
+#define IMAGE_NUMBER_TEXT "IMAGE"
+#define LABEL_SIZE 5
+#define DATE_OF_MEASUREMENT_SIZE 11
+#define TIME_OF_MEASUREMENT_SIZE 5
+#define TIME_OF_ACQUISITION_SIZE 11
+#define TIME_OF_ACQUISITION_TEXT_CT "TI"
+#define TIME_OF_ACQUISITION_TEXT_MR "TA "
+#define NUMBER_OF_ACQUISITIONS_SIZE 11
+#define NUMBER_OF_ACQUISITIONS_TEXT "AC"
+#define COMMENT_NO1_SIZE 26
+#define COMMENT_NO2_SIZE 26
+#define INSTALLATION_NAME_SIZE 26
+#define SOFTWARE_VERSION_SIZE 11
+#define MATRIX_SIZE 11
+#define TYPE_OF_MEASUREMENT_SIZE 11
+#define SCAN_NUMBER_SIZE 11
+#define SCAN_NUMBER_TEXT "SCAN"
+#define REPETITION_TIME_SIZE 11
+#define REPETITION_TIME_TEXT "TR"
+#define ECHO_TIME_SIZE 11
+#define ECHO_TIME_TEXT "TE"
+#define GATING_AND_TRIGGER_SIZE 11
+#define GATING_AND_TRIGGER_TEXT "TD"
+#define TUBE_CURRENT_SIZE 11
+#define TUBE_CURRENT_TEXT "mA"
+#define TUBE_VOLTAGE_SIZE 11
+#define TUBE_VOLTAGE_TEXT "kV"
+#define SLICE_THICKNESS_SIZE 11
+#define SLICE_THICKNESS_TEXT "SL"
+#define SLICE_POSITION_SIZE 11
+#define SLICE_POSITION_TEXT "SP"
+#define SLICE_ORIENTATION_NO1_SIZE 11
+#define SLICE_ORIENTATION_NO2_SIZE SLICE_ORIENTATION_NO1_SIZE
+#define COR_TEXT "Cor"
+#define SAG_TEXT "Sag"
+#define TRA_TEXT "Tra"
+#define FIELD_OF_VIEW_SIZE 11
+#define FIELD_OF_VIEW_TEXT "FoV"
+#define ZOOM_CENTER_SIZE 11
+#define ZOOM_CENTER_TEXT "CE"
+#define ZOOM_CENTER_TEXT_MR "MF"
+#define GANTRY_TILT_SIZE 11
+#define GANTRY_TILT_TEXT "GT"
+#define TABLE_POSITION_SIZE 11
+#define TABLE_POSITION_TEXT "TP"
+#define MIP_HEADLINE_SIZE 3
+#define MIP_HEADLINE_TEXT "VOI"
+#define MIP_LINE_SIZE 15
+#define MIP_LINE_TEXT "Lin"
+#define MIP_COLUMN_SIZE 15
+#define MIP_COLUMN_TEXT "Col"
+#define MIP_SLICE_SIZE 15
+#define MIP_SLICE_TEXT "Sli"
+#define STUDY_NUMBER_SIZE 11
+#define STUDY_NUMBER_TEXT "STUDY"
+#define CONTRAST_SIZE 5
+#define CONTRAST_TEXT_CT "+C IV"
+#define CONTRAST_TEXT_MR "+C   "
+#define CONTRAST_TEXT_NONE "     "
+#define PATIENT_BIRTHDATE_SIZE 11
+#define SEQUENCE_INFO_SIZE 11
+#define SATURATION_REGIONS_SIZE 11
+#define SATURATION_REGIONS_TEXT "SAT"
+#define DATA_SET_ID_SIZE 26
+#define DATA_SET_ID_TEXT_STUDY "STU"
+#define DATA_SET_ID_TEXT_IMAGE "IMA"
+#define DATA_SET_ID_TEXT_DELIMITER "/"
+#define MAGNIFICATION_FACTOR_SIZE 11
+#define MAGNIFICATION_FACTOR_TEXT "MF"
+#define MANUFACTURER_MODEL_SIZE 26
+#define PATIENT_NAME_SIZE 26
+#define TIME_OF_SCANNING_SIZE 8
+
+typedef struct text_info
+{
+    char PatientNumber[PATIENT_NUMBER_SIZE + 1]; /* Patient Id */
+    char PatientSexAndAge[PATIENT_DATE_SIZE + 1]; /* Patient Sex, Patient Age */
+    char PatientPosition[PATIENT_POSITION_SIZE + 1]; /* Patient Rest Direction, ... */
+    char ImageNumber[IMAGE_NUMBER_SIZE + 1]; /* Image */
+    char Label[LABEL_SIZE + 1]; /* Archiving Mark Mask, ... */
+    char DateOfMeasurement[DATE_OF_MEASUREMENT_SIZE + 1]; /* Acquisition Date */
+    char TimeOfMeasurement[TIME_OF_MEASUREMENT_SIZE + 1]; /* Acquisition Time */
+    char TimeOfAcquisition[TIME_OF_ACQUISITION_SIZE + 1]; /* CT: Exposure Time MR:
+                                                             Total Measurement Time */
+    char NumberOfAcquisitions[NUMBER_OF_ACQUISITIONS_SIZE + 1]; /* Number of Averages */
+    char CommentNo1[COMMENT_NO1_SIZE + 1]; /* Procedure Description */
+    char CommentNo2[COMMENT_NO2_SIZE + 1];
+    char InstallationName[INSTALLATION_NAME_SIZE + 1]; /* Institution ID */
+    char SoftwareVersion[SOFTWARE_VERSION_SIZE + 1]; /* Software Version */
+    char Matrix[MATRIX_SIZE + 1]; /* Rows, Columns */
+    char TypeOfMeasurement[TYPE_OF_MEASUREMENT_SIZE + 1]; /* Calculation Mode */
+    char ScanNumber[SCAN_NUMBER_SIZE + 1]; /* Acquisition */
+    char RepetitionTime[REPETITION_TIME_SIZE + 1]; /* Repetition Time */
+    char EchoTime[ECHO_TIME_SIZE + 1]; /* Echo Time */
+    char GatingAndTrigger[GATING_AND_TRIGGER_SIZE + 1]; /* Signal Mask */
+    char TubeCurrent[TUBE_CURRENT_SIZE + 1]; /* Exposure */
+    char TubeVoltage[TUBE_VOLTAGE_SIZE + 1]; /* Generator Power */
+    char SliceThickness[SLICE_THICKNESS_SIZE + 1];	   /* Slice Thickness */
+    char SlicePosition[SLICE_POSITION_SIZE + 1]; /* Image Distance */
+    char SliceOrientationNo1[SLICE_ORIENTATION_NO1_SIZE + 1]; /* Image Position, ... */
+    char SliceOrientationNo2[SLICE_ORIENTATION_NO2_SIZE + 1];
+    char FieldOfView[FIELD_OF_VIEW_SIZE + 1]; /* Field of View */
+    char ZoomCenter[ZOOM_CENTER_SIZE + 1]; /* Target */
+    char GantryTilt[GANTRY_TILT_SIZE + 1]; /* Gantry Tilt */
+    char TablePosition[TABLE_POSITION_SIZE + 1]; /* Location */
+    char MipHeadLine[MIP_HEADLINE_SIZE + 1]; /* <string> */
+    char MipLine[MIP_LINE_SIZE + 1]; /* MIP x Row */
+    char MipColumn[MIP_COLUMN_SIZE + 1]; /* MIP x Column */
+    char MipSlice[MIP_SLICE_SIZE + 1]; /* MIP x Slice */
+    char StudyNumber[STUDY_NUMBER_SIZE + 1]; /* Study */
+    char Contrast[CONTRAST_SIZE + 1]; /* Contrast Agent */
+    char PatientBirthdate[PATIENT_BIRTHDATE_SIZE + 1]; /* Patient Birthday */
+    char SequenceInformation[SEQUENCE_INFO_SIZE + 1]; /* Sequence File Owner, ... */
+    char SaturationRegions[SATURATION_REGIONS_SIZE + 1]; /* Saturation Regions, ... */
+    char DataSetId[DATA_SET_ID_SIZE + 1]; /* Image, Study */
+    char MagnificationFactor[MAGNIFICATION_FACTOR_SIZE + 1]; /* Image Maginification Factor */
+    char ManufacturerModel[MANUFACTURER_MODEL_SIZE + 1]; /* Manufacturer Model */
+    char PatientName[PATIENT_NAME_SIZE + 1]; /* Patient Name */
+    char TimeOfScanning[TIME_OF_SCANNING_SIZE + 1]; /* Acquisition Time */
+} text_info_t;
+
+#if 0
+struct text_info {
+    char PatientID[12+1];       /* 5504 */
+    char PatientSex[1];         /* 5517 */
+    char PatientAge[3];         /* 5518 */
+    char PatientAgeUnits[1];    /* 5521 */
+    char pad1[7];               /* 5522 */
+    char PatientPosition[12];   /* 5529 */
+    char ImageNumberFlag[5];    /* 5541 */
+    char ImageNumber[3];        /* 5546 */
+    char pad2[10];              /* 5551 */
+    char Date[11+1];            /* 5559 */
+    char Time[5+1];             /* 5571 */
+    char AcquisitionTimeFlag[6]; /* 5577 */
+    char AcquisitionTime[5+1];  /* 5583 */
+    char AcquisitionCountFlag[6]; /* 5589 */
+    char AcquisitionCount[5+1]; /* 5595 */
+    char Annotation[27];         /* 5601 */
+    char AdmittingDiagnosis[27]; /* 5628 */
+    char Organization[27];      /* 5655 */
+    char Station[12];           /* 5682 */
+    char AcquisitionMatrixPhase[3]; /* 5695 */
+    char AcquisitionMatrixPhaseAxis[1];
+    char AcquisitionMatrixFreq[3];
+    char AcquisitionMatrixFreq0[1];
+    char AcquisitionMatrixFreqS[1];
+    char Sequence[8];
+    char FlipAngle[3];
+    char ScanNumberFlag[4];
+    char ScanNumberA[3];
+    char ScanNumberB[3];
+    char RepetitionTimeFlag[2];
+    char RepetitionTime[7];
+    char EchoTimeFlag[2];
+    char EchoTime[5];
+    char EchoNumber[1];
+    char SliceThicknessFlag[2];
+    char SliceThickness[7];
+    char SlicePositionFlag[2];
+    char SlicePosition[7];
+    char AngleFlag1[3];
+    char AngleFlag2[1];
+    char AngleFlag3[3];
+    char Angle[4];
+    char FOVFlag[3];
+    char FOVH[3];
+    char FOVV[3];
+    char TablePositionFlag[2];
+    char TablePosition[7];
+    char StudyNumberFlag[5];
+    char StudyNumber[2];
+    char DOBDD[2];
+    char DOBMM[3];
+    char DOBYYYY[4];
+    char StudyNumberFlag2[3];
+    char ImageNumberFlag2[3];
+    char StudyNumber2[2];
+    char ImageNumber2[2];
+    char StudyImageNumber3[5];
+    char ModelName[15];
+    char PatientName[27];       /* 6058 */
+    char ScanStartTimeHH[3];    /* 6085 */
+    char ScanStartTimeMM[3];    /* 6088 */
+    char ScanStartTimeSS[3];    /* 6091 */
+};
+#endif
+
+/* Siemens IMA header - total size is 0x1800 bytes */
+
+typedef struct
+{                               /* Offset - Description */
+    struct ima_acr_0008 G08;    /* 0x0000 - Identifying Information */
+    char G09[0x0180];           /* 0x0180 - Siemens specific */
+    struct ima_acr_0010 G10;    /* 0x0300 - Patient Information */
+    char G11[0x0080];           /* 0x0400 - Siemens specific */
+    char G13[0x0180];           /* 0x0480 - Siemens specific */
+    struct ima_acr_0018 G18;    /* 0x0600 - Acquisition Information */
+    struct ima_siemens_0019 G19; /* 0x0780 - Siemens specific */
+    struct ima_acr_0020 G20;   /* 0x0C80 - Relationship Information */
+    struct ima_siemens_0021 G21;    /* 0x0E80 - Siemens specific */
+    struct ima_acr_0028 G28; /* 0x1380 - Image Presentation Information */
+    char G29[0x0100];           /* 0x1480 - Siemens specific */
+    text_info_t ti;
+} ima_header_t;
+
+#endif /* _SIEMENS_HEADER_DEFS_H_ */
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/siemens_header_table.h
@@ -0,0 +1,97 @@
+Siemens_hdr_entry Siemens_hdr_table[] = {
+{0x0008, 0x0020, &IMA_hdr.G08.StudyDate, create_ima_date_t_element, 1},
+{0x0008, 0x0022, &IMA_hdr.G08.AcquisitionDate, create_ima_date_t_element, 1},
+{0x0008, 0x0023, &IMA_hdr.G08.ContentDate, create_ima_date_t_element, 1},
+{0x0008, 0x0030, &IMA_hdr.G08.StudyTime, create_ima_time_t_element, 1},
+{0x0008, 0x0032, &IMA_hdr.G08.AcquisitionTime, create_ima_time_t_element, 1},
+{0x0008, 0x0033, &IMA_hdr.G08.ContentTime, create_ima_time_t_element, 1},
+{0x0008, 0x0060, &IMA_hdr.G08.Modality, create_modality_element, 1},
+{0x0008, 0x0070, &IMA_hdr.G08.Manufacturer, create_char_element, N_MANUFACTURER+1},
+{0x0008, 0x0080, &IMA_hdr.G08.InstitutionName, create_char_element, N_STRING+1},
+{0x0008, 0x0090, &IMA_hdr.G08.PhysicianName, create_char_element, N_STRING+1},
+{0x0008, 0x1010, &IMA_hdr.G08.StationName, create_char_element, N_STRING+1},
+{0x0008, 0x1030, &IMA_hdr.G08.StudyDescription, create_char_element, N_STRING+1},
+{0x0008, 0x1080, &IMA_hdr.G08.AdmittingDiagnoses, create_char_element, N_DIAGNOSIS+1},
+{0x0008, 0x1090, &IMA_hdr.G08.ModelName, create_char_element, N_STRING+1},
+
+{0x0010, 0x0010, &IMA_hdr.G10.PatientName, create_char_element, N_STRING+1},
+{0x0010, 0x0020, &IMA_hdr.G10.PatientID, create_char_element, N_PATIENTID+1},
+{0x0010, 0x0030, &IMA_hdr.G10.PatientDOB, create_ima_date_t_element, 1},
+{0x0010, 0x0040, &IMA_hdr.G10.PatientSex, create_sex_element, 1},
+{0x0010, 0x1005, &IMA_hdr.G10.PatientBirthName, create_char_element, N_STRING+1},
+{0x0010, 0x1010, &IMA_hdr.G10.PatientAge, create_age_element, 1},
+{0x0010, 0x1030, &IMA_hdr.G10.PatientWeight, create_long_element, 1},
+
+{0x0018, 0x0050, &IMA_hdr.G18.SliceThickness, create_double_element, 1},
+{0x0018, 0x0080, &IMA_hdr.G18.RepetitionTime, create_double_element, 1},
+{0x0018, 0x0081, &IMA_hdr.G18.EchoTime, create_double_element, 1},
+{0x0018, 0x0082, &IMA_hdr.G18.InversionTime, create_double_element, 1},
+{0x0018, 0x0083, &IMA_hdr.G18.NumberOfAverages, create_long_element, 1},
+{0x0018, 0x0084, &IMA_hdr.G18.ImagingFrequency, create_double_element, 1},
+{0x0018, 0x0085, &IMA_hdr.G18.ImagedNucleus, create_char_element, N_NUCLEUS+1},
+{0x0018, 0x0086, &IMA_hdr.G18.EchoNumber, create_long_element, 1},
+{0x0018, 0x0090, &IMA_hdr.G18.DataCollectionDiameter, create_long_element, 1},
+{0x0018, 0x1000, &IMA_hdr.G18.SerialNumber, create_char_element, N_STRING+1},
+{0x0018, 0x1020, &IMA_hdr.G18.SoftwareVersion, create_char_element, N_SWVERSION+1},
+{0x0018, 0x1200, &IMA_hdr.G18.CalibrationDate, create_ima_date_t_element, 1},
+{0x0018, 0x1201, &IMA_hdr.G18.CalibrationTime, create_ima_time_t_element, 1},
+{0x0018, 0x1250, &IMA_hdr.G18.ReceiveCoilName, create_char_element, N_STRING+1},
+{0x0018, 0x5100, &IMA_hdr.G18.PatientPosition, create_ima_position_t_element, 1},
+
+{0x0019, 0x1060, &IMA_hdr.G19.NumberOfDataBytes, create_long_element, 1},
+{0x0019, 0x1220, &IMA_hdr.G19.FourierLinesNominal, create_long_element, 1},
+{0x0019, 0x1226, &IMA_hdr.G19.FourierLinesAfterZero, create_long_element, 1},
+{0x0019, 0x1228, &IMA_hdr.G19.FirstMeasuredFourierLine, create_long_element, 1},
+{0x0019, 0x1230, &IMA_hdr.G19.AcquisitionColumns, create_long_element, 1},
+{0x0019, 0x1231, &IMA_hdr.G19.ReconstructionColumns, create_long_element, 1},
+{0x0019, 0x1250, &IMA_hdr.G19.NumberOfAverages, create_long_element, 1},
+{0x0019, 0x1260, &IMA_hdr.G19.FlipAngle, create_double_element, 1},
+{0x0019, 0x1270, &IMA_hdr.G19.NumberOfPrescans, create_long_element, 1},
+{0x0019, 0x1290, &IMA_hdr.G19.SaturationRegions, create_long_element, 1},
+{0x0019, 0x1412, &IMA_hdr.G19.MagneticFieldStrength, create_double_element, 1},
+
+{0x0020, 0x0010, &IMA_hdr.G20.StudyID, create_long_element, 1},
+{0x0020, 0x0012, &IMA_hdr.G20.AcquisitionNumber, create_long_element, 1},
+{0x0020, 0x0013, &IMA_hdr.G20.InstanceNumber, create_long_element, 1},
+{0x0020, 0x0050, &IMA_hdr.G20.Location, create_long_element, 1},
+{0x0020, 0x0060, &IMA_hdr.G20.Laterality, create_laterality_element, 1},
+{0x0020, 0x1001, &IMA_hdr.G20.AcquisitionsInSeries, create_long_element, 1},
+
+{0x0021, 0x1120, &IMA_hdr.G21.FieldOfView, create_field_of_view_t_element, 1},
+{0x0021, 0x1122, &IMA_hdr.G21.ImageMagnificationFactor, create_double_element, 1},
+{0x0021, 0x1130, &IMA_hdr.G21.ViewDirection, create_view_direction_t_element, 1},
+{0x0021, 0x1132, &IMA_hdr.G21.RestDirection, create_rest_direction_t_element, 1},
+{0x0021, 0x1160, &IMA_hdr.G21.ImagePosition, create_ima_vector_t_element, 1},
+{0x0021, 0x1161, &IMA_hdr.G21.ImageNormal, create_ima_vector_t_element, 1},
+{0x0021, 0x1163, &IMA_hdr.G21.ImageDistance, create_double_element, 1},
+{0x0021, 0x116a, &IMA_hdr.G21.ImageRow, create_ima_vector_t_element, 1},
+{0x0021, 0x116b, &IMA_hdr.G21.ImageColumn, create_ima_vector_t_element, 1},
+{0x0021, 0x1170, &IMA_hdr.G21.OrientationSet1, create_ima_orientation_t_element, 1},
+{0x0021, 0x1171, &IMA_hdr.G21.OrientationSet2, create_ima_orientation_t_element, 1},
+{0x0021, 0x1180, &IMA_hdr.G21.StudyName, create_char_element, N_STRING+1},
+{0x0021, 0x1330, &IMA_hdr.G21.NumberOf3DRawPartNom, create_long_element, 1},
+{0x0021, 0x1331, &IMA_hdr.G21.NumberOf3DRawPartCur, create_long_element, 1},
+{0x0021, 0x1334, &IMA_hdr.G21.NumberOf3DImaPart, create_long_element, 1},
+{0x0021, 0x1336, &IMA_hdr.G21.Actual3DImaPartNumber, create_long_element, 1},
+{0x0021, 0x1339, &IMA_hdr.G21.SlabThickness, create_double_element, 1},
+{0x0021, 0x1340, &IMA_hdr.G21.NumberOfSlicesNom, create_long_element, 1},
+{0x0021, 0x1341, &IMA_hdr.G21.NumberOfSlicesCur, create_long_element, 1},
+{0x0021, 0x1342, &IMA_hdr.G21.CurrentSliceNumber, create_long_element, 1},
+{0x0021, 0x1343, &IMA_hdr.G21.CurrentGroupNumber, create_long_element, 1},
+{0x0021, 0x134f, &IMA_hdr.G21.SliceOrder, create_slice_order_element, 1},
+{0x0021, 0x1370, &IMA_hdr.G21.NumberOfEchoes, create_long_element, 1},
+{0x0028, 0x0005, &IMA_hdr.G28.ImageDimension, create_short_element, 1},
+{0x0028, 0x0010, &IMA_hdr.G28.Rows, create_short_element, 1},
+{0x0028, 0x0011, &IMA_hdr.G28.Columns, create_short_element, 1},
+{0x0028, 0x0030, &IMA_hdr.G28.PixelSpacing, create_pixel_spacing_t_element, 1},
+{0x0028, 0x0100, &IMA_hdr.G28.BitsAllocated, create_short_element, 1},
+{0x0028, 0x0101, &IMA_hdr.G28.BitsStored, create_short_element, 1},
+{0x0028, 0x0102, &IMA_hdr.G28.HighBit, create_short_element, 1},
+{0x0028, 0x0103, &IMA_hdr.G28.PixelRepresentation, create_short_element, 1},
+{0x0028, 0x1050, &IMA_hdr.G28.WindowCenter, create_window_t_element, 1},
+{0x0028, 0x1051, &IMA_hdr.G28.WindowWidth, create_window_t_element, 1},
+{0x0028, 0x1052, &IMA_hdr.G28.RescaleIntercept, create_long_element, 1},
+{0x0028, 0x1053, &IMA_hdr.G28.RescaleSlope, create_long_element, 1},
+{0, 0, NULL, NULL, 0}
+};
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/siemens_to_dicom.c
@@ -0,0 +1,931 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : siemens_to_dicom.c
+@DESCRIPTION: File containing routines to read in a Siemens vision internal
+              file (.IMA extension) and convert it to a DICOM representation.
+@METHOD     : 
+@GLOBALS    : 
+@CREATED    : July 8, 1997 (Peter Neelin)
+@MODIFIED   : $Log: siemens_to_dicom.c,v $
+@MODIFIED   : Revision 1.6.2.1  2005-05-12 21:16:48  bert
+@MODIFIED   : Initial checkin
+@MODIFIED   :
+@MODIFIED   : Revision 1.6  2005/04/21 22:32:15  bert
+@MODIFIED   : Continue Siemens IMA code cleanup
+@MODIFIED   :
+@MODIFIED   : Revision 1.5  2005/04/18 16:21:16  bert
+@MODIFIED   : Fix definition of siemens_to_dicom
+@MODIFIED   :
+@MODIFIED   : Revision 1.4  2005/04/05 21:56:47  bert
+@MODIFIED   : Add some conversion functions, remove some more proprietary junk, and improve range-checking on some functions
+@MODIFIED   :
+@MODIFIED   : Revision 1.3  2005/03/03 18:59:16  bert
+@MODIFIED   : Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+@MODIFIED   :
+@MODIFIED   : Revision 1.2  2005/03/02 20:06:23  bert
+@MODIFIED   : Update conversions to reflect simplified header structures and types
+@MODIFIED   :
+@MODIFIED   : Revision 1.1  2005/02/17 16:38:11  bert
+@MODIFIED   : Initial checkin, revised DICOM to MINC converter
+@MODIFIED   :
+@MODIFIED   : Revision 1.1.1.1  2003/08/15 19:52:55  leili
+@MODIFIED   : Leili's dicom server for sonata
+@MODIFIED   :
+@MODIFIED   : Revision 1.1  2001/12/31 17:28:34  rhoge
+@MODIFIED   : adding file to repos - now needed for reading .ima files in directly
+@MODIFIED   :
+@MODIFIED   : Revision 1.2  2000/12/17 01:05:24  rhoge
+@MODIFIED   : temporary activation of offset table printing macro
+@MODIFIED   :
+@MODIFIED   : Revision 1.1.1.1  2000/11/30 02:05:54  rhoge
+@MODIFIED   : imported sources to CVS repository on amoeba
+@MODIFIED   :
+ * Revision 1.4  1998/11/16  19:54:15  neelin
+ * Added definitions for SunOS.
+ *
+ * Revision 1.3  1998/11/13  16:02:09  neelin
+ * Modifications to support packed images and asynchronous transfer.
+ *
+ * Revision 1.2  1997/11/04  14:31:30  neelin
+ * *** empty log message ***
+ *
+ * Revision 1.1  1997/08/11  12:50:53  neelin
+ * Initial revision
+ *
+---------------------------------------------------------------------------- */
+
+static const char rcsid[]="$Header: /private-cvsroot/minc/conversion/dcm2mnc/siemens_to_dicom.c,v 1.6.2.1 2005-05-12 21:16:48 bert Exp $";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dcm2mnc.h"
+#include "siemens_header_defs.h"
+
+/* Constants */
+
+#define SIEMENS_IMAGE_OFFSET 6144 /* From dclunie.com */
+
+#define IMAGE_NDIMS 2
+
+/* Types */
+#define ELEMENT_FUNC_ARGS \
+    (int grp_id, int elm_id, void *data, int length)
+
+#define DEFINE_ELEMENT_FUNC(name) \
+    static Acr_Element name ELEMENT_FUNC_ARGS
+
+#define DECLARE_ELEMENT_FUNC(name) \
+    static Acr_Element name ELEMENT_FUNC_ARGS
+
+typedef Acr_Element (*Create_Element_Function) ELEMENT_FUNC_ARGS;
+
+typedef struct {
+    int grp_id;
+    int elm_id;
+    void *data;
+    Create_Element_Function function;
+    int length;
+} Siemens_hdr_entry;
+
+/* Functions */
+
+static Acr_Element_Id get_elid(int grp_id, int elm_id, Acr_VR_Type vr_code);
+
+DECLARE_ELEMENT_FUNC(create_char_element);
+DECLARE_ELEMENT_FUNC(create_long_element);
+DECLARE_ELEMENT_FUNC(create_short_element);
+DECLARE_ELEMENT_FUNC(create_double_element);
+DECLARE_ELEMENT_FUNC(create_ima_date_t_element);
+DECLARE_ELEMENT_FUNC(create_ima_time_t_element);
+DECLARE_ELEMENT_FUNC(create_modality_element);
+DECLARE_ELEMENT_FUNC(create_sex_element);
+DECLARE_ELEMENT_FUNC(create_age_element);
+DECLARE_ELEMENT_FUNC(create_slice_order_element);
+DECLARE_ELEMENT_FUNC(create_pixel_spacing_t_element);
+DECLARE_ELEMENT_FUNC(create_window_t_element);
+DECLARE_ELEMENT_FUNC(create_ima_vector_t_element);
+DECLARE_ELEMENT_FUNC(create_laterality_element);
+DECLARE_ELEMENT_FUNC(create_ima_position_t_element);
+DECLARE_ELEMENT_FUNC(create_rest_direction_t_element);
+DECLARE_ELEMENT_FUNC(create_view_direction_t_element);
+DECLARE_ELEMENT_FUNC(create_ima_orientation_t_element);
+DECLARE_ELEMENT_FUNC(create_field_of_view_t_element);
+
+/* Define the table of header values */
+ima_header_t IMA_hdr;           /* Must define this first */
+#include "siemens_header_table.h" /* Now include the table */
+
+/* flag to print offset table, useful in debugging byte pad issues
+   with Linux/sun porting */
+/* #define PRINT_OFFSET_TABLE 1 */
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : siemens_to_dicom
+@INPUT      : filename - name of Siemens internal file
+              read_image - if TRUE, then the image is added to the group list,
+                           otherwise it is not read in.
+@OUTPUT     : (none)
+@RETURNS    : Acr-nema group list containing contents of Siemens file
+@DESCRIPTION: Function to read in a siemens internal format file (.IMA) 
+              and store it in an ACR-NEMA group list.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : July 8, 1997 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+Acr_Group
+siemens_to_dicom(const char *filename, int max_group)
+{
+    FILE *fp;
+    Siemens_hdr_entry *entry;
+    Acr_Group group_list;
+    Acr_Element element;
+    long image_size;
+    long pixel_size;
+    void *image;
+    double flip_angle;
+    short rows;
+    short cols;
+
+#ifdef PRINT_OFFSET_TABLE
+    void *header_ptr;           /* debug junk */
+    void *data_ptr;             /* debug junk */
+    long offset;                /* debug junk */
+#endif
+
+    /* Check the structure offsets */
+    assert(((char *)&IMA_hdr.G08 - (char *)&IMA_hdr) == 0x0000);
+    assert(((char *)&IMA_hdr.G10 - (char *)&IMA_hdr) == 0x0300);
+    assert(((char *)&IMA_hdr.G18 - (char *)&IMA_hdr) == 0x0600);
+    assert(((char *)&IMA_hdr.G19 - (char *)&IMA_hdr) == 0x0780);
+    assert(((char *)&IMA_hdr.G20 - (char *)&IMA_hdr) == 0x0C80);
+    assert(((char *)&IMA_hdr.G21 - (char *)&IMA_hdr) == 0x0E80);
+    assert(((char *)&IMA_hdr.G28 - (char *)&IMA_hdr) == 0x1380);
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("siemens_to_dicom(%s, %x)\n", filename, max_group);
+    }
+
+    /* Open the file */
+    if ((fp = fopen(filename, "rb")) == NULL) {
+        fprintf(stderr, "Error opening file %s\n", filename);
+        return NULL;
+    }
+
+    /* Read in the header */
+    if (fread(&IMA_hdr, sizeof(IMA_hdr), 1, fp) != 1) {
+        fprintf(stderr, "Error reading header in %s\n", filename);
+        fclose(fp);
+        return NULL;
+    }
+
+    /* Get the image if it is needed */
+    if (max_group >= ACR_IMAGE_GID) {
+
+        /* Figure out how much space we need for the image */
+        pixel_size = 2;         /* Apparently this never changes?? */
+
+        /* Need to byte swap row/col values if needed 
+         */
+        acr_get_short(ACR_BIG_ENDIAN, 1, &IMA_hdr.G28.Rows, &rows);
+        acr_get_short(ACR_BIG_ENDIAN, 1, &IMA_hdr.G28.Columns, &cols);
+
+        image_size = rows * cols;
+
+        image = malloc(pixel_size * image_size);
+        CHKMEM(image);
+
+        /* Read in the image */
+        if (fseek(fp, (long) SIEMENS_IMAGE_OFFSET, SEEK_SET)) {
+            printf("ERROR: Error finding image in %s\n", filename);
+            fclose(fp);
+            return NULL;
+        }
+        if (fread(image, pixel_size, image_size, fp) != image_size) {
+            printf("ERROR: Error reading image in %s\n", filename);
+            fclose(fp);
+            return NULL;
+        }
+
+    }         /* If (max_group >= ACR_IMAGE_GID) */
+
+    /* Close the file */
+    fclose(fp);
+
+    /* Loop through the header table, creating a header */
+    group_list = NULL;
+    for (entry = Siemens_hdr_table; entry->data != NULL; entry++) {
+
+#ifdef PRINT_OFFSET_TABLE
+        data_ptr = entry->data;
+        header_ptr = &IMA_hdr;
+        offset = (long) data_ptr - (long) header_ptr;
+        printf("DEBUG:  group = 0x%x, element = 0x%x, offset = 0x%lx, length = 0x%x\n",
+               entry->grp_id, entry->elm_id, offset, entry->length);
+#endif
+
+        if (entry->function == NULL) {
+            continue;
+        }
+        element = entry->function(entry->grp_id, entry->elm_id,
+                                  entry->data, entry->length);
+        if (element == NULL) {
+            continue;
+        }
+
+        acr_insert_element_into_group_list(&group_list, element);
+    }
+
+    /* Insert flip angle element */
+    element = acr_find_group_element(group_list, SPI_Flip_angle);
+    if (element != NULL) {
+        flip_angle = acr_get_element_numeric(element);
+        if (flip_angle >= 0.0) {
+            acr_insert_numeric(&group_list, ACR_Flip_angle, flip_angle);
+        }
+    }
+
+    if (acr_find_int(group_list, SPI_Number_of_slices_nominal, 1) > 1) {
+        short acq_cols;
+
+        acq_cols = acr_find_short(group_list, SPI_Acquisition_columns,
+                                  acr_find_short(group_list, ACR_Columns, 1));
+
+        acr_insert_long(&group_list, EXT_Mosaic_rows, 
+                        acr_find_int(group_list, ACR_Rows, 1));
+
+        acr_insert_long(&group_list, EXT_Mosaic_columns, 
+                        acr_find_int(group_list, ACR_Columns, 1));
+
+        acr_insert_long(&group_list, EXT_Slices_in_file, 
+                        acr_find_int(group_list, SPI_Number_of_slices_nominal, 1));
+        acr_insert_short(&group_list, EXT_Sub_image_rows, acq_cols);
+        acr_insert_short(&group_list, EXT_Sub_image_columns, acq_cols);
+
+        /* We need to set up the ACR_Acquisition (and 
+         * ACR_Acquisitions_in_series) objects to make everyone happy.
+         *
+         * TODO: This appears to work for SOME IMA files, but it may
+         * not be correct for all sequences.
+         */
+        acr_insert_long(&group_list, ACR_Acquisition, 
+                        acr_find_int(group_list, ACR_Image, 1));
+
+        acr_insert_long(&group_list, ACR_Acquisitions_in_series, 
+                        acr_find_int(group_list, ACR_Nr_of_averages, 1));
+    }
+
+    /* Insert a series number */
+    acr_insert_numeric(&group_list, ACR_Series, 1.0);
+
+    /* Insert appropriate image position and orientation information */
+    update_coordinate_info(group_list);
+
+
+    /* Add the image if it is needed */
+    if (max_group >= ACR_IMAGE_GID) {
+
+        /* Insert the image location */
+        acr_insert_short(&group_list, ACR_Image_location, ACR_IMAGE_GID);
+
+        /* Add the image. We don't byte-swap here since it will be done
+           automatically when the data is written out. */
+        element = acr_create_element(ACR_IMAGE_GID, ACR_IMAGE_EID, ACR_VR_OW,
+                                     image_size * pixel_size, image);
+        acr_insert_element_into_group_list(&group_list, element);
+
+        /* explicitly label image data as big-endian */
+        acr_set_element_byte_order(element, ACR_BIG_ENDIAN);
+
+    } /* if (max_group >= ACR_IMAGE_GID) */
+
+    /* Return the group list */
+    return group_list;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : update_coordinate_info
+@INPUT      : group_list
+@OUTPUT     : group_list
+@RETURNS    : (nothing)
+@DESCRIPTION: Function to modify the DICOM coordinate information to match
+              the Siemens info.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : November 9, 1998 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+void
+update_coordinate_info(Acr_Group group_list)
+{
+    Acr_Element element;
+    int nrows, ncolumns;
+    int i;
+    double coord[WORLD_NDIMS];
+    double row[WORLD_NDIMS];
+    double column[WORLD_NDIMS];
+    double normal[WORLD_NDIMS];
+    double pixel_spacing[IMAGE_NDIMS];
+    string_t string;
+    int n_slices;
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("update_coordinate_info(%lx)\n", (unsigned long) group_list);
+    }
+
+    /* Look for the normal vector 
+     */
+    element = acr_find_group_element(group_list, SPI_Image_normal);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, WORLD_NDIMS, normal)
+         != WORLD_NDIMS)) {
+        normal[XCOORD] = 0.0;
+        normal[YCOORD] = 0.0;
+        normal[ZCOORD] = 1.0;
+    }
+
+    /* Look for the row vector.
+     */
+    element = acr_find_group_element(group_list, SPI_Image_row);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, WORLD_NDIMS, row) 
+         != WORLD_NDIMS)) {
+        row[XCOORD] = 1.0; 
+        row[YCOORD] = 0.0; 
+        row[ZCOORD] = 0.0;
+    }
+
+    /* Look for the column vector 
+     */
+    element = acr_find_group_element(group_list, SPI_Image_column);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, WORLD_NDIMS, column) 
+         != WORLD_NDIMS)) {
+        column[XCOORD] = 0.0; 
+        column[YCOORD] = 1.0; 
+        column[ZCOORD] = 0.0;
+    }
+
+    if (G.Debug >= HI_LOGGING) {
+        printf("R %.3f %.3f %.3f C %.3f %.3f %.3f N %.3f %.3f %.3f\n",
+               row[0], row[1], row[2],
+               column[0], column[1], column[2],
+               normal[0], normal[1], normal[2]);
+    }
+
+    /* Put in the dicom orientation (patient) field 
+     */
+    sprintf(string, "%.15g\\%.15g\\%.15g\\%.15g\\%.15g\\%.15g",
+            row[XCOORD], -row[YCOORD], -row[ZCOORD], 
+            column[XCOORD], -column[YCOORD], -column[ZCOORD]);
+    acr_insert_string(&group_list, ACR_Image_orientation_patient, string);
+
+    /* Look for the position.
+     */
+    element = acr_find_group_element(group_list, SPI_Image_position);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, WORLD_NDIMS, coord) 
+         != WORLD_NDIMS)) {
+        coord[XCOORD] = 0.0; 
+        coord[YCOORD] = 0.0; 
+        coord[ZCOORD] = 0.0;
+    }
+    else {
+        if (G.Debug >= HI_LOGGING) {
+            printf(" old %.3f %.3f %.3f, ", coord[0], coord[1], coord[2]);
+        }
+    }
+
+    /* Get the number of rows and columns.
+     */
+
+    nrows = acr_find_int(group_list, ACR_Rows, 0);
+    ncolumns = acr_find_int(group_list, ACR_Columns, 0);
+    if ((nrows <= 0) || (ncolumns <= 0)) {
+        printf("ERROR: Illegal image size in Siemens IMA file\n");
+        exit(1);
+    }
+
+
+    /* Get the pixel size */
+    element = acr_find_group_element(group_list, ACR_Pixel_size);
+    if ((element == NULL) ||
+        (acr_get_element_numeric_array(element, IMAGE_NDIMS, pixel_spacing) 
+         != IMAGE_NDIMS)) {
+        pixel_spacing[0] = pixel_spacing[1] = 1.0;
+    }
+
+    /* Calculate the position of the first pixel. This coordinate
+     * is still in the Siemens space, not dicom space and will
+     * need to be flipped. Note that ncolumns is used with row,
+     * since they are the size and unit vector of the same
+     * dimension.
+     */
+    for (i = 0; i < WORLD_NDIMS; i++) {
+        coord[i] -= 
+            pixel_spacing[0] * ((double) ncolumns - 1.0) / 2.0 * row[i] +
+            pixel_spacing[1] * ((double) nrows - 1.0) / 2.0 * column[i];
+    }
+    sprintf(string, "%.15g\\%.15g\\%.15g", coord[0], -coord[1], -coord[2]);
+    acr_insert_string(&group_list, ACR_Image_position_patient, string);
+    if (G.Debug >= HI_LOGGING) {
+        printf(" new %.3f %.3f %.3f\n", coord[0], -coord[1], -coord[2]);
+    }
+
+    /* Copy non-standard fields to standard fields.
+     */
+    group_list = copy_spi_to_acr(group_list);
+
+    /* If this is a Mosaic image, we need to adjust the pixel spacing
+     * to reflect the ratio between the number of mosaic columns
+     * divided the number of image columns.
+     */
+    n_slices = acr_find_int(group_list, EXT_Slices_in_file, 1);
+    if (n_slices != 1) {
+        int acq_cols = acr_find_short(group_list, SPI_Acquisition_columns, 
+                                      ncolumns);
+        if (G.Debug >= HI_LOGGING) {
+            printf("Hmmm... This appears to be a mosaic image %d %d\n",
+                   acq_cols, ncolumns);
+        }
+
+        /* Mosaic images in IMA format appear to need to have their
+         * pixel spacing scaled up.  I don't fully understand why this
+         * should be necessary, but there it is...
+         */
+        pixel_spacing[0] *= (double) nrows / (double) acq_cols;
+        pixel_spacing[1] *= (double) ncolumns / (double) acq_cols;
+        sprintf(string, "%.15g\\%.15g", pixel_spacing[0], pixel_spacing[1]);
+        acr_insert_string(&group_list, ACR_Pixel_size, string);
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : create_<type>_element
+@INPUT      : grp_id
+              elm_id
+              data - pointer to data in Siemens header
+              length - number of values in array (if appropriate)
+@OUTPUT     : (none)
+@RETURNS    : New element containing data
+@DESCRIPTION: Series of functions to convert Siemens vision header types
+              to ACR-NEMA elements
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : July 8, 1997 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+static Acr_Element_Id 
+get_elid(int grp_id, int elm_id, Acr_VR_Type vr_code)
+{
+    static struct Acr_Element_Id elid_struct = {0, 0, ACR_VR_UNKNOWN};
+    elid_struct.group_id = grp_id;
+    elid_struct.element_id = elm_id;
+    elid_struct.vr_code = vr_code;
+    return &elid_struct;
+}
+
+DEFINE_ELEMENT_FUNC(create_char_element)
+{
+    char *old, *new;
+    int oldsize, newsize, i;
+
+    /* Get a pointer to the old string */
+    old = (char *) data;
+
+    /* Figure out the length of the new string up to the first NUL. Make 
+     * sure that there is a room for an additional NUL if necessary 
+     */
+    for (i = 0; (i < length - 1) && (old[i] != '\0'); i++) 
+        ;
+    newsize = ((old[i] == '\0') ? i + 1 : length + 1);
+    oldsize = newsize - 1;
+    if ((newsize % 2) != 1) {   /* Assure even length overall */
+        newsize++;
+    }
+
+    /* Copy the string, making sure that there is a NUL on the end */
+    new = malloc(newsize);
+    CHKMEM(new);
+    for (i = 0; i < newsize-1; i++) {
+        if (i < oldsize)
+            new[i] = old[i];
+        else
+            new[i] = ' ';
+    }
+    new[newsize-1] = '\0';
+
+    /* Create the element */
+    return acr_create_element(grp_id, elm_id, ACR_VR_ST, 
+                              (long) newsize-1, (void *) new);
+}
+
+DEFINE_ELEMENT_FUNC(create_long_element)
+{
+    long data_out;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, data, &data_out);
+
+    return acr_create_element_numeric(get_elid(grp_id, elm_id, ACR_VR_IS), 
+                                      data_out); 
+}
+
+DEFINE_ELEMENT_FUNC(create_short_element)
+{
+    unsigned short data_out;
+
+    acr_get_short(ACR_BIG_ENDIAN, 1, data, &data_out);
+
+    return acr_create_element_short(get_elid(grp_id, elm_id, ACR_VR_US), 
+                                    data_out);
+}
+
+DEFINE_ELEMENT_FUNC(create_double_element)
+{
+    double data_out;
+  
+    acr_get_double(ACR_BIG_ENDIAN, 1, data, &data_out);
+
+    return acr_create_element_numeric(get_elid(grp_id, elm_id, ACR_VR_DS),
+                                      data_out);
+}
+
+DEFINE_ELEMENT_FUNC(create_ima_date_t_element)
+{
+    string_t string;
+    ima_date_t *ptr;
+    long year;
+    long month;
+    long day;
+
+    ptr = (ima_date_t *) data;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->year, &year); 
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->month, &month);
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->day, &day);
+
+    if ((year < 1900) || (year > 9999)) 
+        return NULL;
+    if ((month < 1) || (month > 12)) 
+        return NULL;
+    if ((day < 1) || (day > 31)) 
+        return NULL;
+
+    sprintf(string, "%04d%02d%02d", (int) year, (int) month, (int) day);
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_DA),
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_ima_time_t_element)
+{
+    string_t string;
+    ima_time_t *ptr;
+    long hour;
+    long minute;
+    long second;
+    long msec;
+
+    ptr = (ima_time_t *) data;
+
+    /* Convert data from big endian to native:
+     */
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->hour, &hour); 
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->minute, &minute); 
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->second, &second); 
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->msec, &msec); 
+
+    if ((hour < 0) || (hour >= 24)) 
+        return NULL;
+    if ((minute < 0) || (minute >= 60)) 
+        return NULL;
+    if ((second < 0) || (second >= 60)) 
+        return NULL;
+    if ((msec < 0) || (msec > 999)) 
+        return NULL;
+
+    sprintf(string, "%02d%02d%02d.%03d", (int) hour, (int) minute, 
+            (int) second, (int) msec);
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_TM), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_modality_element)
+{
+    char *string;
+    int32_t modality;
+
+    /* Get the appropriate string */
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &modality); 
+    switch (modality) {
+    case 1:
+        string = "CT";
+        break;
+    case 2:
+        string = "MR";
+        break;
+    default:
+        return NULL;
+    }
+    
+    /* Return a new element */
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_sex_element)
+{
+    char *string;
+    int32_t sex;
+
+    /* Get the appropriate string */
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &sex); 
+    switch (sex) {
+    case 1:
+        string = "F ";
+        break;
+    case 2:
+        string = "M ";
+        break;
+    case 3:
+        string = "O ";
+        break;
+    default:
+        return NULL;
+    }
+
+    /* Return a new element */
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_age_element)
+{
+    string_t string;
+    int i;
+    int is_ok;
+
+    is_ok = 1;
+
+    /* The age string has a fixed length of 4 */
+    memcpy(string, data, 4);
+    string[4] = '\0';
+
+    for (i = 0; i < 3; i++) {
+        if (string[i] < '0' || string[i] > '9') {
+            is_ok = 0;
+        }
+    }
+    if (string[3] != 'Y' &&
+        string[3] != 'M' && 
+        string[3] != 'W' &&
+        string[3] != 'D') {
+        is_ok = 0;
+    }
+    if (!is_ok) {
+        printf("WARNING: Invalid age field '%s'\n", string);
+        return NULL;
+    }
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_AS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_slice_order_element)
+{
+    char *string;
+    ima_slice_order_t slice_order;
+
+    /* Get the appropriate string */
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &slice_order); 
+    switch (slice_order) {
+    case SO_ASCENDING:
+        string = "ASCENDING ";
+        break;
+    case SO_DESCENDING:
+        string = "DESCENDING ";
+        break;
+    case SO_INTERLEAVED:
+        string = "INTERLEAVED ";
+        break;
+    case SO_NONE:
+        string = "NONE ";
+        break;
+    default:
+        string = "UNDEFINED ";
+        break;
+    }
+
+    /* Return a new element */
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_pixel_spacing_t_element)
+{
+    pixel_spacing_t *ptr;
+    string_t string;
+    double row;
+    double col;
+
+    /* Get the pixel sizes */
+    ptr = (pixel_spacing_t *) data;
+
+    /* Convert from big endian to native format */
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->row, &row); 
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->col, &col); 
+
+    sprintf(string, "%.15g\\%.15g", row, col);
+    
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_DS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_window_t_element)
+{
+    window_t *ptr;
+    string_t string;
+    long x;
+    long y;
+
+    ptr = (window_t *) data;    /* Get the window info */
+
+    /* Convert from big endian to native format */
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->x, &x); 
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) &ptr->y, &y); 
+    
+    sprintf(string, "%ld\\%ld", x, y);
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_IS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_ima_vector_t_element)
+{
+    ima_vector_t *ptr;
+    string_t string;
+    double x, y, z;
+
+    /* Get the coordinate */
+    ptr = (ima_vector_t *) data;
+   
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->x, &x);
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->y, &y);
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->z, &z);
+
+    sprintf(string, "%.15g\\%.15g\\%.15g", x, y, z);
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_DS),
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_laterality_element)
+{
+    long laterality;
+    char *string;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, &laterality);
+
+    switch (laterality) {
+    case 1:
+        string = "L "; break;
+    case 2:
+        string = ""; break;
+    case 3:
+        string = "R "; break;
+    default:
+        return NULL;
+    }
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS), 
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_ima_position_t_element)
+{
+    ima_position_t position;
+    char *string;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &position);
+    switch (position) {
+    case PP_LEFT:
+        string = "HFL"; break;
+    case PP_RIGHT:
+        string = "HFR"; break;
+    case PP_PRONE:
+        string = "HFP"; break;
+    case PP_SUPINE:
+        string = "HFS"; break;
+    default:
+        string = ""; break;
+    }
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS),
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_rest_direction_t_element)
+{
+    ima_rest_direction_t dir;
+    char *string;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &dir);
+    switch (dir) {
+    case RD_HEAD:
+        string = "HEAD";
+        break;
+    case RD_FEET:
+        string = "FEET";
+        break;
+    default:
+        string = "";
+        break;
+    }
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS),
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_view_direction_t_element)
+{
+    ima_view_direction_t dir;
+    char *string;
+
+    acr_get_long(ACR_BIG_ENDIAN, 1, (long *) data, (long *) &dir);
+    switch (dir) {
+    case VD_HEAD:
+        string = "HEAD";
+        break;
+    case VD_FEET:
+        string = "FEET";
+        break;
+    case VD_AtoP:
+        string = "AtoP";
+        break;
+    case VD_LtoR:
+        string = "LtoR";
+        break;
+    case VD_PtoA:
+        string = "PtoA";
+        break;
+    case VD_RtoL:
+        string = "RtoL";
+        break;
+    default:
+        string = "";
+        break;
+    }
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS),
+                                     string);
+}
+
+static void
+copy_to_space(char *dst_ptr, char *src_ptr, int max_chr)
+{
+    while (*src_ptr != ' ' && *src_ptr != '\0' && max_chr > 0) {
+        *dst_ptr++ = *src_ptr++;
+        max_chr--;
+    }
+    *dst_ptr = '\0';
+}
+
+DEFINE_ELEMENT_FUNC(create_ima_orientation_t_element)
+{
+    ima_orientation_t *po_ptr = (ima_orientation_t *) data;
+    char y[N_ORIENTATION + 1];
+    char x[N_ORIENTATION + 1];
+    char z[N_ORIENTATION + 1];
+    string_t string;
+
+    copy_to_space(y, po_ptr->y, N_ORIENTATION);
+    copy_to_space(x, po_ptr->x, N_ORIENTATION);
+    copy_to_space(z, po_ptr->z, N_ORIENTATION);
+
+    sprintf(string, "%s\\%s\\%s", y, x, z);
+
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_CS),
+                                     string);
+}
+
+DEFINE_ELEMENT_FUNC(create_field_of_view_t_element)
+{
+    ima_field_of_view_t *ptr;
+    string_t string;
+    double height;
+    double width;
+
+    ptr = (ima_field_of_view_t *) data;
+
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->height, &height);
+    acr_get_double(ACR_BIG_ENDIAN, 1, (double *) &ptr->width, &width);
+
+    sprintf(string, "%.15g\\%.15g", height, width);
+    return acr_create_element_string(get_elid(grp_id, elm_id, ACR_VR_DS),
+                                     string);
+}
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/siemens_to_dicom.h
@@ -0,0 +1,3 @@
+extern Acr_Group siemens_to_dicom(const char *filename, int max_group);
+extern void update_coordinate_info(Acr_Group group_list);
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/spi_element_defs.h
@@ -0,0 +1,63 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : spi_element_defs.h
+@DESCRIPTION: Element definitions for Siemens "Standard Product Interconnect" 
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : November 23, 1993 (Peter Neelin)
+@MODIFIED   : 
+@COPYRIGHT  :
+              Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* Element id's for SPI */
+/* Most of this information is available at David Clunie's medical imaging 
+ * website (www.dclunie.com).
+ */
+GLOBAL_ELEMENT(SPI_Number_of_data_bytes               , 0x0019, 0x1060, IS);
+GLOBAL_ELEMENT(SPI_Fourier_lines_nominal              , 0x0019, 0x1220, IS);
+GLOBAL_ELEMENT(SPI_Fourier_lines_after_zero           , 0x0019, 0x1226, IS);
+GLOBAL_ELEMENT(SPI_First_measured_fourier_line        , 0x0019, 0x1228, IS);
+GLOBAL_ELEMENT(SPI_Acquisition_columns                , 0x0019, 0x1230, LO);
+GLOBAL_ELEMENT(SPI_Reconstruction_columns             , 0x0019, 0x1231, LO);
+GLOBAL_ELEMENT(SPI_Number_of_averages                 , 0x0019, 0x1250, IS);
+GLOBAL_ELEMENT(SPI_Flip_angle                         , 0x0019, 0x1260, DS);
+GLOBAL_ELEMENT(SPI_Number_of_prescans                 , 0x0019, 0x1270, IS);
+GLOBAL_ELEMENT(SPI_Saturation_regions                 , 0x0019, 0x1290, IS);
+GLOBAL_ELEMENT(SPI_Magnetic_field_strength            , 0x0019, 0x1412, DS);
+
+GLOBAL_ELEMENT(SPI_Field_of_view                      , 0x0021, 0x1120, DS);
+GLOBAL_ELEMENT(SPI_Image_magnification_factor         , 0x0021, 0x1122, DS);
+GLOBAL_ELEMENT(SPI_View_direction                     , 0x0021, 0x1130, CS);
+GLOBAL_ELEMENT(SPI_Rest_direction                     , 0x0021, 0x1132, CS);
+GLOBAL_ELEMENT(SPI_Image_position                     , 0x0021, 0x1160, DS);
+GLOBAL_ELEMENT(SPI_Image_normal                       , 0x0021, 0x1161, DS);
+GLOBAL_ELEMENT(SPI_Image_distance                     , 0x0021, 0x1163, DS);
+GLOBAL_ELEMENT(SPI_Image_row                          , 0x0021, 0x116a, DS);
+GLOBAL_ELEMENT(SPI_Image_column                       , 0x0021, 0x116b, DS);
+GLOBAL_ELEMENT(SPI_Patient_orientation_set1           , 0x0021, 0x1170, CS);
+GLOBAL_ELEMENT(SPI_Patient_orientation_set2           , 0x0021, 0x1171, CS);
+GLOBAL_ELEMENT(SPI_Study_name                         , 0x0021, 0x1180, CS);
+GLOBAL_ELEMENT(SPI_Study_type                         , 0x0021, 0x1182, CS);
+GLOBAL_ELEMENT(SPI_Number_of_3D_raw_partitions_nominal, 0x0021, 0x1330, IS);
+GLOBAL_ELEMENT(SPI_Number_of_3d_raw_part_cur          , 0x0021, 0x1331, IS);
+GLOBAL_ELEMENT(SPI_Number_of_3D_image_partitions      , 0x0021, 0x1334, IS);
+GLOBAL_ELEMENT(SPI_Actual_3D_partition_number         , 0x0021, 0x1336, IS);
+GLOBAL_ELEMENT(SPI_Slab_thickness                     , 0x0021, 0x1339, DS);
+GLOBAL_ELEMENT(SPI_Number_of_slices_nominal           , 0x0021, 0x1340, IS);
+GLOBAL_ELEMENT(SPI_Number_of_slices_cur               , 0x0021, 0x1341, IS);
+GLOBAL_ELEMENT(SPI_Current_slice_number               , 0x0021, 0x1342, IS);
+GLOBAL_ELEMENT(SPI_Order_of_slices                    , 0x0021, 0x134f, IS);
+GLOBAL_ELEMENT(SPI_Number_of_echoes                   , 0x0021, 0x1370, IS);
+
+GLOBAL_ELEMENT(SPI_Protocol                           , 0x0029, 0x1020, CS);
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/string_to_filename.c
@@ -0,0 +1,323 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : string_to_filename.c
+@DESCRIPTION: Code to convert a string to something that can be used in a 
+              file name.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : January 10, 1997 (Peter Neelin)
+@MODIFIED   : 
+ * $Log: string_to_filename.c,v $
+ * Revision 1.2.2.1  2005-05-12 21:16:48  bert
+ * Initial checkin
+ *
+ * Revision 1.2  2005/03/03 18:59:16  bert
+ * Fix handling of image position so that we work with the older field (0020, 0030) as well as the new (0020, 0032)
+ *
+ * Revision 1.1  2005/02/17 16:38:11  bert
+ * Initial checkin, revised DICOM to MINC converter
+ *
+ * Revision 1.1.1.1  2003/08/15 19:52:55  leili
+ * Leili's dicom server for sonata
+ *
+ * Revision 1.2  2002/03/22 19:19:36  rhoge
+ * Numerous fixes -
+ * - handle Numaris 4 Dicom patient name
+ * - option to cleanup input files
+ * - command option
+ * - list-only option
+ * - debug mode
+ * - user supplied name, idstr
+ * - anonymization
+ *
+ * Revision 1.1.1.1  2000/11/30 02:13:15  rhoge
+ * imported sources to CVS repository on amoeba
+ *
+ * Revision 6.1  1999/10/29 17:52:00  neelin
+ * Fixed Log keyword
+ *
+ * Revision 6.0  1997/09/12 13:24:27  neelin
+ * Release of minc version 0.6
+ *
+ * Revision 5.0  1997/08/21  13:25:26  neelin
+ * Release of minc version 0.5
+ *
+ * Revision 4.0  1997/05/07  20:06:20  neelin
+ * Release of minc version 0.4
+ *
+ * Revision 1.1  1997/03/04  20:56:47  neelin
+ * Initial revision
+ *
+@COPYRIGHT  :
+              Copyright 1997 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/string_to_filename.c,v 1.2.2.1 2005-05-12 21:16:48 bert Exp $";
+
+#include "dcm2mnc.h"
+#include <ctype.h>
+
+#define SEPARATOR '_'
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : string_to_filename
+@INPUT      : string - string to convert
+              maxlen - maximum length of output string (including terminating
+                 '\0')
+@OUTPUT     : filename - output string
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to convert a string to something that can be used in
+              a filename
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : December 10, 1993 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+void string_to_filename(const char *string, char *filename, int maxlen)
+{
+   int length, isrc, idst;
+   int ch;
+   int found_first, need_separator;
+
+   /* Get string length */
+   length = strlen(string);
+   if (length > maxlen-1) length = maxlen - 1;
+
+   /* Loop through characters */
+   idst = 0;
+   found_first = FALSE;
+   need_separator = FALSE;
+   for (isrc=0; isrc < length; isrc++) {
+      ch = string[isrc];
+      if (isalnum(ch)) {
+         found_first = TRUE;
+         if (need_separator) {
+            filename[idst++] = SEPARATOR;
+            need_separator = FALSE;
+         }
+         filename[idst++] = tolower(ch);
+      }
+      else if (found_first) {
+         need_separator = TRUE;
+      }
+   }
+
+   /* Add terminating '\0' */
+   filename[idst++] = '\0';
+
+   return;
+}
+
+void string_to_initials(char *string, char *filename, int maxlen)
+{
+  /* function added by R. Hoge to convert name-like strings to
+     initials in environment where confidentiality policy prohibits
+     use of names in file-names */
+
+   int length, isrc, idst;
+   int ch;
+   int first_found, sep_found, multi_word, comma_found, comma_found2, in_word;
+
+   /* Get string length */
+   length = strlen(string);
+   if (length > maxlen-1) length = maxlen - 1;
+
+   /* do first pass to look for multi-words, commas */
+
+   first_found = FALSE;
+   sep_found = FALSE;
+   multi_word = FALSE;
+   comma_found = FALSE;
+
+   for (isrc=0; isrc < length; isrc++) {
+      ch = string[isrc];
+
+      /* if we hit a separator after finding a first alphanum, treat
+	 as multi words */
+
+      /* alphanumeric expressions (including underscores, hyphens) are treated 
+	 as discrete words - note that we won't print hyphens */
+
+      /* examples of single words:
+
+  	   test5
+	   test-5
+	   test_5
+
+	 examples of multi words:
+
+	   test 5
+	   snr_test 5
+	   test,5
+	   snr-test 5
+
+       */
+
+      if (sep_found && isalnum(ch)) {
+	multi_word = TRUE;
+      }
+      
+      if (first_found && !(isalnum(ch)||ch=='-'||ch=='_')) {
+	sep_found = TRUE;
+      }
+
+      if (isalnum(ch)) {
+	first_found = TRUE;
+      }
+
+      // Numaris 4 used caret (^) to separate names (Last^first)
+      if (ch == ',' || ch == '^') {
+	comma_found = TRUE;
+      }
+   }
+
+   /* if Patient name is only a single word, then just strip out
+      non-alphanumeric characters 
+
+      examples:  
+
+      snrtest1   -> snrtest1
+      snrtest-1  -> snrtest1
+      snr_test-2 -> snr_test2
+
+      note that hyphens are omitted, because these
+      are used as delimiters in filename */
+
+   if (!multi_word) {
+
+     idst = 0;
+     for (isrc=0; isrc < length; isrc++) {
+       ch = string[isrc];
+       
+       if (isalnum(ch) || ch=='_') {
+         filename[idst++] = tolower(ch);
+       }
+     }
+
+     /* Add terminating '\0' */
+     filename[idst++] = '\0';
+     
+   } else { /* multiple words */
+     
+     if (!comma_found) {
+
+       /* examples of multi-word no comma:  
+
+	  john doe        -> jd
+	  john edward doe -> jed
+	  john doe-smith  -> jds
+	  my snr_test     -> mst 
+	  john doe 12     -> jd12
+	  john12 smith    -> j12s
+	  12john smith    -> 12js
+	  john doe test2b -> jst2b
+
+	  note that underscores are treated as separators here,
+          contiguous digits are all printed, and digits
+          are treated as printable separators */
+
+       /* Loop through characters */
+       idst = 0;
+       in_word = FALSE;
+       for (isrc=0; isrc < length; isrc++) {
+	 ch = string[isrc];
+	 if (isalpha(ch) && !in_word) {
+	   in_word = TRUE;
+	   filename[idst++] = tolower(ch);
+	 }
+	 else if (isdigit(ch)) {
+	   in_word = FALSE;
+	   filename[idst++] = ch;
+	 }
+	 else if (!isalnum(ch)) {
+	   in_word = FALSE;
+	 }
+       }
+       
+       /* Add terminating '\0' */
+       filename[idst++] = '\0';
+     
+     } else { /* multiple words with comma separation */
+
+       /* examples of multi-word with comma:  
+
+	  doe, john       -> jd
+	  doe,john        -> jd
+	  doe-smith, john -> jds
+
+	  note that we treat stuff before the comma as the LAST name */
+
+       /* we do two passes:  all the stuff after the comma THEN 
+	  all the stuff before the comma */
+
+       idst = 0;
+
+       /* Loop through characters, writing those after comma*/
+
+       comma_found2 = FALSE;
+       in_word = FALSE;
+       for (isrc=0; isrc < length; isrc++) {
+	 ch = string[isrc];
+
+	 if (isalpha(ch) && !in_word) {
+	   in_word = TRUE;
+	   if (comma_found2) filename[idst++] = tolower(ch);
+	 }
+	 else if (isdigit(ch)) {
+	   in_word = FALSE;
+	   if (comma_found2) filename[idst++] = ch;
+	 }
+	 else if (!isalnum(ch)) {
+	   in_word = FALSE;
+	 }
+
+	 // numaris 4 uses Last^First
+	 if (ch == ',' || ch == '^') {
+	   comma_found2 = TRUE;
+	 }
+       }
+
+       /* now write characters/initials before the comma*/
+       
+       comma_found2 = FALSE;
+       in_word = FALSE;
+       for (isrc=0; isrc < length; isrc++) {
+	 ch = string[isrc];
+
+	 if (isalpha(ch) && !in_word) {
+	   in_word = TRUE;
+	   if (!comma_found2) filename[idst++] = tolower(ch);
+	 }
+	 else if (isdigit(ch)) {
+	   in_word = FALSE;
+	   if (!comma_found2) filename[idst++] = ch;
+	 }
+	 else if (!isalnum(ch)) {
+	   in_word = FALSE;
+	 }
+
+	 // Numaris 4 uses Last^First
+	 if (ch == ',' || ch == '^') {
+	   comma_found2 = TRUE;
+	 }
+       }
+       
+       /* Add terminating '\0' */
+       filename[idst++] = '\0';
+     
+     }
+   }
+
+   return;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/conversion/dcm2mnc/string_to_filename.h
@@ -0,0 +1,2 @@
+extern void string_to_filename(const char *string, char *filename, int maxlen);
+extern void string_to_initials(char *string, char *filename, int maxlen);