This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/master
in repository dcm2niix.

commit da6a7e864029464a35ffeb262451ede3e657c59b
Author: Ghislain Antony Vaillant <ghisv...@gmail.com>
Date:   Sun Feb 4 14:10:46 2018 +0000

    New upstream version 1.0.20171215
---
 README.md                   |   5 +-
 VERSIONS.md                 |   9 +
 console/main_console.cpp    |  69 +++++-
 console/makefile            |  11 +-
 console/nii_dicom.cpp       | 534 +++++++++++++++++++++++++++++++++++++-------
 console/nii_dicom.h         |   8 +-
 console/nii_dicom_batch.cpp | 187 ++++++++++++----
 console/nii_dicom_batch.h   |   3 +
 8 files changed, 695 insertions(+), 131 deletions(-)

diff --git a/README.md b/README.md
index 97eb97b..d1f42ec 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ mkdir build && cd build
 cmake ..
 make
 ```
-`dcm2niix` will be created in the `bin` subfolder. To install on the system 
run `make install`.
+`dcm2niix` will be created in the `bin` subfolder. To install on the system 
run `make install` instead of `make` - this will copy the executable to your 
path so you do not have to provide the full path to the executable.
 
 **optional building with OpenJPEG:**
 
@@ -70,7 +70,8 @@ If you have any problems with the cmake build script 
described above or want to
   - [dcm2niir](https://github.com/muschellij2/dcm2niir) R wrapper for 
dcm2niix/dcm2nii.
   - [divest](https://github.com/jonclayden/divest) R interface to dcm2niix.
   - [sci-tran dcm2niix](https://github.com/scitran-apps/dcm2niix) docker.
-  - [neuro_docker](https://github.com/Neurita/neuro_docker) includes dcm2niix 
as part of a provides a single, static Dockerfile.
+  - [neuro_docker](https://github.com/Neurita/neuro_docker) includes dcm2niix 
as part of a single, static Dockerfile.
+  - [https://github.com/lalet/boutiques-dcm2niix boutiques-dcm2niix] is a 
dockerfile for installing and validating dcm2niix.
   - [neurodocker](https://github.com/kaczmarj/neurodocker) generates 
[custom](https://github.com/rordenlab/dcm2niix/issues/138) Dockerfiles given 
specific versions of neuroimaging software.
   - 
[dcm2niix_afni](https://afni.nimh.nih.gov/pub/dist/doc/program_help/dcm2niix_afni.html)
 is a version of dcm2niix included with the [AFNI](https://afni.nimh.nih.gov/) 
distribution.
   - [MRIcroGL](https://github.com/neurolabusc/MRIcroGL) is available for 
MacOS, Linux and Windows and provides a graphical interface for dcm2niix. You 
can get compiled copies from the [MRIcroGL NITRC web 
site](https://www.nitrc.org/projects/mricrogl/).
\ No newline at end of file
diff --git a/VERSIONS.md b/VERSIONS.md
index 43ef2d4..0d8b611 100644
--- a/VERSIONS.md
+++ b/VERSIONS.md
@@ -1,5 +1,14 @@
 ## Versions
 
+15-Dec-2017
+ - Support [Siemens XA10 
images](https://github.com/rordenlab/dcm2niix/pull/145).
+ - [Ability to select specific series to 
convert](https://github.com/rordenlab/dcm2niix/pull/146).
+
+4-Dec-2017
+ - Handle implicit VR DICOMs where [critical values nested in sequence groups 
(SQ)](https://github.com/rordenlab/dcm2niix/commit/7f5649c6fe6ed366d07776aa54397b50f6641aff)
+ - Better support for [PAR/REC files with segmented 3D 
EPI](https://github.com/rordenlab/dcm2niix/commit/66cdf2dcc60d55a6ef37f5a6db8d500d3eeb7c88).
+ - Allow Protocol Name to be 
[empty](https://github.com/rordenlab/dcm2niix/commit/94f3129898ba83bf310c9ff28e994f29feb13068).
+
 17-Oct-2017
  - Swap [phase-encoding direction 
polarity](https://github.com/rordenlab/dcm2niix/issues/125) for Siemens images 
where PE is in the Column direction.
  - Sort diffusion volumes by [B-value 
amplitude](https://www.nitrc.org/forum/forum.php?thread_id=8396&forum_id=4703) 
(use "-d n"/"-d y" to turn the feature off/on).
diff --git a/console/main_console.cpp b/console/main_console.cpp
index 3608038..a784d2d 100644
--- a/console/main_console.cpp
+++ b/console/main_console.cpp
@@ -89,11 +89,15 @@ void showHelp(const char * argv[], struct TDCMopts opts) {
     printf("  -h : show help\n");
     printf("  -i : ignore derived, localizer and 2D images (y/n, default 
n)\n");
     printf("  -m : merge 2D slices from same series regardless of study time, 
echo, coil, orientation, etc. (y/n, default n)\n");
+    printf("  -n : only convert this series number - can be used up to %i 
times (default convert all)\n", MAX_NUM_SERIES);
     printf("  -o : output directory (omit to save to input folder)\n");
     printf("  -p : Philips precise float (not display) scaling (y/n, default 
y)\n");
     printf("  -s : single file mode, do not convert other images in folder 
(y/n, default n)\n");
     printf("  -t : text notes includes private patient details (y/n, default 
n)\n");
-    printf("  -v : verbose (n/y or 0/1/2 [no, yes, logorrheic], default 0)\n");
+    #if !defined(_WIN64) && !defined(_WIN32) //shell script for Unix only
+       printf("  -u : up-to-date check\n");
+       #endif
+       printf("  -v : verbose (n/y or 0/1/2 [no, yes, logorrheic], default 
0)\n");
     printf("  -x : crop (y/n, default n)\n");
     char gzCh = 'n';
     if (opts.isGz) gzCh = 'y';
@@ -145,6 +149,53 @@ int invalidParam(int i, const char * argv[]) {
        return 1;
 }
 
+#if !defined(_WIN64) && !defined(_WIN32) //shell script for Unix only
+
+int checkUpToDate() {
+       #define URL "/rordenlab/dcm2niix/releases/"
+       #define APIURL "\"https://api.github.com/repos"; URL "latest\""
+       #define HTMURL "https://github.com"; URL
+       #define SHELLSCRIPT "#!/usr/bin/env bash\n curl --silent " APIURL " | 
grep '\"tag_name\":' | sed -E 's/.*\"([^\"]+)\".*/\\1/'"
+       //check first 13 characters, e.g. "v1.0.20171204"
+       #define versionChars 13
+    FILE *pipe = popen(SHELLSCRIPT, "r");
+    char ch, gitvers[versionChars+1];
+    int n = 0;
+    int nMatch = 0;
+    while ((ch = fgetc(pipe)) != EOF) {
+       if (n < versionChars) {
+               gitvers[n] = ch;
+               if (gitvers[n] == kDCMvers[n])
+                       nMatch ++;
+               n ++;
+       }
+    }
+    pclose(pipe);
+       gitvers[n] = 0; //null terminate
+    if (n < 1) { //script reported nothing
+       printf("Error: unable to check version with script:\n %s\n", 
SHELLSCRIPT);
+       return 3; //different from EXIT_SUCCESS (0) and EXIT_FAILURE (1)
+    }
+    if (nMatch == versionChars) { //versions match
+       printf("Good news: Your version is up to date: %s\n", gitvers);
+       return EXIT_SUCCESS;
+    }
+       //report error
+       char myvers[versionChars+1];
+    for (int i = 0; i < versionChars; i++) myvers[i] = kDCMvers[i];
+    myvers[versionChars] = 0; //null terminate
+    int myv = atoi(myvers + 5); //skip "v1.0."
+       int gitv = atoi(gitvers + 5); //skip "v1.0."
+       if (myv > gitv) {
+               printf("Warning: your version ('%s') more recent than stable 
release ('%s')\n %s\n", myvers, gitvers, HTMURL);
+               return 2; //different from EXIT_SUCCESS (0) and EXIT_FAILURE (1)
+       }
+       printf("Error: your version ('%s') is not the latest release ('%s')\n 
%s\n", myvers, gitvers, HTMURL);
+       return EXIT_FAILURE;
+} //checkUpToDate()
+
+#endif //shell script for UNIX only
+
 //#define mydebugtest
 int main(int argc, const char * argv[])
 {
@@ -244,6 +295,10 @@ int main(int argc, const char * argv[])
                     opts.isCreateText = false;
                 else
                     opts.isCreateText = true;
+               #if !defined(_WIN64) && !defined(_WIN32) //shell script for 
Unix only
+            } else if (argv[i][1] == 'u') {
+                               return checkUpToDate();
+                       #endif
             } else if ((argv[i][1] == 'v') && ((i+1) < argc)) {
                 i++;
                 if (invalidParam(i, argv)) return 0;
@@ -279,6 +334,18 @@ int main(int argc, const char * argv[])
             } else if ((argv[i][1] == 'o') && ((i+1) < argc)) {
                 i++;
                 strcpy(opts.outdir,argv[i]);
+            } else if ((argv[i][1] == 'n') && ((i+1) < argc)) {
+              i++;
+              int seriesNumber = atoi(argv[i]);
+              if (seriesNumber < 0)
+               opts.numSeries = -1; //report series: convert none
+              else if ((opts.numSeries >= 0) && (opts.numSeries < 
MAX_NUM_SERIES)) {
+                  opts.seriesNumber[opts.numSeries] = seriesNumber;
+                  opts.numSeries += 1;
+                }
+                else {
+                  printf("Warning: too many series specified, ignoring -n 
%s\n", argv[i]);
+                }
             } else
              printf(" Error: invalid option '%s %s'\n", argv[i], argv[i+1]);;
             lastCommandArg = i;
diff --git a/console/makefile b/console/makefile
index 3fe5ea4..4b0c688 100755
--- a/console/makefile
+++ b/console/makefile
@@ -1,9 +1,14 @@
-CFLAGS=-s
+# Regular use
+CFLAGS=-s -O3
+
+# Debugging
+#CFLAGS=-g
+
 ifneq ($(OS),Windows_NT)
        OS = $(shell uname)
        ifeq "$(OS)" "Darwin"
-               CFLAGS=-dead_strip
+               CFLAGS=-dead_strip -O3
        endif
 endif
 all:
-       g++ $(CFLAGS) -O3 -I. main_console.cpp nii_foreign.cpp nii_dicom.cpp 
jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  -o 
dcm2niix -DmyDisableOpenJPEG
+       g++ $(CFLAGS) -I. main_console.cpp nii_foreign.cpp nii_dicom.cpp 
jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  -o 
dcm2niix -DmyDisableOpenJPEG
diff --git a/console/nii_dicom.cpp b/console/nii_dicom.cpp
index a4f7451..7ad2926 100644
--- a/console/nii_dicom.cpp
+++ b/console/nii_dicom.cpp
@@ -657,6 +657,8 @@ struct TDICOMdata clear_dicom_data() {
         d.angulation[i] = 0.0f;
         d.xyzMM[i] = 1;
     }
+    for (int i=0; i < MAX_NUMBER_OF_DIMENSIONS; ++i)
+      d.dimensionIndexValues[i] = 0;
     d.CSA.sliceTiming[0] = -1.0f; //impossible value denotes not known
     d.CSA.numDti = 0;
     for (int i=0; i < 5; i++)
@@ -840,7 +842,7 @@ void dcmStr(int lLength, unsigned char lBuffer[], char* 
lOut, bool isStrLarge =
             if (c == 255) cString[i] = 'y';
         }
     for (int i = 0; i < lLength; i++)
-        if ((cString[i]<1) || (cString[i]==' ') || (cString[i]==',') || 
(cString[i]=='^') || (cString[i]=='/') || (cString[i]=='\\')  || 
(cString[i]=='%') || (cString[i]=='*')) cString[i] = '_';
+        if ((cString[i]<1) || (cString[i]==' ') || (cString[i]==',') || 
(cString[i]=='^') || (cString[i]=='/') || (cString[i]=='\\')  || 
(cString[i]=='%') || (cString[i]=='*') || (cString[i] == 9) || (cString[i] == 
10) || (cString[i] == 11) || (cString[i] == 13)) cString[i] = '_';
     int len = 1;
     for (int i = 1; i < lLength; i++) { //remove repeated "_"
         if ((cString[i-1]!='_') || (cString[i]!='_')) {
@@ -888,7 +890,8 @@ float dcmFloat(int lByteLength, unsigned char lBuffer[], 
bool littleEndian) {//r
     return swapVal;
 } //dcmFloat()
 
-double dcmFloatDouble(int lByteLength, unsigned char lBuffer[], bool 
littleEndian) {//read binary 32-bit float
+double dcmFloatDouble(const size_t lByteLength, const unsigned char lBuffer[],
+                      const bool littleEndian) {//read binary 32-bit float
     
//http://stackoverflow.com/questions/2782725/converting-float-values-from-big-endian-to-little-endian
     bool swap = (littleEndian != littleEndianPlatform());
     double retVal = 0.0f;
@@ -921,14 +924,14 @@ int dcmInt (int lByteLength, unsigned char lBuffer[], 
bool littleEndian) { //rea
     return lBuffer[3]+(lBuffer[2]<<8)+(lBuffer[1]<<16)+(lBuffer[0]<<24); 
//shortint vs word?
 } //dcmInt()
 
-int dcmStrInt (int lByteLength, unsigned char lBuffer[]) {//read float stored 
as a string
+int dcmStrInt (const int lByteLength, const unsigned char lBuffer[]) {//read 
float stored as a string
 //#ifdef _MSC_VER
        char * cString = (char *)malloc(sizeof(char) * (lByteLength + 1));
 //#else
 //     char cString[lByteLength + 1];
 //#endif
     cString[lByteLength] =0;
-    memcpy(cString, (char*)&lBuffer[0], lByteLength);
+    memcpy(cString, (const unsigned char*)(&lBuffer[0]), lByteLength);
     //printMessage(" --> *%s* %s%s\n",cString, &lBuffer[0],&lBuffer[1]);
     int ret = atoi(cString);
 //#ifdef _MSC_VER
@@ -937,7 +940,7 @@ int dcmStrInt (int lByteLength, unsigned char lBuffer[]) 
{//read float stored as
        return ret;
 } //dcmStrInt()
 
-int dcmStrManufacturer (int lByteLength, unsigned char lBuffer[]) {//read 
float stored as a string
+int dcmStrManufacturer (const int lByteLength, unsigned char lBuffer[]) 
{//read float stored as a string
     if (lByteLength < 2) return kMANUFACTURER_UNKNOWN;
 //#ifdef _MSC_VER
        char * cString = (char *)malloc(sizeof(char) * (lByteLength + 1));
@@ -1158,6 +1161,7 @@ int readCSAImageHeader(unsigned char *buff, int lLength, 
struct TCSAdata *CSA, i
             }
         } //if at least 1 item
     }// for lT 1..lnTag
+    if (CSA->protocolSliceNumber1 > 1) CSA->sliceOrder = NIFTI_SLICE_UNKNOWN;
     return EXIT_SUCCESS;
 } // readCSAImageHeader()
 
@@ -1170,6 +1174,16 @@ void dcmMultiShorts (int lByteLength, unsigned char 
lBuffer[], int lnShorts, uin
        nifti_swap_2bytes(lnShorts, &lShorts[0]);
 } //dcmMultiShorts()
 
+void dcmMultiLongs (int lByteLength, unsigned char lBuffer[], int lnLongs, 
uint32_t *lLongs, bool littleEndian) {
+  //read array of unsigned longs UL 
http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html
+  if((lnLongs < 1) || (lByteLength != (lnLongs * 4)))
+    return;
+  memcpy(&lLongs[0], (uint32_t *)&lBuffer[0], lByteLength);
+  bool swap = (littleEndian != littleEndianPlatform());
+  if (swap)
+    nifti_swap_4bytes(lnLongs, &lLongs[0]);
+} //dcmMultiLongs()
+
 void dcmMultiFloat (int lByteLength, char lBuffer[], int lnFloats, float 
*lFloats) {
     //warning: lFloats indexed from 1! will fill lFloats[1]..[nFloats]
     if ((lnFloats < 1) || (lByteLength < 1)) return;
@@ -1204,7 +1218,7 @@ void dcmMultiFloat (int lByteLength, char lBuffer[], int 
lnFloats, float *lFloat
 //#endif
 } //dcmMultiFloat()
 
-float dcmStrFloat (int lByteLength, unsigned char lBuffer[]) { //read float 
stored as a string
+float dcmStrFloat (const int lByteLength, const unsigned char lBuffer[]) { 
//read float stored as a string
 //#ifdef _MSC_VER
        char * cString = (char *)malloc(sizeof(char) * (lByteLength + 1));
 //#else
@@ -1375,19 +1389,29 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
 #define        kYmm    29
 #define        kTEcho  30
 #define        kDynTime        31
-#define        kGradientNumber 42
 #define        kbval 33
+#define        kInversionDelayMs 40
+#define        kGradientNumber 42
 #define        kv1     47
 #define        kv2     45
 #define        kv3     46
 #define        kASL    48
     char buff[LINESZ];
+    int sliceNumberMrPhilipsB2[kMaxDTI4D], sliceNumberMrPhilipsVol2[kMaxDTI4D];
+    int patientPositionNumPhilipsB2 = 0;
+    int patientPositionNumPhilipsVol2 = 0;
     //float intenScalePhilips = 0.0f;
     float maxBValue = 0.0f;
     float maxDynTime = 0.0f;
     float minDynTime = 999999.0f;
+    int minDyn = 32767;
+    int maxDyn = 0;
     bool ADCwarning = false;
+    int prevDyn = -1;
+    bool dynNotAscending = false;
     int parVers = 0;
+    int maxEcho = 1;
+    int maxCardiac = 1;
     int nCols = 26;
     int slice = 0;
     //int prevSliceIndex = 0; //index of prior slice: detect if images are not 
in order
@@ -1426,7 +1450,6 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
         if (buff[0] == '.') { //tag
             char Comment[8][50];
             sscanf(buff, ". %s %s %s %s %s %s %s %s\n", Comment[0], 
Comment[1],Comment[2], Comment[3], Comment[4], Comment[5], Comment[6], 
Comment[7]);
-
             if ((strcmp(Comment[0], "Acquisition") == 0) && 
(strcmp(Comment[1], "nr") == 0)) {
                 d.acquNum = atoi( Comment[3]);
                 d.seriesNum = d.acquNum;
@@ -1490,6 +1513,8 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
         if (slice == 1) {
             //for (int i = 0; i < nCols; i++)
             //    cols1[i] = cols[i]; //store first slice to see if dimensions 
or intensity scale varies between slices
+            //for (int i = 0; i < nCols; i++)
+            //    printMessage("%d %g\n",i, cols[i]); //store first slice to 
see if dimensions or intensity scale varies between slices
             d.xyzDim[1] = (int) cols[kXdim];
                        d.xyzDim[2] = (int) cols[kYdim];
             d.xyzMM[1] = cols[kXmm];
@@ -1503,6 +1528,7 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
             d.angulation[3] = cols[kAngulationFHs];
                        d.sliceOrient = (int) cols[kSliceOrients];
             d.TE = cols[kTEcho];
+                       d.TI = cols[kInversionDelayMs];
                        d.bitsAllocated = (int) cols[kBitsPerVoxel];
                        d.bitsStored = (int) cols[kBitsPerVoxel];
             d.intenIntercept = cols[kRI];
@@ -1523,8 +1549,22 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
         }
         if (cols[kImageType] == 0) d.isHasMagnitude = true;
         if (cols[kImageType] != 0) d.isHasPhase = true;
+        if (cols[kDyn] > maxDyn) maxDyn = (int) cols[kDyn];
+        if (cols[kDyn] < minDyn) minDyn = (int) cols[kDyn];
+        if (cols[kDyn] < prevDyn) dynNotAscending = true;
+        prevDyn = cols[kDyn];
         if (cols[kDynTime] > maxDynTime) maxDynTime = cols[kDynTime];
         if (cols[kDynTime] < minDynTime) minDynTime = cols[kDynTime];
+        if (cols[kEcho] > maxEcho) maxEcho = cols[kEcho];
+        if (cols[kCardiac] > maxCardiac) maxCardiac = cols[kCardiac];
+        if ((cols[kEcho] == 1) && (cols[kDyn] == 1) && 
(patientPositionNumPhilipsB2 < kMaxDTI4D) && (cols[kCardiac] == 1) && 
(cols[kGradientNumber] == 2)) {
+                       sliceNumberMrPhilipsB2[patientPositionNumPhilipsB2] = 
round(cols[kSlice]);
+                       patientPositionNumPhilipsB2++;
+               }
+        if ((cols[kEcho] == 1) && (cols[kDyn] == 2) && 
(patientPositionNumPhilipsVol2 < kMaxDTI4D) && (cols[kCardiac] == 1) && 
(cols[kGradientNumber] == 1)) {
+                       sliceNumberMrPhilipsVol2[patientPositionNumPhilipsVol2] 
= round(cols[kSlice]);
+                       patientPositionNumPhilipsVol2++;
+               }
         if ((cols[kEcho] == 1) && (cols[kDyn] == 1) && (cols[kCardiac] == 1) 
&& (cols[kGradientNumber] == 1)) {
                        if (cols[kSlice] == 1) {
                                d.patientPosition[1] = cols[kPositionRL];
@@ -1548,14 +1588,16 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
                 //it seems like the ADC is always saved as the final volume, 
so this solution SHOULD be foolproof.
                 ADCwarning = true;
             }*/
-            if (cols[kSlice] == 1) { //only first slice
+            //666: test (cols[kDyn] == 1)
+            //(cols[kImageType] == 0) means magnitude scan
+            if ((cols[kImageType] == 0) && (cols[kDyn] == 1) && (cols[kEcho] 
== 1) && (cols[kCardiac] == 1)  && (cols[kSlice] == 1)) { //only first slice
                 d.CSA.numDti++;
                 int dir = d.CSA.numDti;
                 if (dir <= kMaxDTI4D) {
                     if (isVerbose ) {
                         if (d.CSA.numDti == 1) 
printMessage("n\tdir\tbValue\tV1\tV2\tV3\n");
                         printMessage("%d\t%g\t%g\t%g\t%g\t%g\n", dir-1, 
cols[kGradientNumber], cols[kbval], cols[kv1], cols[kv2], cols[kv3]);
-                    }
+                       }
                     dti4D->S[dir-1].V[0] = cols[kbval];
                     dti4D->S[dir-1].V[1] = cols[kv1];
                     dti4D->S[dir-1].V[2] = cols[kv2];
@@ -1568,15 +1610,31 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
         //printMessage("%f %f %lu\n",cols[9],cols[kGradientNumber], 
strlen(buff))
         p = fgets (buff, LINESZ, fp);//get next line
     }
-
     free (cols);
     fclose (fp);
     d.manufacturer = kMANUFACTURER_PHILIPS;
     d.isValid = true;
     d.isSigned = true;
+    if ((patientPositionNumPhilipsB2 > 1) && (patientPositionNumPhilipsVol2 < 
1)) {
+       patientPositionNumPhilipsVol2 = patientPositionNumPhilipsB2;
+       for (int s = 0; s < patientPositionNumPhilipsVol2; s++)
+               sliceNumberMrPhilipsVol2[s] = sliceNumberMrPhilipsB2[s];
+    }
+    if ((patientPositionNumPhilipsVol2 > 1) && (d.patientPositionNumPhilips == 
patientPositionNumPhilipsVol2)) {
+       bool isSliceOrderConsistent = true;
+       for (int s = 0; s < patientPositionNumPhilipsVol2; s++)
+               if (sliceNumberMrPhilipsVol2[s] != 
dti4D->S[s].sliceNumberMrPhilips) isSliceOrderConsistent = false;
+        if (!isSliceOrderConsistent)
+               printError("PAR file order of slices varies between volumes 
(hint: use dicm2nii)\n");
+        d.isValid = false;
+       }
+    if (dynNotAscending) {
+        printError("PAR file volumes not saved in ascending order (hint: use 
dicm2nii)\n");
+        d.isValid = false;
+    }
     if ((slice % d.xyzDim[3]) != 0) {
-        printError("Total number of slices (%d) not divisible by slices per 3D 
volume (%d) [acquisition aborted]. Try nii_rescue_par to fix this: %s\n", 
slice, d.xyzDim[3], parname);
-        d.isValid = true;
+        printError("Total number of slices (%d) not divisible by slices per 3D 
volume (%d) [acquisition aborted]. Try dicm2nii or nii_rescue_par to fix this: 
%s\n", slice, d.xyzDim[3], parname);
+        d.isValid = false;
     }
     d.xyzDim[4] = slice/d.xyzDim[3];
     d.locationsInAcquisition = d.xyzDim[3];
@@ -1665,8 +1723,10 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
         printError("Unable to convert DTI [increase kMaxDTI4D]\n");
         d.CSA.numDti = 0;
     };
-    if ((maxBValue <= 0.0f) && (maxDynTime > minDynTime) && (d.CSA.numDti > 
1)) {
-       float TRms =  1000.0f * (maxDynTime - minDynTime) / 
(float)(d.CSA.numDti-1);
+    if ((maxBValue <= 0.0f) && (maxDyn > minDyn) && (maxDynTime > minDynTime)) 
{ //use max vs min Dyn instead of && (d.CSA.numDti > 1)
+       int numDyn = maxDyn - minDyn;
+       float TRms =  1000.0f * (maxDynTime - minDynTime) / (float)numDyn;
+       //float TRms =  1000.0f * (maxDynTime - minDynTime) / 
(float)(d.CSA.numDti-1);
        if (fabs(TRms - d.TR) > 0.005f)
                printWarning("Reported TR=%gms, measured TR=%gms (prospect. 
motion corr.?)\n", d.TR, TRms);
        d.TR = TRms;
@@ -1684,6 +1744,7 @@ struct TDICOMdata  nii_readParRec (char * parname, int 
isVerbose, struct TDTI4D
        if ((!v1varies) || (!v2varies) || (!v3varies))
                 printError("Bizarre b-vectors %s\n", parname);
     }
+    if ((maxEcho > 1) || (maxCardiac > 1)) printWarning("Multiple Echo (%d) or 
Cardiac (%d). Segment output, e.g. nii_segment4d('img.nii', %d)\n", maxEcho,  
maxCardiac, maxEcho*maxCardiac);
     return d;
 } //nii_readParRec()
 
@@ -1843,6 +1904,7 @@ unsigned char * nii_reorderSlices(unsigned char* bImg, 
struct nifti_1_header *h,
        memcpy(&srcImg[0], &bImg[volStart], volBytes); //dest, src, size
        for (int z = 0; z < h->dim[3]; z++) { //for each slice
                        int src = dti4D->S[z].sliceNumberMrPhilips - 1; //-1 as 
Philips indexes slices from 1 not 0
+                       //printMessage("Reordering volume %d slice %d\n", v, 
dti4D->S[z].sliceNumberMrPhilips);
                        if ((src < 0) || (src >= h->dim[3])) continue;
                        memcpy(&bImg[volStart+(src*sliceBytes)], 
&srcImg[z*sliceBytes], sliceBytes); //dest, src, size
        }
@@ -2621,6 +2683,17 @@ unsigned char * nii_loadImgXL(char* imgname, struct 
nifti_1_header *hdr, struct
     return img;
 } //nii_loadImgXL()
 
+int isSQ(uint32_t groupElement) { //Detect sequence VR ("SQ") for implicit tags
+    static const int array_size = 34;
+    uint32_t array[array_size] = {0x2005+(uint32_t(0x140F)<<16), 
0x0008+(uint32_t(0x1111)<<16), 0x0008+(uint32_t(0x1115)<<16), 
0x0008+(uint32_t(0x1140)<<16), 0x0008+(uint32_t(0x1199)<<16), 
0x0008+(uint32_t(0x2218)<<16), 0x0008+(uint32_t(0x9092)<<16), 
0x0018+(uint32_t(0x9006)<<16), 0x0018+(uint32_t(0x9042)<<16), 
0x0018+(uint32_t(0x9045)<<16), 0x0018+(uint32_t(0x9049)<<16), 
0x0018+(uint32_t(0x9112)<<16), 0x0018+(uint32_t(0x9114)<<16), 
0x0018+(uint32_t(0x9115)<<16), 0x0018+(uint32_t(0x9119) [...]
+    for (int i = 0; i < array_size; i++) {
+        //if (array[i] == groupElement) printMessage(" implicitSQ 
%04x,%04x\n",   groupElement & 65535,groupElement>>16);
+        if (array[i] == groupElement)
+            return 1;
+    }
+    return 0;
+} //isSQ()
+
 int isDICOMfile(const char * fname) { //0=NotDICOM, 1=DICOM, 2=Maybe(not Part 
10 compliant)
     FILE *fp = fopen(fname, "rb");
        if (!fp)  return 0;
@@ -2642,6 +2715,196 @@ int isDICOMfile(const char * fname) { //0=NotDICOM, 
1=DICOM, 2=Maybe(not Part 10
     return 0;
 } //isDICOMfile()
 
+//START RIR 12/2017 Robert I. Reid
+
+// Gathering spot for all the info needed to get the b value and direction
+// for a volume.
+struct TVolumeDiffusion {
+    struct TDICOMdata* pdd;  // The multivolume
+    struct TDTI4D* pdti4D;   // permanent records.
+
+    uint8_t manufacturer;            // kMANUFACTURER_UNKNOWN, 
kMANUFACTURER_SIEMENS, etc.
+
+    //void set_manufacturer(const uint8_t m) {manufacturer = m; update();}  // 
unnecessary
+
+    // Everything after this in the structure would be private if it were a C++
+    // class, but it has been rewritten as a struct for C compatibility.  I am
+    // using _ as a hint of that, although _ for privacy is not really a
+    // universal convention in C.  Privacy is desired because immediately
+    // any of these are updated _update_tvd() should be called.
+
+    bool _isAtFirstPatientPosition;   // Limit b vals and vecs to 1 per volume.
+
+    //float bVal0018_9087;      // kDiffusion_b_value, always present in 
Philips/Siemens.
+    //float bVal2001_1003;        // kDiffusionBFactor
+    // float dirRL2005_10b0;        // kDiffusionDirectionRL
+    // float dirAP2005_10b1;        // kDiffusionDirectionAP
+    // float dirFH2005_10b2;        // kDiffusionDirectionFH
+
+    // Philips diffusion scans tend to have a "trace" (average of the diffusion
+    // weighted volumes) volume tacked on, usually but not always at the end,
+    // so b is > 0, but the direction is meaningless.  Most software versions
+    // explicitly set the direction to 0, but version 3 does not, making (0x18,
+    // 0x9075) necessary.
+    bool _isPhilipsNonDirectional;
+
+    //char _directionality0018_9075[16];   // DiffusionDirectionality, not in 
Philips 2.6.
+    // float _orientation0018_9089[3];      // kDiffusionOrientation, always
+    //                                      // present in Philips/Siemens for
+    //                                      // volumes with a direction.
+    //char _seq0018_9117[64];              // MRDiffusionSequence, not in 
Philips 2.6.
+
+    float _dtiV[4];
+    //uint16_t numDti;
+};
+struct TVolumeDiffusion initTVolumeDiffusion(struct TDICOMdata* ptdd, struct 
TDTI4D* dti4D);
+void clear_volume(struct TVolumeDiffusion* ptvd); // Blank the volume-specific 
members or set them to impossible values.
+void set_directionality0018_9075(struct TVolumeDiffusion* ptvd, unsigned char* 
inbuf);
+void set_orientation0018_9089(struct TVolumeDiffusion* ptvd, int lLength, 
unsigned char* inbuf,
+                              bool isLittleEndian);
+void set_isAtFirstPatientPosition_tvd(struct TVolumeDiffusion* ptvd, bool 
iafpp);
+void set_bValGE(struct TVolumeDiffusion* ptvd, int lLength, unsigned char* 
inbuf);
+void set_diffusion_directionGE(struct TVolumeDiffusion* ptvd, int lLength, 
unsigned char* inbuf,  int axis);
+void set_bVal(struct TVolumeDiffusion* ptvd, float b);
+void _update_tvd(struct TVolumeDiffusion* ptvd);
+
+struct TVolumeDiffusion initTVolumeDiffusion(struct TDICOMdata* ptdd, struct 
TDTI4D* dti4D) {
+    struct TVolumeDiffusion tvd;
+    tvd.pdd = ptdd;
+    tvd.pdti4D = dti4D;
+    clear_volume(&tvd);
+    return tvd;
+} //initTVolumeDiffusion()
+
+void clear_volume(struct TVolumeDiffusion* ptvd) {
+    ptvd->_isAtFirstPatientPosition = false;
+    ptvd->manufacturer = kMANUFACTURER_UNKNOWN;
+    //bVal0018_9087 = -1;
+    //ptvd->_directionality0018_9075[0] = 0;
+    //ptvd->seq0018_9117[0] = 0;
+    //bVal2001_1003 = -1;
+    // dirRL2005_10b0 = 2;
+    // dirAP2005_10b1 = 2;
+    // dirFH2005_10b2 = 2;
+    ptvd->_isPhilipsNonDirectional = false;
+    ptvd->_dtiV[0] = -1;
+    for(int i = 1; i < 4; ++i)
+        ptvd->_dtiV[i] = 2;
+    //numDti = 0;
+}//clear_volume()
+
+void set_directionality0018_9075(struct TVolumeDiffusion* ptvd, unsigned char* 
inbuf) {
+    if(strncmp(( char*)(inbuf), "DIRECTIONAL", 11) &&  // strncmp = 0 for ==.
+       strncmp(( char*)(inbuf), "BMATRIX", 7)){        // Siemens XA10
+        ptvd->_isPhilipsNonDirectional = true;
+        // Explicitly set the direction to 0 now, because there may
+        // not be a 0018,9089 for this frame.
+        for(int i = 1; i < 4; ++i)  // 1-3 is intentional.
+            ptvd->_dtiV[i] = 0.0;
+    }
+    else{
+        ptvd->_isPhilipsNonDirectional = false;
+        // Wait for 0018,9089 to get the direction.
+    }
+
+    _update_tvd(ptvd);
+} //set_directionality0018_9075()
+
+void set_bValGE(struct TVolumeDiffusion* ptvd, int lLength, unsigned char* 
inbuf) {
+    //int dcmStrInt (int lByteLength, unsigned char lBuffer[]) {//read float 
stored as a string
+dcmStrInt(lLength, inbuf);
+
+    ptvd->_dtiV[0] = dcmStrInt(lLength, inbuf);
+    //dd.CSA.numDti = 1;   // Always true for GE.
+
+    _update_tvd(ptvd);
+} //set_bValGE()
+
+// axis: 0 -> x, 1 -> y , 2 -> z
+void set_diffusion_directionGE(struct TVolumeDiffusion* ptvd, int lLength, 
unsigned char* inbuf, const int axis){
+    ptvd->_dtiV[axis + 1] = dcmStrFloat(lLength, inbuf);
+
+    _update_tvd(ptvd);
+}//set_diffusion_directionGE()
+
+void dcmMultiFloatDouble (size_t lByteLength, unsigned char lBuffer[], size_t 
lnFloats, float *lFloats, bool isLittleEndian) {
+    size_t floatlen = lByteLength / lnFloats;
+
+    for(size_t i = 0; i < lnFloats; ++i)
+        lFloats[i] = dcmFloatDouble((int)floatlen, lBuffer + i * floatlen, 
isLittleEndian);
+} //dcmMultiFloatDouble()
+
+void set_orientation0018_9089(struct TVolumeDiffusion* ptvd, int lLength, 
unsigned char* inbuf, bool isLittleEndian) {
+    if(ptvd->_isPhilipsNonDirectional){
+        for(int i = 1; i < 4; ++i) // Deliberately ignore inbuf; it might be 
nonsense.
+            ptvd->_dtiV[i] = 0.0;
+    }
+    else
+        dcmMultiFloatDouble(lLength, inbuf, 3, ptvd->_dtiV + 1, 
isLittleEndian);
+    _update_tvd(ptvd);
+}//set_orientation0018_9089()
+
+void set_bVal(struct TVolumeDiffusion* ptvd, const float b) {
+    ptvd->_dtiV[0] = b;
+    _update_tvd(ptvd);
+}//set_bVal()
+
+void set_isAtFirstPatientPosition_tvd(struct TVolumeDiffusion* ptvd, const 
bool iafpp) {
+    ptvd->_isAtFirstPatientPosition = iafpp;
+    _update_tvd(ptvd);
+}//set_isAtFirstPatientPosition_tvd()
+
+// Update the diffusion info in dd and *pdti4D for a volume once all the
+// diffusion info for that volume has been read into pvd.
+//
+// Note that depending on the scanner software the diffusion info can arrive in
+// different tags, in different orders (because of enclosing sequence tags),
+// and the values in some tags may be invalid, or may be essential, depending
+// on the presence of other tags.  Thus it is best to gather all the diffusion
+// info for a volume (frame) before taking action on it.
+//
+// On the other hand, dd and *pdti4D need to be updated as soon as the
+// diffusion info is ready, before diffusion info for the next volume is read
+// in.
+void _update_tvd(struct TVolumeDiffusion* ptvd) {
+    // Figure out if we have both the b value and direction (if any) for this
+    // volume, and if isFirstPosition.
+
+    // // GE (software version 27) is liable to NOT include kDiffusion_b_value 
for the
+    // // slice if it is 0, but should still have kDiffusionBFactor, which 
comes
+    // // after PatientPosition.
+    // if(isAtFirstPatientPosition && manufacturer == kMANUFACTURER_GE && 
dtiV[0] < 0)
+    //   dtiV[0] = 0;  // Implied 0.
+
+    bool isReady = (ptvd->_isAtFirstPatientPosition && (ptvd->_dtiV[0] >= 0));
+    if(isReady){
+        for(int i = 1; i < 4; ++i){
+            if(ptvd->_dtiV[i] > 1){
+                isReady = false;
+                break;
+            }
+        }
+    }
+    if(!isReady)
+        return;
+
+    // If still here, update dd and *pdti4D.
+    ptvd->pdd->CSA.numDti++;
+    if (ptvd->pdd->CSA.numDti == 2) {                  // First time we know 
that this is a 4D DTI dataset;
+        for(int i = 0; i < 4; ++i)                       // Start *pdti4D 
before ptvd->pdd->CSA.dtiV
+            ptvd->pdti4D->S[0].V[i] = ptvd->pdd->CSA.dtiV[i];    // is updated.
+    }
+    for(int i = 0; i < 4; ++i)                         // Update pdd
+        ptvd->pdd->CSA.dtiV[i] = ptvd->_dtiV[i];
+    if((ptvd->pdd->CSA.numDti > 1) && (ptvd->pdd->CSA.numDti < kMaxDTI4D)){   
// Update *pdti4D
+        //d.dti4D = (TDTI *)malloc(kMaxDTI4D * sizeof(TDTI));
+        for(int i = 0; i < 4; ++i)
+            ptvd->pdti4D->S[ptvd->pdd->CSA.numDti - 1].V[i] = ptvd->_dtiV[i];
+    }
+    clear_volume(ptvd); // clear the slate for the next volume.
+}//_update_tvd()
+//END RIR
+
 struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, 
struct TDTI4D *dti4D) {
        struct TDICOMdata d = clear_dicom_data();
     strcpy(d.protocolName, ""); //erase dummy with empty
@@ -2649,6 +2912,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, 
int compressFlag, stru
     strcpy(d.seriesDescription, ""); //erase dummy with empty
     strcpy(d.sequenceName, ""); //erase dummy with empty
     //do not read folders - code specific to GCC (LLVM/Clang seems to 
recognize a small file size)
+
+    struct TVolumeDiffusion volDiffusion = initTVolumeDiffusion(&d, dti4D);
+
     struct stat s;
     if( stat(fname,&s) == 0 ) {
         if( !(s.st_mode & S_IFREG) ){
@@ -2716,6 +2982,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, 
int compressFlag, stru
 #define  kUnused 0x0001+(0x0001 << 16 )
 #define  kStart 0x0002+(0x0000 << 16 )
 #define  kTransferSyntax 0x0002+(0x0010 << 16)
+//#define  kImplementationVersionName 0x0002+(0x0013 << 16)
 #define  kSourceApplicationEntityTitle 0x0002+(0x0016 << 16 )
 //#define  kSpecificCharacterSet 0x0008+(0x0005 << 16 ) //someday we should 
handle foreign characters...
 #define  kImageTypeTag 0x0008+(0x0008 << 16 )
@@ -2772,12 +3039,19 @@ struct TDICOMdata readDICOMv(char * fname, int 
isVerbose, int compressFlag, stru
 #define  kInPlanePhaseEncodingDirection  0x0018+(0x1312<< 16 ) //CS
 #define  kSAR  0x0018+(0x1316 << 16 ) //'DS' 'SAR'
 #define  kPatientOrient  0x0018+(0x5100<< 16 )    //0018,5100. patient 
orientation - 'HFS'
+#define  kDiffusionDirectionality  0x0018+uint32_t(0x9075<< 16 )   // NONE, 
ISOTROPIC, or DIRECTIONAL
 //#define  kDiffusionBFactorSiemens  0x0019+(0x100C<< 16 ) //   
0019;000C;SIEMENS MR HEADER  ;B_value
+#define  kDiffusion_bValue  0x0018+uint32_t(0x9087<< 16 ) // FD
+#define  kDiffusionOrientation  0x0018+uint32_t(0x9089<< 16 ) // FD, seen in 
enhanced
+                                                              // DICOM from 
Philips 5.*
+                                                              // and Siemens 
XA10.
 #define  kDwellTime  0x0019+(0x1018<< 16 ) //IS in NSec, see 
https://github.com/rordenlab/dcm2niix/issues/127
 #define  kLastScanLoc  0x0019+(0x101B<< 16 )
 #define  kDiffusionDirectionGEX  0x0019+(0x10BB<< 16 ) //DS
 #define  kDiffusionDirectionGEY  0x0019+(0x10BC<< 16 ) //DS
 #define  kDiffusionDirectionGEZ  0x0019+(0x10BD<< 16 ) //DS
+#define  kSharedFunctionalGroupsSequence  0x5200+uint32_t(0x9229<< 16 ) // SQ
+#define  kPerFrameFunctionalGroupsSequence  0x5200+uint32_t(0x9230<< 16 ) // SQ
 #define  kBandwidthPerPixelPhaseEncode  0x0019+(0x1028<< 16 ) //FD
 #define  kStudyID 0x0020+(0x0010 << 16 )
 #define  kSeriesNum 0x0020+(0x0011 << 16 )
@@ -2785,11 +3059,12 @@ struct TDICOMdata readDICOMv(char * fname, int 
isVerbose, int compressFlag, stru
 #define  kImageNum 0x0020+(0x0013 << 16 )
 #define  kStudyInstanceUID 0x0020+(0x000D << 16 )
 #define  kSeriesInstanceUID 0x0020+(0x000E << 16 )
-#define  kPatientPosition 0x0020+(0x0032 << 16 )
+#define  kPatientPosition 0x0020+(0x0032 << 16 )   // Actually 
ImagePositionPatient!
 #define  kOrientationACR 0x0020+(0x0035 << 16 )
 #define  kOrientation 0x0020+(0x0037 << 16 )
 #define  kImagesInAcquisition 0x0020+(0x1002 << 16 ) //IS
 #define  kImageComments 0x0020+(0x4000<< 16 )// '0020' '4000' 'LT' 
'ImageComments'
+#define  kDimensionIndexValues 0x0020+uint32_t(0x9157<< 16 ) // UL 
n-dimensional index of frame.
 #define  kLocationsInAcquisitionGE 0x0021+(0x104F<< 16 )// 'SS' 
'LocationsInAcquisitionGE'
 #define  kSamplesPerPixel 0x0028+(0x0002 << 16 )
 #define  kPhotometricInterpretation 0x0028+(0x0004 << 16 )
@@ -2838,7 +3113,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, 
int compressFlag, stru
 #define  kDiffusionDirectionRL 0x2005+(0x10B0 << 16)
 #define  kDiffusionDirectionAP 0x2005+(0x10B1 << 16)
 #define  kDiffusionDirectionFH 0x2005+(0x10B2 << 16)
-#define  k2005140F 0x2005+(0x140F << 16)
+#define  kPrivatePerFrameSq 0x2005+(0x140F << 16)
 #define  kWaveformSq 0x5400+(0x0100 << 16)
 #define  kImageStart 0x7FE0+(0x0010 << 16 )
 #define  kImageStartFloat 0x7FE0+(0x0008 << 16 )
@@ -2864,6 +3139,7 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
     //float intenScalePhilips = 0.0;
     char acquisitionDateTimeTxt[kDICOMStr] = "";
     bool isEncapsulatedData = false;
+    int multiBandFactor = 0;
     int encapsulatedDataFragments = 0;
     int encapsulatedDataFragmentStart = 0; //position of first FFFE,E000 for 
compressed images
     int encapsulatedDataImageStart = 0; //position of 7FE0,0010 for compressed 
images (where actual image start should be start of first fragment)
@@ -2881,6 +3157,7 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
     float patientPosition[4] = {NAN, NAN, NAN, NAN}; //used to compute slice 
direction for Philips 4D
     float patientPositionEndPhilips[4] = {NAN, NAN, NAN, NAN};
     float patientPositionStartPhilips[4] = {NAN, NAN, NAN, NAN};
+
     while ((d.imageStart == 0) && ((lPos+8+lFileOffset) <  fileLen)) {
        #ifndef myLoadWholeFileToReadHeader //read one segment at a time
        if ((size_t)(lPos + 128) > MaxBufferSz) { //avoid overreading the file
@@ -2940,7 +3217,8 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 lPos = lPos + 4;  //skip 4 byte length
             } else if   ((buffer[lPos] == 'S') && (buffer[lPos+1] == 'Q')) {
                 lLength = 8; //Sequence Tag
-                is2005140FSQ = (groupElement == k2005140F);
+                //printMessage(" !!!SQ\t%04x,%04x\n",   groupElement & 
65535,groupElement>>16);
+                is2005140FSQ = (groupElement == kPrivatePerFrameSq);
             } else { //explicit VR with 16-bit length
                 if ((d.isLittleEndian)  )
                     lLength = buffer[lPos+2] | (buffer[lPos+3] << 8);
@@ -2956,13 +3234,19 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
             else
                 lLength = buffer[lPos+3] | (buffer[lPos+2] << 8) | 
(buffer[lPos+1] << 16) | (buffer[lPos] << 24);
             lPos += 4;  //we have loaded the 32-bit length
+            if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isSQ(groupElement))) { //https://github.com/rordenlab/dcm2niix/issues/144
+               vr[0] = 'S';
+               vr[1] = 'Q';
+               lLength = 8; //Sequence Tag
+               is2005140FSQ = (groupElement == kPrivatePerFrameSq);
+               //if (is2005140FSQ) printMessage(" !!!SQ\t%04x,%04x\n",   
groupElement & 65535,groupElement>>16);
+            }
         } //if explicit else implicit VR
         if (lLength == 0xFFFFFFFF) {
             lLength = 8; //SQ (Sequences) use 0xFFFFFFFF [4294967295] to 
denote unknown length
             vr[0] = 'S';
             vr[1] = 'Q';
         }
-
         if   ((vr[0] == 'S') && (vr[1] == 'Q')) {
             sqDepth++;
             //printMessage("SQstart %d\n", sqDepth);
@@ -2986,6 +3270,12 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
         if (true) { //(nest <= 0) { //some Philips images have different 
0020,0013
         //verbose reporting :
         // printMessage("Pos %ld GroupElement %#08x,%#08x Length %d isLittle 
%d\n", lPos, (groupElement & 0xFFFF), (groupElement >> 16), lLength, 
d.isLittleEndian);
+
+        // // Debugging
+        // int groupItem = groupElement >> 16;
+        // int groupGroup = groupElement - (groupItem << 16);
+        // printMessage("groupElement: (%04X, %04X)\n", groupGroup, groupItem);
+
         switch ( groupElement ) {
             case kTransferSyntax: {
                 char transferSyntax[kDICOMStr];
@@ -3031,6 +3321,13 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                     d.imageStart = 1;//abort as invalid (imageStart MUST be 
>128)
                 }
                 break;} //{} provide scope for variable 'transferSyntax
+            /*case kImplementationVersionName: {
+               char impTxt[kDICOMStr];
+                dcmStr (lLength, &buffer[lPos], impTxt);
+                int slen = (int) strlen(impTxt);
+                               if((slen < 6) || (strstr(impTxt, "OSIRIX") == 
NULL) ) break;
+                printError("OSIRIX Detected\n");
+               break; }*/
             case kSourceApplicationEntityTitle: {
                char saeTxt[kDICOMStr];
                 dcmStr (lLength, &buffer[lPos], saeTxt);
@@ -3080,6 +3377,7 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 break;
             case kManufacturer:
                 d.manufacturer = dcmStrManufacturer (lLength, &buffer[lPos]);
+                volDiffusion.manufacturer = d.manufacturer;
                 break;
             case kInstitutionName:
                dcmStr(lLength, &buffer[lPos], d.institutionName);
@@ -3163,6 +3461,9 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
             case kPatientOrient :
                 dcmStr (lLength, &buffer[lPos], d.patientOrient);
                 break;
+            case kDiffusionDirectionality : // 0018, 9075
+                set_directionality0018_9075(&volDiffusion, (&buffer[lPos]));
+                break;
             case kDwellTime :
                d.dwellTime  =  dcmStrInt(lLength, &buffer[lPos]);
                break;
@@ -3175,27 +3476,27 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
 
                  break;*/
             case kDiffusionDirectionGEX :
-                if (d.manufacturer == kMANUFACTURER_GE)  d.CSA.dtiV[1] =  
dcmStrFloat(lLength, &buffer[lPos]);
+                if (d.manufacturer == kMANUFACTURER_GE)
+                  set_diffusion_directionGE(&volDiffusion, lLength, 
(&buffer[lPos]), 0);
                 break;
             case kDiffusionDirectionGEY :
-                if (d.manufacturer == kMANUFACTURER_GE)  d.CSA.dtiV[2] =  
dcmStrFloat(lLength, &buffer[lPos]);
+                if (d.manufacturer == kMANUFACTURER_GE)
+                  set_diffusion_directionGE(&volDiffusion, lLength, 
(&buffer[lPos]), 1);
                 break;
             case kDiffusionDirectionGEZ :
-                if (d.manufacturer == kMANUFACTURER_GE) {
-                    d.CSA.dtiV[3] =  dcmStrFloat(lLength, &buffer[lPos]);
-                    d.CSA.numDti = 1;
-                }
+                if (d.manufacturer == kMANUFACTURER_GE)
+                  set_diffusion_directionGE(&volDiffusion, lLength, 
(&buffer[lPos]), 2);
                 break;
-               case kBandwidthPerPixelPhaseEncode:
-                       d.bandwidthPerPixelPhaseEncode = 
dcmFloatDouble(lLength, &buffer[lPos],d.isLittleEndian);
-                       break;
-            case kStudyInstanceUID :
+            case kBandwidthPerPixelPhaseEncode:
+                d.bandwidthPerPixelPhaseEncode = dcmFloatDouble(lLength, 
&buffer[lPos],d.isLittleEndian);
+                break;
+            case kStudyInstanceUID : // 0020, 000D
                 dcmStr (lLength, &buffer[lPos], d.studyInstanceUID);
                 break;
-            case kSeriesInstanceUID :
+            case kSeriesInstanceUID : // 0020, 000E
                dcmStr (lLength, &buffer[lPos], d.seriesInstanceUID);
                 break;
-            case kPatientPosition :
+            case kPatientPosition : // 0020, 0032, ImagePositionPatient
                 if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(is2005140FSQ)) {
                     if (!is2005140FSQwarned)
                         printWarning("Philips R3.2.2 can report different 
positions for the same slice. Attempting patch.\n");
@@ -3220,6 +3521,7 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                                 d.patientPositionSequentialRepeats = 
patientPositionNum-1;
                         } //if different position from 1st slice in file
                     } //if not first slice in file
+                    set_isAtFirstPatientPosition_tvd(&volDiffusion, 
isAtFirstPatientPosition);
                     if (isVerbose > 1)
                        printMessage("   Patient Position 0020,0032 
(#,@,X,Y,Z)\t%d\t%ld\t%g\t%g\t%g\n", patientPositionNum, lPos, 
patientPosition[1], patientPosition[2], patientPosition[3]);
 
@@ -3244,6 +3546,20 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 //int dx = 3;
                 if (d.imageNum <= 1) d.imageNum = dcmStrInt(lLength, 
&buffer[lPos]);  //Philips renames each image as image1 in 2001,9000
                 break;
+            case kDimensionIndexValues:  // kImageNum is not enough for 4D 
series from Philips 5.*.
+              {                                   // { necessary for 
initializing ndim.
+                uint8_t ndim = lLength / 4;
+
+                if(ndim > MAX_NUMBER_OF_DIMENSIONS){
+                    // Ideally degenerate axes would be cleverly handled.
+                    // They are commonly seen in NIfTIs, but perhaps not in 
DICOM.
+                    printError("%d is too many dimensions.  Only up to %d are 
supported\n", ndim,
+                               MAX_NUMBER_OF_DIMENSIONS);
+                    ndim = MAX_NUMBER_OF_DIMENSIONS;  // Truncate
+                }
+                dcmMultiLongs(4 * ndim, &buffer[lPos], ndim, 
d.dimensionIndexValues, d.isLittleEndian);
+              }
+                break;
             case kPhotometricInterpretation:
                                char interp[kDICOMStr];
                 dcmStr (lLength, &buffer[lPos], interp);
@@ -3385,6 +3701,13 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 d.accelFactPE = (float)strtof(accelStr, &ptr);
                 if (*ptr != '\0')
                        d.accelFactPE = 0.0;
+                //between slice accel
+                dcmStr (lLength, &buffer[lPos], accelStr);
+                dcmStrDigitsOnlyKey('s', accelStr); //e.g. if "p2s4" return 
"4", if "p2" return ""
+                multiBandFactor = (int)strtol(accelStr, &ptr, 10);
+                if (*ptr != '\0')
+                       multiBandFactor = 0.0;
+                //printMessage("p%gs%d\n",  d.accelFactPE, multiBandFactor);
                                break; }
             case kLocationsInAcquisition :
                 d.locationsInAcquisition = 
dcmInt(lLength,&buffer[lPos],d.isLittleEndian);
@@ -3457,23 +3780,70 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 else
                     d.sliceOrient = kSliceOrientTra; //transverse (axial)
                 break; }
-            case       kDiffusionBFactor:
-                if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
-                    d.CSA.numDti++; //increment with BFactor: on Philips 
slices with B=0 have B-factor but no diffusion directions
-                    if (d.CSA.numDti == 2) { //First time we know that this is 
a 4D DTI dataset
-                        //d.dti4D = (TDTI *)malloc(kMaxDTI4D * sizeof(TDTI));
-                        dti4D->S[0].V[0] = d.CSA.dtiV[0];
-                        dti4D->S[0].V[1] = d.CSA.dtiV[1];
-                        dti4D->S[0].V[2] = d.CSA.dtiV[2];
-                        dti4D->S[0].V[3] = d.CSA.dtiV[3];
-                    }
-                    d.CSA.dtiV[0] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
-                    if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
-                        dti4D->S[d.CSA.numDti-1].V[0] = d.CSA.dtiV[0];
-                    /*if ((d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
-                       d.CSA.dtiV[d.CSA.numDti-1][0] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
-                }
-                break;
+            // case    kDiffusionBFactor: // 2001,1003
+            //     if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
+            //         d.CSA.numDti++; //increment with BFactor: on Philips 
slices with B=0 have B-factor but no diffusion directions
+            //         if (d.CSA.numDti == 2) { //First time we know that this 
is a 4D DTI dataset
+            //             //d.dti4D = (TDTI *)malloc(kMaxDTI4D * 
sizeof(TDTI));
+            //             dti4D->S[0].V[0] = d.CSA.dtiV[0];
+            //             dti4D->S[0].V[1] = d.CSA.dtiV[1];
+            //             dti4D->S[0].V[2] = d.CSA.dtiV[2];
+            //             dti4D->S[0].V[3] = d.CSA.dtiV[3];
+            //         }
+            //         d.CSA.dtiV[0] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
+            //         if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
+            //             dti4D->S[d.CSA.numDti-1].V[0] = d.CSA.dtiV[0];
+            //         /*if ((d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
+            //            d.CSA.dtiV[d.CSA.numDti-1][0] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
+            //     }
+            //     break;
+            case kDiffusion_bValue:  // 0018, 9087
+              // Note that this is ahead of kPatientPosition (0020,0032), so
+              // isAtFirstPatientPosition is not necessarily set yet.
+              // Philips uses this tag too, at least as of 5.1, but they also
+              // use kDiffusionBFactor (see above), and we do not want to
+              // double count.  More importantly, with Philips this tag
+              // (sometimes?)  gets repeated in a nested sequence with the
+              // value *unset*!
+              // GE started using this tag in 27, and annoyingly, NOT including
+              // the b value if it is 0 for the slice.
+              if((d.manufacturer != kMANUFACTURER_PHILIPS) || !is2005140FSQ){
+                // d.CSA.numDti++;
+
+                // if (d.CSA.numDti == 2) { //First time we know that this is 
a 4D DTI dataset
+                //   //d.dti4D = (TDTI *)malloc(kMaxDTI4D * sizeof(TDTI));
+                //   dti4D->S[0].V[0] = d.CSA.dtiV[0];
+                //   dti4D->S[0].V[1] = d.CSA.dtiV[1];
+                //   dti4D->S[0].V[2] = d.CSA.dtiV[2];
+                //   dti4D->S[0].V[3] = d.CSA.dtiV[3];
+                // }
+                //d.CSA.dtiV[0] = dcmFloatDouble(lLength, &buffer[lPos], 
d.isLittleEndian);
+                set_bVal(&volDiffusion, dcmFloatDouble(lLength, &buffer[lPos], 
d.isLittleEndian));
+
+                // if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
+                //   dti4D->S[d.CSA.numDti-1].V[0] = d.CSA.dtiV[0];
+              }
+              break;
+            case kDiffusionOrientation:  // 0018, 9089
+              // Note that this is ahead of kPatientPosition (0020,0032), so
+              // isAtFirstPatientPosition is not necessarily set yet.
+              // Philips uses this tag too, at least as of 5.1, but they also
+              // use kDiffusionDirectionRL, etc., and we do not want to double
+              // count.  More importantly, with Philips this tag (sometimes?)
+              // gets repeated in a nested sequence with the value *unset*!
+              // if (((d.manufacturer == kMANUFACTURER_SIEMENS) ||
+              //      ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
!is2005140FSQ)) &&
+              //     (isAtFirstPatientPosition || isnan(d.patientPosition[1])))
+              if((d.manufacturer == kMANUFACTURER_SIEMENS) ||
+                 ((d.manufacturer == kMANUFACTURER_PHILIPS) && !is2005140FSQ))
+                set_orientation0018_9089(&volDiffusion, lLength, 
&buffer[lPos], d.isLittleEndian);
+              break;
+            // case kSharedFunctionalGroupsSequence:
+            //   if ((d.manufacturer == kMANUFACTURER_SIEMENS) && 
isAtFirstPatientPosition) {
+            //     break; // For now - need to figure out how to get the nested
+            //            // part of buffer[lPos].
+            //   }
+            //   break;
             case kSliceNumberMrPhilips :
                if (d.manufacturer != kMANUFACTURER_PHILIPS)
                        break;
@@ -3512,35 +3882,35 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                        break;
                 locationsInAcquisitionPhilips = 
dcmInt(lLength,&buffer[lPos],d.isLittleEndian);
                                break;
-            case    kDiffusionDirectionRL:
-                if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
-                    d.CSA.dtiV[1] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
-                    if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
-                        dti4D->S[d.CSA.numDti-1].V[1] = d.CSA.dtiV[1];
-                }
-                /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
-                    d.CSA.dtiV[d.CSA.numDti-1][1] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
-                break;
-            case kDiffusionDirectionAP:
-                if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
-                    d.CSA.dtiV[2] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
-                    if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
-                        dti4D->S[d.CSA.numDti-1].V[2] = d.CSA.dtiV[2];
-                }
-                /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
-                    d.CSA.dtiV[d.CSA.numDti-1][2] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
-                break;
-            case       kDiffusionDirectionFH:
-                if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
-                    d.CSA.dtiV[3] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
-                    if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
-                        dti4D->S[d.CSA.numDti-1].V[3] = d.CSA.dtiV[3];
-                    //printMessage("dti XYZ %g %g 
%g\n",d.CSA.dtiV[1],d.CSA.dtiV[2],d.CSA.dtiV[3]);
-                }
-                /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
-                    d.CSA.dtiV[d.CSA.numDti-1][3] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
-                
//http://www.na-mic.org/Wiki/index.php/NAMIC_Wiki:DTI:DICOM_for_DWI_and_DTI
-                break;
+            // case    kDiffusionDirectionRL:
+            //     if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
+            //         d.CSA.dtiV[1] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
+            //         if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
+            //             dti4D->S[d.CSA.numDti-1].V[1] = d.CSA.dtiV[1];
+            //     }
+            //     /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
+            //         d.CSA.dtiV[d.CSA.numDti-1][1] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
+            //     break;
+            // case kDiffusionDirectionAP:
+            //     if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
+            //         d.CSA.dtiV[2] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
+            //         if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
+            //             dti4D->S[d.CSA.numDti-1].V[2] = d.CSA.dtiV[2];
+            //     }
+            //     /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
+            //         d.CSA.dtiV[d.CSA.numDti-1][2] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
+            //     break;
+            // case    kDiffusionDirectionFH:
+            //     if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition)) {
+            //         d.CSA.dtiV[3] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);
+            //         if ((d.CSA.numDti > 1) && (d.CSA.numDti < kMaxDTI4D))
+            //             dti4D->S[d.CSA.numDti-1].V[3] = d.CSA.dtiV[3];
+            //         //printMessage("dti XYZ %g %g 
%g\n",d.CSA.dtiV[1],d.CSA.dtiV[2],d.CSA.dtiV[3]);
+            //     }
+            //     /*if ((d.manufacturer == kMANUFACTURER_PHILIPS) && 
(isAtFirstPatientPosition) && (d.CSA.numDti > 0) && (d.CSA.numDti <= kMaxDTIv))
+            //         d.CSA.dtiV[d.CSA.numDti-1][3] = dcmFloat(lLength, 
&buffer[lPos],d.isLittleEndian);*/
+            //     
//http://www.na-mic.org/Wiki/index.php/NAMIC_Wiki:DTI:DICOM_for_DWI_and_DTI
+            //     break;
             case kWaveformSq:
                 d.imageStart = 1; //abort!!!
                 printMessage("Skipping DICOM (audio not image) '%s'\n", fname);
@@ -3570,7 +3940,8 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                 if (d.manufacturer == kMANUFACTURER_GE) 
d.effectiveEchoSpacingGE = dcmInt(lLength,&buffer[lPos],d.isLittleEndian);
                 break;
             case kDiffusionBFactorGE :
-                if (d.manufacturer == kMANUFACTURER_GE) d.CSA.dtiV[0] =  
dcmStrInt(lLength, &buffer[lPos]);
+                if (d.manufacturer == kMANUFACTURER_GE)
+                  set_bValGE(&volDiffusion, lLength, &buffer[lPos]);
                 break;
             case kGeiisFlag:
                 if ((lLength > 4) && (buffer[lPos]=='G') && 
(buffer[lPos+1]=='E') && (buffer[lPos+2]=='I')  && (buffer[lPos+3]=='I')) {
@@ -3641,6 +4012,7 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                //printMessage(" 
Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\t%s\n",   groupElement & 
65535,groupElement>>16, lLength, lPos, nest, tagStr);
             } else
                printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\n", 
  groupElement & 65535,groupElement>>16, lLength, lFileOffset+lPos, nest);
+               //if (d.isExplicitVR) printMessage(" VR=%c%c\n", vr[0], vr[1]);
         }   //printMessage(" tag=%04x,%04x length=%u pos=%ld %c%c nest=%d\n",  
 groupElement & 65535,groupElement>>16, lLength, lPos,vr[0], vr[1], nest);
         lPos = lPos + (lLength);
         //printMessage("%d\n",d.imageStart);
@@ -3727,8 +4099,8 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
                strcpy(d.protocolName, d.seriesDescription);
     if ((strlen(d.protocolName) < 1) && (strlen(d.seriesDescription) > 1))
                strcpy(d.protocolName, d.seriesDescription);
-    if ((strlen(d.protocolName) < 1) && (strlen(d.sequenceName) > 1))
-               strcpy(d.protocolName, d.sequenceName);
+    if ((strlen(d.protocolName) < 1) && (strlen(d.sequenceName) > 1) && 
(d.manufacturer != kMANUFACTURER_SIEMENS))
+               strcpy(d.protocolName, d.sequenceName); //protocolName 
(0018,1030) optional, sequence name (0018,0024) is not a good substitute for 
Siemens as it can vary per volume: *ep_b0 *ep_b1000#1, *ep_b1000#2, etc 
https://www.nitrc.org/forum/forum.php?thread_id=8771&forum_id=4703
        //     if (!isOrient) {
        //      if (d.isNonImage)
        //              printWarning("Spatial orientation ambiguous  (tag 
0020,0037 not found) [probably not important: derived image]: %s\n", fname);
@@ -3760,6 +4132,8 @@ uint32_t kUnnest2 = 0xFFFE +(0xE0DD << 16 ); //#define  
kUnnest2 0xFFFE +(0xE0DD
         printError("Unable to convert DTI [recompile with increased kMaxDTI4D] 
detected=%d, max = %d\n", d.CSA.numDti, kMaxDTI4D);
         d.CSA.numDti = 0;
     }
+    if (multiBandFactor > d.CSA.multiBandFactor)
+       d.CSA.multiBandFactor = multiBandFactor; //SMS reported in 0051,1011 
but not CSA header
     //d.isValid = false; //debug only - will not create output!
     #ifndef myLoadWholeFileToReadHeader
        fclose(file);
diff --git a/console/nii_dicom.h b/console/nii_dicom.h
index 9b32399..fb513e0 100644
--- a/console/nii_dicom.h
+++ b/console/nii_dicom.h
@@ -38,7 +38,7 @@ extern "C" {
        #define kCCsuf " CompilerNA" //unknown compiler!
 #endif
 
-#define kDCMvers "v1.0.20171017" kDCMsuf kCCsuf
+#define kDCMvers "v1.0.20171215" kDCMsuf kCCsuf
 
 static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens 
Mosaic
 static const int kMaxDTI4D = 4096; //maximum number of DTI directions for 4D 
(Philips) images, also maximum number of 3D slices for Philips 3D and 4D images
@@ -70,6 +70,10 @@ static const int kCompressC3 = 2; //obsolete JPEG lossless
 static const int kCompress50 = 3; //obsolete JPEG lossy
 static const int kCompressRLE = 4; //run length encoding
 
+// Maximum number of dimensions for .dimensionIndexValues, i.e. possibly the
+// number of axes in the output .nii.
+static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
+
     struct TDTI {
         float V[4];
         int sliceNumberMrPhilips;
@@ -77,6 +81,7 @@ static const int kCompressRLE = 4; //run length encoding
     struct TDTI4D {
         struct TDTI S[kMaxDTI4D];
     };
+
 #ifdef _MSC_VER //Microsoft nomenclature for packed structures is different...
     #pragma pack(2)
     typedef struct {
@@ -121,6 +126,7 @@ static const int kCompressRLE = 4; //run length encoding
         //char mrAcquisitionType[kDICOMStr]
         char scanOptions[kDICOMStr], stationName[kDICOMStr], 
softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], 
institutionAddress[kDICOMStr], institutionName[kDICOMStr], 
referringPhysicianName[kDICOMStr], seriesInstanceUID[kDICOMStr], 
studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], 
procedureStepDescription[kDICOMStr], imageType[kDICOMStr], 
institutionalDepartmentName[kDICOMStr], manufacturersModelName[kDICOMStr], 
patientID[kDICOMStr], patientOrient[kDICOMStr], patient [...]
         char imageComments[kDICOMStrLarge];
+        uint32_t dimensionIndexValues[MAX_NUMBER_OF_DIMENSIONS];
         struct TCSAdata CSA;
         bool isSegamiOasis, isDerived, isXRay, isMultiEcho, 
isSlicesSpatiallySequentialPhilips, isValid, is3DAcq, is2DAcq, isExplicitVR, 
isLittleEndian, isPlanarRGB, isSigned, isHasPhase,isHasMagnitude,isHasMixed, 
isFloat, isResampled;
         char phaseEncodingRC, patientSex;
diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp
index e7ab697..e7df4d5 100644
--- a/console/nii_dicom_batch.cpp
+++ b/console/nii_dicom_batch.cpp
@@ -70,7 +70,8 @@
 #endif
 
 struct TDCMsort {
-    uint64_t indx, img;
+  uint64_t indx, img;
+  uint32_t dimensionIndexValues[MAX_NUMBER_OF_DIMENSIONS];
 };
 
 struct TSearchList {
@@ -237,9 +238,9 @@ void geCorrectBvecs(struct TDICOMdata *d, int sliceDir, 
struct TDTI *vx){
                           + (vx[i].V[2]*vx[i].V[2])
                           + (vx[i].V[3]*vx[i].V[3]));
         if ((vx[i].V[0] <= FLT_EPSILON)|| (vLen <= FLT_EPSILON) ) { //bvalue=0
-            for (int v= 0; v < 4; v++)
-                vx[i].V[v] =0.0f;
-            continue; //do not normalize or reorient b0 vectors
+            for (int v= 1; v < 4; v++)
+                vx[i].V[v] = 0.0f;
+            continue; //do not normalize or reorient 0 vectors
         }
         if (!col) { //rows need to be swizzled
                //see Stanford dataset Ax_DWI_Tetrahedral_7 unable to resolve 
between possible solutions
@@ -535,6 +536,7 @@ void siemensCsaAscii(const char * filename,  int csaOffset, 
int csaLength, float
        char keyStr[] = "### ASCCONV BEGIN"; //skip to start of ASCII often 
"### ASCCONV BEGIN ###" but also "### ASCCONV BEGIN 
object=MrProtDataImpl@MrProtocolData"
        char *keyPos = (char *)memmem(bufferTrim, csaLengthTrim, keyStr, 
strlen(keyStr));
        if (keyPos) {
+               //We could detect multi-echo MPRAGE here, e.g. "lContrasts      
 =      4"- but ideally we want an earlier detection
                csaLengthTrim -= (keyPos-bufferTrim);
                char keyStrEnd[] = "### ASCCONV END";
                char *keyPosEnd = (char *)memmem(keyPos, csaLengthTrim, 
keyStrEnd, strlen(keyStrEnd));
@@ -936,11 +938,28 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata 
d, struct TDCMopts opts,
        // Slice Timing
        if (d.CSA.sliceTiming[0] >= 0.0) {
                fprintf(fp, "\t\"SliceTiming\": [\n");
-               for (int i = 0; i < kMaxEPI3D; i++) {
-                       if (d.CSA.sliceTiming[i] < 0.0) break;
-                       if (i != 0)
-                               fprintf(fp, ",\n");
-                       fprintf(fp, "\t\t%g", d.CSA.sliceTiming[i] / 1000.0 );
+               if (d.CSA.protocolSliceNumber1 > 1) {
+                       //https://github.com/rordenlab/dcm2niix/issues/40
+                       //equivalent to dicm2nii "s.SliceTiming = 
s.SliceTiming(end:-1:1);"
+                       int mx = 0;
+                       for (int i = 0; i < kMaxEPI3D; i++) {
+                               if (d.CSA.sliceTiming[i] < 0.0) break;
+                               mx++;
+                       }
+                       mx--;
+                       for (int i = mx; i >= 0; i--) {
+                               if (d.CSA.sliceTiming[i] < 0.0) break;
+                               if (i != mx)
+                                       fprintf(fp, ",\n");
+                               fprintf(fp, "\t\t%g", d.CSA.sliceTiming[i] / 
1000.0 );
+                       }
+               } else {
+                       for (int i = 0; i < kMaxEPI3D; i++) {
+                               if (d.CSA.sliceTiming[i] < 0.0) break;
+                               if (i != 0)
+                                       fprintf(fp, ",\n");
+                               fprintf(fp, "\t\t%g", d.CSA.sliceTiming[i] / 
1000.0 );
+                       }
                }
                fprintf(fp, "\t],\n");
        }
@@ -1112,15 +1131,35 @@ int * nii_SaveDTI(char pathoutname[],int nConvert, 
struct TDCMsort dcmSort[],str
         bvals[i] = bvals[i] + (0.5 * i/numDti); //add a small bias so ties are 
kept in sequential order
        }
        if (*numADC > 0) {
-               if ((numDti - *numADC) < 2) {
-                       if (!dcmList[indx0].isDerived) //no need to warn if 
images are derived Trace/ND pair
-                               printWarning("No bvec/bval files created: only 
single value after ADC excluded\n");
-                       *numADC = 0;
-                       free(bvals);
-                       free(vx);
-                       return NULL;
-               }
-               printMessage("Note: %d volumes appear to be ADC images that 
will be removed to allow processing\n", *numADC);
+                // DWIs (i.e. short diffusion scans with too few directions to
+                // calculate tensors...they typically acquire b=0 + 3 b > 0 so
+                // the isotropic trace or MD can be calculated) often come as
+                // b=0 and trace pairs, with the b=0 and trace in either order,
+                // and often as "ORIGINAL", even though the trace is not.
+                // The bval file is needed for downstream processing to know
+                // * which is the b=0 and which is the trace, and
+                // * what b is for the trace,
+                // so dcm2niix should *always* write the bval and bvec files,
+                // AND include the b for the trace for DWIs.
+                // One hackish way to accomplish that is to set *numADC = 0
+                // when *numADC == 1 && numDti == 2.
+                // - Rob Reid, 2017-11-29.
+                if ((*numADC == 1) && ((numDti - *numADC) < 2)){
+                    *numADC = 0;
+                    printMessage("Note: this appears to be a b=0+trace DWI; 
ADC/trace removal has been disabled.\n");
+                }
+                else{
+                  if ((numDti - *numADC) < 2) {
+                    if (!dcmList[indx0].isDerived) //no need to warn if images 
are derived Trace/ND pair
+                      printWarning("No bvec/bval files created: only single 
value after ADC excluded\n");
+                    *numADC = 0;
+                    free(bvals);
+                    free(vx);
+                    return NULL;
+                  }
+                  printMessage("Note: %d volumes appear to be ADC or trace 
images that will be removed to allow processing\n",
+                               *numADC);
+                }
        }
        //sort ALL including ADC
        int * volOrderIndex = (int *) malloc(numDti * sizeof(int));
@@ -2299,7 +2338,7 @@ int saveDcm2Nii(int nConvert, struct TDCMsort 
dcmSort[],struct TDICOMdata dcmLis
        printMessage("Ignoring derived image(s) of series %ld %s\n", 
dcmList[indx].seriesNum,  nameList->str[indx]);
        return EXIT_SUCCESS;
     }
-    if ((opts.isIgnoreDerivedAnd2D) && (strcmp(dcmList[indx].sequenceName, 
"_fl2d1")== 0)) {
+    if ((opts.isIgnoreDerivedAnd2D) && ((strcmp(dcmList[indx].sequenceName, 
"_fl3d1_ns")== 0) || (strcmp(dcmList[indx].sequenceName, "_fl2d1")== 0)) ) {
        printMessage("Ignoring localizer (sequence %s) of series %ld %s\n", 
dcmList[indx].sequenceName, dcmList[indx].seriesNum,  nameList->str[indx]);
        return EXIT_SUCCESS;
     }
@@ -2438,12 +2477,21 @@ int saveDcm2Nii(int nConvert, struct TDCMsort 
dcmSort[],struct TDICOMdata dcmLis
         free(imgM);
         return EXIT_FAILURE;
     }
+    // Prevent these DICOM files from being reused.
+    for(int i = 0; i < nConvert; ++i)
+      dcmList[dcmSort[i].indx].converted2NII = 1;
+    if (opts.numSeries < 0) { //report series number but do not convert
+       printMessage("\t%d\t%s\n", dcmList[dcmSort[0].indx].seriesNum, 
pathoutname);
+       printMessage(" %s\n",nameList->str[dcmSort[0].indx]);
+       return EXIT_SUCCESS;
+    }
     checkSliceTiming(&dcmList[indx0], &dcmList[indx1]);
     int sliceDir = 0;
     if (hdr0.dim[3] > 1)sliceDir = 
headerDcm2Nii2(dcmList[dcmSort[0].indx],dcmList[dcmSort[nConvert-1].indx] , 
&hdr0, true);
        //UNCOMMENT NEXT TWO LINES TO RE-ORDER MOSAIC WHERE CSA's 
protocolSliceNumber does not start with 1
        if (dcmList[dcmSort[0].indx].CSA.protocolSliceNumber1 > 1) {
-               printWarning("Weird CSA 'ProtocolSliceNumber' (%d): SPATIAL, 
SLICE-ORDER AND DTI TRANSFORMS UNTESTED\n", 
dcmList[dcmSort[0].indx].CSA.protocolSliceNumber1);
+               printWarning("Weird CSA 'ProtocolSliceNumber' 
(System/Miscellaneous/ImageNumbering reversed): VALIDATE SLICETIMING AND 
BVECS\n");
+               
//https://www.healthcare.siemens.com/siemens_hwem-hwem_ssxa_websites-context-root/wcm/idc/groups/public/@global/@imaging/@mri/documents/download/mdaz/nzmy/~edisp/mri_60_graessner-01646277.pdf
                //see https://github.com/neurolabusc/dcm2niix/issues/40
                sliceDir = -1; //not sure how to handle negative determinants?
        }
@@ -2451,6 +2499,18 @@ int saveDcm2Nii(int nConvert, struct TDCMsort 
dcmSort[],struct TDICOMdata dcmLis
         imgM = nii_flipZ(imgM, &hdr0);
         sliceDir = abs(sliceDir); //change this, we have flipped the image so 
GE DTI bvecs no longer need to be flipped!
     }
+    // skip converting if user has specified one or more series, but has not 
specified this one
+    if (opts.numSeries > 0) {
+      int i = 0;
+      for (; i < opts.numSeries; i++) {
+        if (opts.seriesNumber[i] == dcmList[dcmSort[0].indx].seriesNum) {
+          break;
+        }
+      }
+      if (i == opts.numSeries) {
+        return EXIT_SUCCESS;
+      }
+    }
     //move before headerDcm2Nii2 checkSliceTiming(&dcmList[indx0], 
&dcmList[indx1]);
     //nii_SaveBIDS(pathoutname, dcmList[dcmSort[0].indx], opts, dti4D, &hdr0, 
nameList->str[dcmSort[0].indx]);
     nii_SaveBIDS(pathoutname, dcmList[dcmSort[0].indx], opts, &hdr0, 
nameList->str[dcmSort[0].indx]);
@@ -2459,7 +2519,6 @@ int saveDcm2Nii(int nConvert, struct TDCMsort 
dcmSort[],struct TDICOMdata dcmLis
         free(imgM);
         return EXIT_SUCCESS;
     }
-
        nii_SaveText(pathoutname, dcmList[dcmSort[0].indx], opts, &hdr0, 
nameList->str[indx]);
        int numADC = 0;
     int * volOrderIndex = nii_SaveDTI(pathoutname,nConvert, dcmSort, dcmList, 
opts, sliceDir, dti4D, &numADC);
@@ -2530,27 +2589,56 @@ int saveDcm2Nii(int nConvert, struct TDCMsort 
dcmSort[],struct TDICOMdata dcmLis
     }
     if ((opts.isCrop) && (dcmList[indx0].is3DAcq)   && (hdr0.dim[3] > 1) && 
(hdr0.dim[0] < 4))//for T1 scan: && (dcmList[indx0].TE < 25)
         returnCode = nii_saveCrop(pathoutname, hdr0, imgM,opts); //n.b. must 
be run AFTER nii_setOrtho()!
-
 #ifdef HAVE_R
     // Note that for R, only one image should be created per series
     // Hence the logical OR here
     if (returnCode == EXIT_SUCCESS || nii_saveNII(pathoutname,hdr0,imgM,opts) 
== EXIT_SUCCESS)
         nii_saveAttributes(dcmList[dcmSort[0].indx], hdr0, opts);
 #endif
-
     free(imgM);
     return returnCode;//EXIT_SUCCESS;
 }// saveDcm2Nii()
 
+void fillTDCMsort(struct TDCMsort& tdcmref, const uint64_t indx, const struct 
TDICOMdata& dcmdata){
+  // Copy the relevant parts of dcmdata to tdcmref.
+  tdcmref.indx = indx;
+  tdcmref.img = ((uint64_t)dcmdata.seriesNum << 32) + dcmdata.imageNum;
+  for(int i = 0; i < MAX_NUMBER_OF_DIMENSIONS; ++i)
+    tdcmref.dimensionIndexValues[i] = dcmdata.dimensionIndexValues[i];
+} // fillTDCMsort()
+
 int compareTDCMsort(void const *item1, void const *item2) {
     //for quicksort 
http://blog.ablepear.com/2011/11/objective-c-tuesdays-sorting-arrays.html
     struct TDCMsort const *dcm1 = (const struct TDCMsort *)item1;
     struct TDCMsort const *dcm2 = (const struct TDCMsort *)item2;
+
+    int retval = 0;   // tie
+
     if (dcm1->img < dcm2->img)
-        return -1;
+        retval = -1;
     else if (dcm1->img > dcm2->img)
-        return 1;
-    return 0; //tie
+        retval = 1;
+
+    if(retval == 0){
+      // Check the dimensionIndexValues (useful for enhanced DICOM 4D series).
+      // ->img is basically behaving as a (seriesNum, imageNum) sort key
+      // concatenated into a (large) integer for qsort.  That is unwieldy when
+      // dimensionIndexValues need to be compared, because the existence of
+      // uint128_t, uint256_t, etc. is not guaranteed.  This sorts by
+      // (seriesNum, ImageNum, div[0], div[1], ...), or if you think of it as a
+      // number, the dimensionIndexValues come after the decimal point.
+      for(int i=0; i < MAX_NUMBER_OF_DIMENSIONS; ++i){
+        if(dcm1->dimensionIndexValues[i] < dcm2->dimensionIndexValues[i]){
+          retval = -1;
+          break;
+        }
+        else if(dcm1->dimensionIndexValues[i] > dcm2->dimensionIndexValues[i]){
+          retval = 1;
+          break;
+        }
+      }
+    }
+    return retval;
 } //compareTDCMsort()
 
 int isSameFloatGE (float a, float b) {
@@ -2566,7 +2654,7 @@ int isSameFloatDouble (double a, double b) {
 }
 
 struct TWarnings { //generate a warning only once per set
-        bool acqNumVaries, bitDepthVaries, dateTimeVaries, echoVaries, 
coilVaries, nameVaries, orientVaries;
+        bool acqNumVaries, bitDepthVaries, dateTimeVaries, echoVaries, 
coilVaries, nameVaries, nameEmpty, orientVaries;
 };
 
 TWarnings setWarnings() {
@@ -2577,13 +2665,13 @@ TWarnings setWarnings() {
        r.echoVaries = false;
        r.coilVaries = false;
        r.nameVaries = false;
+       r.nameEmpty = false;
        r.orientVaries = false;
        return r;
 }
 
 bool isSameSet (struct TDICOMdata d1, struct TDICOMdata d2, struct TDCMopts* 
opts, struct TWarnings* warnings, bool *isMultiEcho) {
     //returns true if d1 and d2 should be stacked together as a single output
-    *isMultiEcho = false;
     if (!d1.isValid) return false;
     if (!d2.isValid) return false;
     if (d1.modality != d2.modality) return false; //do not stack MR and CT 
data!
@@ -2607,7 +2695,7 @@ bool isSameSet (struct TDICOMdata d1, struct TDICOMdata 
d2, struct TDCMopts* opt
     }
     if (!isSameFloatDouble(d1.dateTime, d2.dateTime)) { //beware, some vendors 
incorrectly store Image Time (0008,0033) as Study Time (0008,0030).
        if (!warnings->dateTimeVaries)
-               printMessage("slices not stacked: Study Data/Time (0008,0020 / 
0008,0030) varies %12.12f ~= %12.12f\n", d1.dateTime, d2.dateTime);
+               printMessage("slices not stacked: Study Date/Time (0008,0020 / 
0008,0030) varies %12.12f ~= %12.12f\n", d1.dateTime, d2.dateTime);
        warnings->dateTimeVaries = true;
        return false;
     }
@@ -2631,9 +2719,13 @@ bool isSameSet (struct TDICOMdata d1, struct TDICOMdata 
d2, struct TDCMopts* opt
         warnings->coilVaries = true;
         return false;
     }
-    if ((strcmp(d1.protocolName, d2.protocolName) != 0)) {
-        if ((!warnings->nameVaries))
-               printMessage("slices not stacked: protocol name varies\n");
+    if ((strlen(d1.protocolName) < 1) && (strlen(d2.protocolName) < 1)) {
+       if (!warnings->nameEmpty)
+       printWarning("Empty protocol name(s) (0018,1030)\n");
+       warnings->nameEmpty = true;
+    } else if ((strcmp(d1.protocolName, d2.protocolName) != 0)) {
+        if (!warnings->nameVaries)
+               printMessage("slices not stacked: protocol name varies '%s' != 
'%s'\n", d1.protocolName, d2.protocolName);
         warnings->nameVaries = true;
         return false;
     }
@@ -2666,10 +2758,9 @@ int singleDICOM(struct TDCMopts* opts, char *fname) {
     strcpy(nameList.str[nameList.numItems],filename);
     nameList.numItems++;
     struct TDCMsort dcmSort[1];
-    dcmSort[0].indx = 0;
-    dcmSort[0].img = ((uint64_t)dcmList[0].seriesNum << 32) + 
dcmList[0].imageNum;
     dcmList[0].converted2NII = 1;
     dcmList[0] = readDICOMv(nameList.str[0], opts->isVerbose, 
opts->compressFlag, &dti4D); //ignore compile warning - memory only freed on 
first of 2 passes
+    fillTDCMsort(dcmSort[0], 0, dcmList[0]);
     return saveDcm2Nii(1, dcmSort, dcmList, &nameList, *opts, &dti4D);
 }// singleDICOM()
 
@@ -2736,11 +2827,13 @@ int removeDuplicates(int nConvert, struct TDCMsort 
dcmSort[]){
     if (nConvert < 2) return nConvert;
     int nDuplicates = 0;
     for (int i = 1; i < nConvert; i++) {
-        if (dcmSort[i].img == dcmSort[i-1].img) {
+        if (compareTDCMsort(&dcmSort[i], &dcmSort[i-1]) == 0) {
             nDuplicates ++;
         } else {
             dcmSort[i-nDuplicates].img = dcmSort[i].img;
             dcmSort[i-nDuplicates].indx = dcmSort[i].indx;
+            for(int j = 0; j < MAX_NUMBER_OF_DIMENSIONS; ++j)
+              dcmSort[i - nDuplicates].dimensionIndexValues[j] = 
dcmSort[i].dimensionIndexValues[j];
         }
     }
     if (nDuplicates > 0)
@@ -2753,18 +2846,20 @@ int removeDuplicatesVerbose(int nConvert, struct 
TDCMsort dcmSort[], struct TSea
     if (nConvert < 2) return nConvert;
     int nDuplicates = 0;
     for (int i = 1; i < nConvert; i++) {
-        if (dcmSort[i].img == dcmSort[i-1].img) {
+        if (compareTDCMsort(&dcmSort[i], &dcmSort[i-1]) == 0) {
             
printMessage("\t%s\t=\t%s\n",nameList->str[dcmSort[i-1].indx],nameList->str[dcmSort[i].indx]);
             nDuplicates ++;
         } else {
             dcmSort[i-nDuplicates].img = dcmSort[i].img;
             dcmSort[i-nDuplicates].indx = dcmSort[i].indx;
+            for(int j = 0; j < MAX_NUMBER_OF_DIMENSIONS; ++j)
+              dcmSort[i - nDuplicates].dimensionIndexValues[j] = 
dcmSort[i].dimensionIndexValues[j];
         }
     }
     if (nDuplicates > 0)
         printMessage("Some images have identical time, series, acquisition and 
image values. Duplicates removed.\n");
     return nConvert - nDuplicates;
-}// removeDuplicates()
+}// removeDuplicatesVerbose()
 
 bool isExt (char *file_name, const char* ext) {
     char *p_extension;
@@ -2777,6 +2872,7 @@ bool isExt (char *file_name, const char* ext) {
 int convert_parRec(struct TDCMopts opts) {
     //sample dataset from Ed Gronenschild 
<ed.gronensch...@maastrichtuniversity.nl>
     struct TSearchList nameList;
+    int ret = EXIT_FAILURE;
     nameList.numItems = 1;
     nameList.maxItems = 1;
     nameList.str = (char **) malloc((nameList.maxItems+1) * sizeof(char *)); 
//we reserve one pointer (32 or 64 bits) per potential file
@@ -2787,7 +2883,8 @@ int convert_parRec(struct TDCMopts opts) {
     dcmList[0] = nii_readParRec(nameList.str[0], opts.isVerbose, &dti4D);
     struct TDCMsort dcmSort[1];
     dcmSort[0].indx = 0;
-    int ret = saveDcm2Nii(1, dcmSort, dcmList, &nameList, opts, &dti4D);
+    if (dcmList[0].isValid)
+       ret = saveDcm2Nii(1, dcmSort, dcmList, &nameList, opts, &dti4D);
     free(dcmList);//if (nConvertTotal == 0)
     if (nameList.numItems < 1)
        printMessage("No valid PAR/REC files were found\n");
@@ -2891,8 +2988,8 @@ int nii_loadDir(struct TDCMopts* opts) {
         dcmList[i] = readDICOMv(nameList.str[i], opts->isVerbose, 
opts->compressFlag, &dti4D); //ignore compile warning - memory only freed on 
first of 2 passes
         if ((dcmList[i].isValid) &&((dcmList[i].patientPositionNumPhilips > 1) 
|| (dcmList[i].CSA.numDti > 1))) { //4D dataset: dti4D arrays require huge 
amounts of RAM - write this immediately
             struct TDCMsort dcmSort[1];
-            dcmSort[0].indx = i;
-            dcmSort[0].img = ((uint64_t)dcmList[i].seriesNum << 32) + 
dcmList[i].imageNum;
+
+            fillTDCMsort(dcmSort[0], i, dcmList[i]);
             dcmList[i].converted2NII = 1;
             int ret = saveDcm2Nii(1, dcmSort, dcmList, &nameList, *opts, 
&dti4D);
             if (ret == EXIT_SUCCESS)
@@ -2942,24 +3039,24 @@ int nii_loadDir(struct TDCMopts* opts) {
                if ((dcmList[i].converted2NII == 0) && (dcmList[i].isValid)) {
                        int nConvert = 0;
                        struct TWarnings warnings = setWarnings();
-                       bool isMultiEcho;
+                       bool isMultiEcho = false;
                        for (int j = i; j < (int)nDcm; j++)
                                if (isSameSet(dcmList[i], dcmList[j], opts, 
&warnings, &isMultiEcho ) )
                                        nConvert++;
                        if (nConvert < 1) nConvert = 1; //prevents compiler 
warning for next line: never executed since j=i always causes nConvert ++
                        TDCMsort * dcmSort = (TDCMsort *)malloc(nConvert * 
sizeof(TDCMsort));
                        nConvert = 0;
+                       isMultiEcho = false;
                        for (int j = i; j < (int)nDcm; j++)
                                if (isSameSet(dcmList[i], dcmList[j], opts, 
&warnings, &isMultiEcho)) {
-                                       dcmSort[nConvert].indx = j;
-                                       dcmSort[nConvert].img = 
((uint64_t)dcmList[j].seriesNum << 32) + dcmList[j].imageNum;
-                                       dcmList[j].converted2NII = 1;
+                                        fillTDCMsort(dcmSort[nConvert], j, 
dcmList[j]);
                                        nConvert++;
                                } else {
                                        dcmList[i].isMultiEcho = isMultiEcho;
                                        dcmList[j].isMultiEcho = isMultiEcho;
                                }
                        qsort(dcmSort, nConvert, sizeof(struct TDCMsort), 
compareTDCMsort); //sort based on series and image numbers....
+                       //dcmList[dcmSort[0].indx].isMultiEcho = isMultiEcho;
                        if (opts->isVerbose)
                                nConvert = removeDuplicatesVerbose(nConvert, 
dcmSort, &nameList);
                        else
@@ -3159,6 +3256,8 @@ void setDefaultOpts (struct TDCMopts *opts, const char * 
argv[]) { //either "set
         opts->isVerbose = false;
 #endif
     opts->isTiltCorrect = true;
+    opts->numSeries = 0;
+    memset(opts->seriesNumber, 0, sizeof(opts->seriesNumber));
     strcpy(opts->filename,"%f_%p_%t_%s");
 } // setDefaultOpts()
 
diff --git a/console/nii_dicom_batch.h b/console/nii_dicom_batch.h
index f9f0ba9..ced863e 100644
--- a/console/nii_dicom_batch.h
+++ b/console/nii_dicom_batch.h
@@ -22,10 +22,13 @@ extern "C" {
     };
 #endif
 
+#define MAX_NUM_SERIES 16
+
     struct TDCMopts {
         bool isSave3D,isGz, isFlipY,  isCreateBIDS, isSortDTIbyBVal, 
isAnonymizeBIDS, isOnlyBIDS, isCreateText, isIgnoreDerivedAnd2D, 
isPhilipsFloatNotDisplayScaling, isTiltCorrect, isRGBplanar, isOnlySingleFile, 
isForceStackSameSeries, isCrop;
         int isVerbose, compressFlag, gzLevel; //support for compressed data 
0=none,
         char filename[512], outdir[512], indir[512], pigzname[512], 
optsname[512], indirParent[512], imageComments[24];
+        long seriesNumber[MAX_NUM_SERIES], numSeries;
 #ifdef HAVE_R
         bool isScanOnly;
         void *imageList;

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/debian-med/dcm2niix.git

_______________________________________________
debian-med-commit mailing list
debian-med-commit@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit

Reply via email to