[med-svn] [vtk-dicom] 01/07: Imported Upstream version 0.7.8

Gert Wollny gert-guest at moszumanska.debian.org
Wed Jun 1 11:47:18 UTC 2016


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

gert-guest pushed a commit to branch master
in repository vtk-dicom.

commit 4685bd916b29265bc63e4cdd7d473467f41a0881
Author: Gert Wollny <gw.fossdev at gmail.com>
Date:   Tue May 31 13:31:52 2016 +0000

    Imported Upstream version 0.7.8
---
 CMakeLists.txt                      |   2 +-
 DicomCli/CMakeLists.txt             |   1 +
 DicomCli/mainmacro.cxx              |  25 +++-
 DicomCli/readquery.cxx              |  20 ++++
 DicomCli/vtkConsoleOutputWindow.cxx |  53 +++++++++
 DicomCli/vtkConsoleOutputWindow.h   |  45 +++++++
 Programs/dicomdump.cxx              |  19 +--
 Programs/dicomfind.cxx              |  64 ++++++++--
 Programs/dicompull.cxx              |   5 +-
 Programs/dicomtocsv.cxx             | 231 +++++++++++++++++++++++++++++++-----
 Programs/dicomtodicom.cxx           |   4 +
 Programs/dicomtonifti.cxx           |   4 +
 Programs/nifticenter.cxx            |   4 +
 Programs/niftidump.cxx              | 194 ++++++++++++++++--------------
 Programs/niftitodicom.cxx           |   4 +
 Programs/scancodump.cxx             |  95 ++++++++-------
 Programs/scancotodicom.cxx          |   4 +
 Source/vtkDICOMCharacterSet.cxx     | 170 +++++++++++++++++++-------
 Source/vtkDICOMCompiler.cxx         |  14 ++-
 Source/vtkDICOMCompiler.h           |  14 ++-
 Source/vtkDICOMDirectory.cxx        |  22 +++-
 Source/vtkDICOMDirectory.h          |   2 +-
 Source/vtkDICOMFile.cxx             |  20 ++--
 Source/vtkDICOMFileDirectory.cxx    |  18 +--
 Source/vtkDICOMFilePath.cxx         |  87 +++++++++++++-
 Source/vtkDICOMFilePath.h           |  42 ++++++-
 Source/vtkDICOMImageCodec.h         |   2 +-
 Source/vtkDICOMMetaDataAdapter.cxx  |  33 ++++--
 Source/vtkDICOMMetaDataAdapter.h    |  18 +++
 Source/vtkDICOMReader.cxx           |  51 ++++----
 Source/vtkNIFTIHeader.cxx           |  18 ++-
 Source/vtkNIFTIReader.cxx           |  83 ++++++++++---
 Source/vtkNIFTIWriter.cxx           |  68 ++++++++---
 Source/vtkScancoCTReader.cxx        |  14 ++-
 34 files changed, 1098 insertions(+), 352 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ebfe5f0..05cc9c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@ include(CTest)
 # Project version
 set(DICOM_MAJOR_VERSION 0)
 set(DICOM_MINOR_VERSION 7)
-set(DICOM_PATCH_VERSION 7)
+set(DICOM_PATCH_VERSION 8)
 set(DICOM_SHORT_VERSION "${DICOM_MAJOR_VERSION}.${DICOM_MINOR_VERSION}")
 set(DICOM_VERSION "${DICOM_SHORT_VERSION}.${DICOM_PATCH_VERSION}")
 
diff --git a/DicomCli/CMakeLists.txt b/DicomCli/CMakeLists.txt
index 2ba54f9..35cc393 100644
--- a/DicomCli/CMakeLists.txt
+++ b/DicomCli/CMakeLists.txt
@@ -12,6 +12,7 @@ set(LIB_SRCS
   ${MAINMACRO_SRC}
   readquery.cxx
   progress.cxx
+  vtkConsoleOutputWindow.cxx
 )
 
 add_library(${LIB_NAME} STATIC ${LIB_SRCS})
diff --git a/DicomCli/mainmacro.cxx b/DicomCli/mainmacro.cxx
index b4cada0..47c3977 100644
--- a/DicomCli/mainmacro.cxx
+++ b/DicomCli/mainmacro.cxx
@@ -47,13 +47,11 @@ namespace {
 class Arguments
 {
 public:
-  // Construct with an empty argument list.
-  Arguments() : m_Argc(0), m_Argv(0) {}
+  // Construct with an empty argument list, set console code page to UTF-8.
+  Arguments();
 
-  // Destruct by freeing the memory.
-  ~Arguments() {
-    FreeStrings(&m_Argc, &m_Argv);
-  }
+  // Destruct by freeing the memory and restoring the origin code page.
+  ~Arguments();
 
   // Add the next arg (this is called by ExpandArgs).
   void Push(wchar_t *arg);
@@ -142,8 +140,23 @@ private:
 
   int m_Argc;
   char **m_Argv;
+  UINT m_CodePage;
 };
 
+Arguments::Arguments() : m_Argc(0), m_Argv(0)
+{
+  // Save the current code page, then set code page to UTF-8
+  m_CodePage = GetConsoleOutputCP();
+  SetConsoleOutputCP(65001);
+}
+
+Arguments::~Arguments()
+{
+  FreeStrings(&m_Argc, &m_Argv);
+  // Restore the old code page
+  SetConsoleOutputCP(m_CodePage);
+}
+
 bool Arguments::MatchesSpec(
   const wchar_t *val, size_t vl,
   const wchar_t *spec, size_t sl)
diff --git a/DicomCli/readquery.cxx b/DicomCli/readquery.cxx
index 8c35335..e383ef8 100644
--- a/DicomCli/readquery.cxx
+++ b/DicomCli/readquery.cxx
@@ -24,6 +24,10 @@
 #include <algorithm>
 #include <iostream>
 
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
 typedef vtkDICOMVR VR;
 
 // Prototype for function that reads one query key
@@ -57,7 +61,15 @@ vtkDICOMTagPath path_append(const vtkDICOMTagPath& tpath, vtkDICOMTag tag)
 bool dicomcli_readquery(
   const char *fname, vtkDICOMItem *query, QueryTagList *ql)
 {
+#ifdef _WIN32
+  int cn = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
+  wchar_t *wfname = new wchar_t[cn];
+  MultiByteToWideChar(CP_UTF8, 0, fname, -1, wfname, cn);
+  ifstream f(wfname);
+  delete [] wfname;
+#else
   ifstream f(fname);
+#endif
   if (!f.good())
     {
     return false;
@@ -492,7 +504,15 @@ bool dicomcli_looks_like_key(const char *cp)
 bool dicomcli_readuids(
   const char *fname, vtkDICOMItem *query, QueryTagList *ql)
 {
+#ifdef _WIN32
+  int cn = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
+  wchar_t *wfname = new wchar_t[cn];
+  MultiByteToWideChar(CP_UTF8, 0, fname, -1, wfname, cn);
+  ifstream f(wfname);
+  delete [] wfname;
+#else
   ifstream f(fname);
+#endif
   if (!f.good())
     {
     return false;
diff --git a/DicomCli/vtkConsoleOutputWindow.cxx b/DicomCli/vtkConsoleOutputWindow.cxx
new file mode 100644
index 0000000..0cea988
--- /dev/null
+++ b/DicomCli/vtkConsoleOutputWindow.cxx
@@ -0,0 +1,53 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkConsoleOutputWindow.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "vtkConsoleOutputWindow.h"
+
+vtkConsoleOutputWindow *vtkConsoleOutputWindow::New()
+{
+  return new vtkConsoleOutputWindow;
+}
+
+vtkConsoleOutputWindow::vtkConsoleOutputWindow()
+{
+}
+
+vtkConsoleOutputWindow::~vtkConsoleOutputWindow()
+{
+}
+
+void vtkConsoleOutputWindow::Initialize()
+{
+}
+
+void vtkConsoleOutputWindow::Install()
+{
+  vtkConsoleOutputWindow *win = vtkConsoleOutputWindow::New();
+  vtkOutputWindow::SetInstance(win);
+  win->Delete();
+}
+
+void vtkConsoleOutputWindow::DisplayText(const char* text)
+{
+  if (text)
+    {
+    fwrite(text, 1, strlen(text), stderr);
+    fputc('\n', stderr);
+    }
+}
+
+void vtkConsoleOutputWindow::PrintSelf(ostream& os, vtkIndent indent)
+{
+  this->Superclass::PrintSelf(os, indent);
+}
diff --git a/DicomCli/vtkConsoleOutputWindow.h b/DicomCli/vtkConsoleOutputWindow.h
new file mode 100644
index 0000000..2259284
--- /dev/null
+++ b/DicomCli/vtkConsoleOutputWindow.h
@@ -0,0 +1,45 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkConsoleOutputWindow.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+// .NAME vtkConsoleOutputWindow - Output errors to the console.
+// .SECTION Description
+// Writes debug/warning/error output to the console, even on Windows.
+// To use this class, instantiate it and then call SetInstance(this).
+//
+
+#ifndef vtkConsoleOutputWindow_h
+#define vtkConsoleOutputWindow_h
+
+#include "vtkOutputWindow.h"
+
+class vtkConsoleOutputWindow : public vtkOutputWindow
+{
+public:
+  vtkTypeMacro(vtkConsoleOutputWindow, vtkOutputWindow);
+  static vtkConsoleOutputWindow* New();
+  virtual void PrintSelf(ostream& os, vtkIndent indent);
+  virtual void DisplayText(const char*);
+  static void Install();
+
+protected:
+  vtkConsoleOutputWindow();
+  virtual ~vtkConsoleOutputWindow();
+  void Initialize();
+
+private:
+  vtkConsoleOutputWindow(const vtkConsoleOutputWindow&);  // Not implemented.
+  void operator=(const vtkConsoleOutputWindow&);  // Not implemented.
+};
+
+#endif
diff --git a/Programs/dicomdump.cxx b/Programs/dicomdump.cxx
index dee8435..ac088b5 100644
--- a/Programs/dicomdump.cxx
+++ b/Programs/dicomdump.cxx
@@ -21,6 +21,7 @@
 #include "vtkDICOMUtilities.h"
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 #include "readquery.h"
 
@@ -32,10 +33,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#if defined(_WIN32)
-#include <windows.h>
-#endif
-
 #define MAX_INDENT 24
 #define INDENT_SIZE 2
 #define MAX_LENGTH 120
@@ -410,6 +407,9 @@ void printElementFromTagPath(
 // This program will dump all the metadata in the given file
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
 
   // for the optional query file
@@ -505,12 +505,6 @@ int MAINMACRO(int argc, char *argv[])
     vtkSmartPointer<vtkDICOMMetaData>::New();
   parser->SetMetaData(data);
 
-#if defined(_WIN32)
-  // Temporarily switch the console to utf-8
-  UINT codePage = GetConsoleOutputCP();
-  SetConsoleOutputCP(65001);
-#endif
-
   int m = sorter->GetNumberOfStudies();
   for (int j = 0; j < m; j++)
     {
@@ -574,10 +568,5 @@ int MAINMACRO(int argc, char *argv[])
       }
     }
 
-#if defined(_WIN32)
-  // Restore the console code page
-  SetConsoleOutputCP(codePage);
-#endif
-
   return rval;
 }
diff --git a/Programs/dicomfind.cxx b/Programs/dicomfind.cxx
index 77ec793..5942ca6 100644
--- a/Programs/dicomfind.cxx
+++ b/Programs/dicomfind.cxx
@@ -20,6 +20,7 @@
 #include "vtkDICOMMetaData.h"
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 #include "readquery.h"
 
@@ -33,6 +34,7 @@
 #include <errno.h>
 #else
 // includes for spawn
+#include <windows.h>
 #include <process.h>
 #include <errno.h>
 // include for getcwd
@@ -44,7 +46,6 @@
 #include <stdlib.h>
 
 #include <limits>
-#include <iostream>
 
 // print the version
 void dicomfind_version(FILE *file, const char *cp)
@@ -214,13 +215,32 @@ bool execute_command(const char *command, char *argv[])
   return true;
 }
 #else
-bool execute_command(const char *command, char *argv[])
+bool execute_command(const char *, char *argv[])
 {
+  bool rval = true;
+
   // flush the output
   fflush(stdout);
   fflush(stderr);
 
-  if (_spawnvp(_P_WAIT, command, argv) != 0)
+  int m = 0;
+  while (argv[m] != 0)
+    {
+    m++;
+    }
+
+  wchar_t **wargv = new wchar_t *[m + 1];
+
+  for (int i = 0; i < m; i++)
+    {
+    int n = MultiByteToWideChar(CP_UTF8, 0, argv[i], -1, NULL, 0);
+    wargv[i] = new wchar_t[n];
+    MultiByteToWideChar(CP_UTF8, 0, argv[i], -1, wargv[i], n);
+    }
+
+  wargv[m] = 0;
+
+  if (_wspawnvp(_P_WAIT, wargv[0], wargv) != 0)
     {
     if (errno == ENOENT)
       {
@@ -243,10 +263,16 @@ bool execute_command(const char *command, char *argv[])
       fprintf(stderr, "Unknown error while running command: %s\n", argv[0]);
       }
 
-    return false;
+    rval = false;
     }
 
-  return true;
+  for (int i = 0; i < m; i++)
+    {
+    delete [] wargv[i];
+    }
+  delete [] wargv;
+
+  return rval;
 }
 #endif
 
@@ -259,7 +285,12 @@ int dicomfind_chdir(const char *dirname)
 int dicomfind_chdir(const char *dirname)
 {
   // use _wchdir to allow paths longer than the 260 char limit
-  return _chdir(dirname);
+  int n = MultiByteToWideChar(CP_UTF8, 0, dirname, -1, NULL, 0);
+  wchar_t *wp = new wchar_t[n];
+  MultiByteToWideChar(CP_UTF8, 0, dirname, -1, wp, n);
+  int rval = _wchdir(wp);
+  delete [] wp;
+  return rval;
 }
 #endif
 
@@ -272,8 +303,16 @@ std::string dicomfind_getcwd()
 #else
 std::string dicomfind_getcwd()
 {
-  char buffer[2048];
-  return _getcwd(buffer, sizeof(buffer));
+  wchar_t wbuffer[2048];
+  wchar_t *wp = _wgetcwd(wbuffer, sizeof(wbuffer)/sizeof(wchar_t));
+  int n = WideCharToMultiByte(
+    CP_UTF8, 0, wp, -1, NULL, 0, NULL, NULL);
+  char *cp = new char[n];
+  WideCharToMultiByte(
+    CP_UTF8, 0, wp, -1, cp, n, NULL, NULL);
+  std::string s = cp;
+  delete [] cp;
+  return s;
 }
 #endif
 
@@ -300,10 +339,10 @@ void dicomfind_operations(
       char endchar = (op->Type == "-print0" ? '\0' : '\n');
       for (int kk = 0; kk < sa->GetNumberOfValues(); kk++)
         {
-        std::cout << sa->GetValue(kk);
-        std::cout.put(endchar);
+        fprintf(stdout, "%s", sa->GetValue(kk).c_str());
+        fputc(endchar, stdout);
         }
-      std::cout.flush();
+      fflush(stdout);
       }
     else if (op->Type == "-exec" || op->Type == "-execdir")
       {
@@ -498,6 +537,9 @@ MAINMACRO_PASSTHROUGH(-name);
 // This program will dump all the metadata in the given file
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   std::vector<Operation> operationList;
 
   int rval = 0;
diff --git a/Programs/dicompull.cxx b/Programs/dicompull.cxx
index 86b6ac8..c105a9d 100644
--- a/Programs/dicompull.cxx
+++ b/Programs/dicompull.cxx
@@ -24,6 +24,7 @@
 #include "vtkDICOMFileDirectory.h"
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 #include "readquery.h"
 #include "progress.h"
@@ -37,7 +38,6 @@
 #include <ctype.h>
 
 #include <limits>
-#include <iostream>
 #include <map>
 #include <utility>
 
@@ -253,6 +253,9 @@ MAINMACRO_PASSTHROUGH(-name);
 // This program will find and copy dicom files
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
   int scandepth = std::numeric_limits<int>::max();
   bool followSymlinks = true;
diff --git a/Programs/dicomtocsv.cxx b/Programs/dicomtocsv.cxx
index a695d71..c59aa40 100644
--- a/Programs/dicomtocsv.cxx
+++ b/Programs/dicomtocsv.cxx
@@ -23,6 +23,7 @@
 #include "vtkDICOMFile.h"
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 #include "readquery.h"
 #include "progress.h"
@@ -37,7 +38,10 @@
 #include <stdlib.h>
 
 #include <limits>
-#include <iostream>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 namespace {
 
@@ -92,7 +96,10 @@ void dicomtocsv_help(FILE *file, const char *cp)
     "file and as a \"-k\" option), then its first appearance will set the\n"
     "column number that it appears in.  Also, with regards to the search,\n"
     "the value specified in the final appearance of the tag as an option\n"
-    "will be the value used for the search.\n\n");
+    "will be the value used for the search.\n"
+    "\n"
+    "If no attributes are specified with either \"-k\" or \"-q\", then a\n"
+    "default set of query attributes will be used.\n\n");
 }
 
 // remove path portion of filename
@@ -105,16 +112,130 @@ const char *dicomtocsv_basename(const char *filename)
 
 typedef vtkDICOMVR VR;
 
+// Create a default query for --image
+void dicomtocsv_image_default(vtkDICOMItem *query, QueryTagList *ql)
+{
+  // these are the attributes that must be part of the query
+  static const DC::EnumType defaultElements[] = {
+    // patient-level information
+    DC::PatientName,          // 2
+    DC::PatientID,            // 1
+    DC::PatientBirthDate,     // 3
+    DC::PatientSex,           // 3
+    // study-level information
+    DC::StudyDate,            // 1
+    DC::StudyTime,            // 1
+    DC::StudyID,              // 1
+    DC::AccessionNumber,      // 2
+    DC::StudyDescription,     // 2
+    DC::StudyInstanceUID,     // 1
+    // series-level information
+    DC::Modality,             // 1
+    DC::SeriesNumber,         // 1
+    DC::SeriesDescription,    // 3
+    DC::SeriesInstanceUID,    // 1
+    DC::Rows,                 // 3
+    DC::Columns,              // 3
+    // image-level information
+    DC::InstanceNumber,       // 1
+    DC::SOPClassUID,          // 1
+    DC::SOPInstanceUID,       // 1
+    DC::ReferencedFileID,     // special
+    // delimiter to mark end of list
+    DC::ItemDelimitationItem
+  };
+
+  for (const DC::EnumType *tagPtr = defaultElements;
+       *tagPtr != DC::ItemDelimitationItem;
+       ++tagPtr)
+    {
+    VR vr = query->FindDictVR(*tagPtr);
+    query->SetAttributeValue(*tagPtr, vtkDICOMValue(vr));
+    ql->push_back(vtkDICOMTagPath(*tagPtr));
+    }
+}
+
+// Create a default query for --series
+void dicomtocsv_series_default(vtkDICOMItem *query, QueryTagList *ql)
+{
+  // these are the attributes that must be part of the query
+  static const DC::EnumType defaultElements[] = {
+    // patient-level information
+    DC::PatientName,          // 2
+    DC::PatientID,            // 1
+    DC::PatientBirthDate,     // 3
+    DC::PatientSex,           // 3
+    // study-level information
+    DC::StudyDate,            // 1
+    DC::StudyTime,            // 1
+    DC::StudyID,              // 1
+    DC::AccessionNumber,      // 2
+    DC::StudyDescription,     // 2
+    DC::StudyInstanceUID,     // 1
+    // series-level information
+    DC::Modality,             // 1
+    DC::SeriesNumber,         // 1
+    DC::SeriesDescription,    // 3
+    DC::SeriesInstanceUID,    // 1
+    DC::Rows,                 // 3
+    DC::Columns,              // 3
+    DC::NumberOfReferences,   // special
+    // delimiter to mark end of list
+    DC::ItemDelimitationItem
+  };
+
+  for (const DC::EnumType *tagPtr = defaultElements;
+       *tagPtr != DC::ItemDelimitationItem;
+       ++tagPtr)
+    {
+    VR vr = query->FindDictVR(*tagPtr);
+    query->SetAttributeValue(*tagPtr, vtkDICOMValue(vr));
+    ql->push_back(vtkDICOMTagPath(*tagPtr));
+    }
+}
+
+// Create a default query for --study
+void dicomtocsv_study_default(vtkDICOMItem *query, QueryTagList *ql)
+{
+  // these are the attributes that must be part of the query
+  static const DC::EnumType defaultElements[] = {
+    // patient-level information
+    DC::PatientName,          // 2
+    DC::PatientID,            // 1
+    DC::PatientBirthDate,     // 3
+    DC::PatientSex,           // 3
+    // study-level information
+    DC::StudyDate,            // 1
+    DC::StudyTime,            // 1
+    DC::StudyID,              // 1
+    DC::AccessionNumber,      // 2
+    DC::StudyDescription,     // 2
+    DC::StudyInstanceUID,     // 1
+    DC::NumberOfReferences,   // special
+    // delimiter to mark end of list
+    DC::ItemDelimitationItem
+  };
+
+  for (const DC::EnumType *tagPtr = defaultElements;
+       *tagPtr != DC::ItemDelimitationItem;
+       ++tagPtr)
+    {
+    VR vr = query->FindDictVR(*tagPtr);
+    query->SetAttributeValue(*tagPtr, vtkDICOMValue(vr));
+    ql->push_back(vtkDICOMTagPath(*tagPtr));
+    }
+}
+
 // Write the header for a csv file
 void dicomtocsv_writeheader(
-  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os)
+  const vtkDICOMItem& query, const QueryTagList *ql, FILE *fp)
 {
   // print human-readable names for each tag
   for (size_t i = 0; i < ql->size(); i++)
     {
     if (i != 0)
       {
-      os << ",";
+      fprintf(fp, "%s", ",");
       }
     const vtkDICOMItem *pitem = &query;
     vtkDICOMTagPath tagPath = ql->at(i);
@@ -124,7 +245,7 @@ void dicomtocsv_writeheader(
       vtkDICOMDictEntry e = pitem->FindDictEntry(tag);
       if (e.IsValid())
         {
-        os << e.GetName();
+        fprintf(fp, "%s", e.GetName());
         }
       if (!tagPath.HasTail())
         {
@@ -132,10 +253,10 @@ void dicomtocsv_writeheader(
         }
       pitem = pitem->GetAttributeValue(tag).GetSequenceData();
       tagPath = tagPath.GetTail();
-      os << "\\";
+      fprintf(fp, "%s", "\\");
       }
     }
-  os << "\r\n";
+  fprintf(fp, "%s", "\r\n");
 }
 
 // Convert date to format YYYY-MM-DD HH:MM:SS
@@ -186,7 +307,7 @@ std::string dicomtocsv_quote(const std::string& s)
 
 // Write out the results in csv format
 void dicomtocsv_write(vtkDICOMDirectory *finder,
-  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os,
+  const vtkDICOMItem& query, const QueryTagList *ql, FILE *fp,
   int level, bool firstNonZero, bool useDirectoryRecords, vtkCommand *p)
 {
   // for keeping track of progress
@@ -262,9 +383,6 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
           }
         }
 
-      // create an adapter, in case of enhanced IOD
-      vtkDICOMMetaDataAdapter adapter(meta);
-
       // this loop is only for the "image" level
       int m = (level >= 4 ? meta->GetNumberOfInstances() : 1);
       for (int jj = 0; jj < m; jj++)
@@ -274,7 +392,7 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
           {
           if (i != 0)
             {
-            os << ",";
+            fprintf(fp, "%s", ",");
             }
 
           const vtkDICOMItem *qitem = &query;
@@ -287,6 +405,10 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
           n = (level >= 4 ? jj+1 : n);
           for (int ii = jj; ii < n; ii++)
             {
+            // Create an adapter, which helps with extracting attributes from
+            // the PerFrameFunctionalSequence of enhanced IODs.
+            vtkDICOMMetaDataAdapter adapter(meta, ii);
+
             for (;;)
               {
               vtkDICOMTag tag = tagPath.GetHead();
@@ -308,21 +430,31 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
                 {
                 vp = &mitem->GetAttributeValue(tag);
                 }
+              else if (tag != DC::NumberOfFrames)
+                {
+                // vtkDICOMMetaDataAdapter hides NumberOfFrames, so it
+                // will never be found if we check the adapter
+                vp = &adapter->GetAttributeValue(tag);
+                }
               else
                 {
-                vp = &adapter->GetAttributeValue(ii, tag);
+                vp = &meta->GetAttributeValue(ii, tag);
                 }
               if (vp && !vp->IsValid())
                 {
                 vp = 0;
                 }
+              // break if we have reached the end of a tag path
               if (vp == 0 || !tagPath.HasTail())
                 {
                 break;
                 }
+              // go one level deeper into the query
               qitem = qitem->GetAttributeValue(
                 tagPath.GetHead()).GetSequenceData();
+              // go one level deeper along the tag path
               tagPath = tagPath.GetTail();
+              // go one level deeper into the meta data
               mitem = vp->GetSequenceData();
               if (mitem == 0 || vp->GetNumberOfValues() == 0)
                 {
@@ -351,13 +483,15 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
                  v.GetVR() == VR::FL ||
                  v.GetVR() == VR::FD))
               {
-              os << v;
+              std::string s = v.AsString();
+              fprintf(fp, "%s", s.c_str());
               }
             else if (v.GetVR() == VR::DA ||
                      v.GetVR() == VR::TM ||
                      v.GetVR() == VR::DT)
               {
-              os << "\"" << dicomtocsv_date(v.AsString(), v.GetVR()) << "\"";
+              std::string s = dicomtocsv_date(v.AsString(), v.GetVR());
+              fprintf(fp, "\"%s\"", s.c_str());
               }
             else if (v.GetVR() == VR::SQ)
               {
@@ -365,7 +499,8 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
               }
             else if (v.GetVL() != 0 && v.GetVL() != 0xFFFFFFFF)
               {
-              os << "\"" << dicomtocsv_quote(v.AsUTF8String()) << "\"";
+              std::string s = dicomtocsv_quote(v.AsUTF8String());
+              fprintf(fp, "\"%s\"", s.c_str());
               }
             }
           else if (tagPath.GetHead() == DC::ReferencedFileID &&
@@ -373,7 +508,8 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
             {
             // ReferencedFileID (0004,1500) is meant to be used in DICOMDIR,
             // but we hijack it to report the first file in the series.
-            os << "\"" << dicomtocsv_quote(a->GetValue(jj)) << "\"";
+            std::string s = dicomtocsv_quote(a->GetValue(jj));
+            fprintf(fp, "\"%s\"", s.c_str());
             }
           else if (tagPath.GetHead() == DC::NumberOfReferences &&
                    !tagPath.HasTail())
@@ -382,11 +518,11 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
             // to count the number of references to a file, but we hijack
             // it and use it to report the number of files found for the
             // series.
-            os << "\"" << numberOfFiles << "\"";
+            fprintf(fp, "\"%d\"", numberOfFiles);
             }
           }
 
-        os << "\r\n";
+        fprintf(fp, "%s", "\r\n");
 
         // report progress
         if (p)
@@ -411,6 +547,9 @@ void dicomtocsv_write(vtkDICOMDirectory *finder,
 // This program will dump all the metadata in the given file
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
   int scandepth = std::numeric_limits<int>::max();
   QueryTagList qtlist;
@@ -561,22 +700,28 @@ int MAINMACRO(int argc, char *argv[])
       }
     }
 
-  std::ostream *osp = &std::cout;
-  std::ofstream ofs;
+  FILE *fp = stdout;
+  FILE *fp1 = NULL;
 
   if (ofile)
     {
-    ofs.open(ofile,
-             std::ofstream::out |
-             std::ofstream::binary |
-             std::ofstream::trunc);
-
-    if (ofs.fail())
+#ifndef _WIN32
+    fp1 = fopen(ofile, "wb");
+#else
+    // use wide chars to avoid narrowing to local character set
+    int n = MultiByteToWideChar(CP_UTF8, 0, ofile, -1, NULL, 0);
+    wchar_t *wofile = new wchar_t[n];
+    MultiByteToWideChar(CP_UTF8, 0, ofile, -1, wofile, n);
+    fp1 = _wfopen(wofile, L"wb");
+    delete [] wofile;
+#endif
+
+    if (!fp1)
       {
       fprintf(stderr, "Error: Unable to open output file %s.\n", ofile);
       return 1;
       }
-    osp = &ofs;
+    fp = fp1;
     }
   else
     {
@@ -584,9 +729,26 @@ int MAINMACRO(int argc, char *argv[])
     silent = true;
     }
 
+  // If no query specified, then use a default one
+  if (qtlist.size() == 0)
+    {
+    if (level == 2)
+      {
+      dicomtocsv_study_default(&query, &qtlist);
+      }
+    else if (level == 3)
+      {
+      dicomtocsv_series_default(&query, &qtlist);
+      }
+    else if (level == 4)
+      {
+      dicomtocsv_image_default(&query, &qtlist);
+      }
+    }
+
   // Write the header
-  dicomtocsv_writeheader(query, &qtlist, *osp);
-  osp->flush();
+  dicomtocsv_writeheader(query, &qtlist, fp);
+  fflush(fp);
 
   // Write data for every input directory
   if (a->GetNumberOfTuples() > 0)
@@ -617,10 +779,15 @@ int MAINMACRO(int argc, char *argv[])
       p->SetText("Writing");
       }
     dicomtocsv_write(
-      finder, query, &qtlist, *osp, level,
+      finder, query, &qtlist, fp, level,
       firstNonZero, useDirectoryRecords, p);
 
-    osp->flush();
+    fflush(fp);
+    }
+
+  if (fp1)
+    {
+    fclose(fp1);
     }
 
   return rval;
diff --git a/Programs/dicomtodicom.cxx b/Programs/dicomtodicom.cxx
index 4c65f4e..dfc334b 100644
--- a/Programs/dicomtodicom.cxx
+++ b/Programs/dicomtodicom.cxx
@@ -46,6 +46,7 @@
 #include <ctype.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // Kinds of reformats
@@ -628,6 +629,9 @@ void dicomtodicom_convert_files(
 // This program will convert DICOM to DICOM
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   // for the list of input DICOM files
   vtkSmartPointer<vtkStringArray> files =
     vtkSmartPointer<vtkStringArray>::New();
diff --git a/Programs/dicomtonifti.cxx b/Programs/dicomtonifti.cxx
index 62f03e8..05be227 100644
--- a/Programs/dicomtonifti.cxx
+++ b/Programs/dicomtonifti.cxx
@@ -53,6 +53,7 @@
 #include <ctype.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // Simple structure for command-line options
@@ -1088,6 +1089,9 @@ void dicomtonifti_files_and_dirs(
 // This program will convert DICOM to NIFTI
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   // for the list of input DICOM files
   vtkSmartPointer<vtkStringArray> files =
     vtkSmartPointer<vtkStringArray>::New();
diff --git a/Programs/nifticenter.cxx b/Programs/nifticenter.cxx
index 5833a5e..9c808ed 100644
--- a/Programs/nifticenter.cxx
+++ b/Programs/nifticenter.cxx
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // remove path portion of filename
@@ -38,6 +39,9 @@ const char *basename(const char *filename)
 // This program will convert
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
 
   if (argc < 2)
diff --git a/Programs/niftidump.cxx b/Programs/niftidump.cxx
index b43cd5a..4184cf7 100644
--- a/Programs/niftidump.cxx
+++ b/Programs/niftidump.cxx
@@ -16,16 +16,18 @@
 #include "vtkNIFTIReader.h"
 #include "vtkNIFTIHeader.h"
 #include "vtkNIFTIPrivate.h"
-#include "vtkMatrix4x4.h"
-#include "vtkStringArray.h"
 
+#include <vtkMatrix4x4.h>
+#include <vtkStringArray.h>
 #include <vtkSmartPointer.h>
 
 #include <stdio.h>
+#include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // print the version
@@ -56,6 +58,34 @@ void printHelp(FILE *file, const char *cp)
     "Dump the header from a NIfTI file.\n");
 }
 
+// sanitize a string (remove unprintable characters)
+#define SANITIZE_BUFSIZE 82
+const char *stringSanitize(
+  char op[SANITIZE_BUFSIZE], const char *cp, size_t l)
+{
+  if (l >= SANITIZE_BUFSIZE)
+    {
+    l = SANITIZE_BUFSIZE - 1;
+    }
+
+  size_t i;
+  for (i = 0; i < l && cp[i] != '\0'; i++)
+    {
+    if (isprint(cp[i]))
+      {
+      op[i] = cp[i];
+      }
+    else
+      {
+      op[i] = '?';
+      }
+    }
+
+  op[i] = '\0';
+
+  return op;
+}
+
 // remove path portion of filename
 const char *fileBasename(const char *filename)
 {
@@ -67,6 +97,9 @@ const char *fileBasename(const char *filename)
 // This program will convert
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
 
   if (argc < 2)
@@ -265,124 +298,103 @@ int MAINMACRO(int argc, char *argv[])
       }
     }
 
-  cout << "sizeof_hdr: " << (version >= 2 ?
-                             vtkNIFTIHeader::Nifti2HeaderSize :
-                             vtkNIFTIHeader::Nifti1HeaderSize) << "\n";
-  cout << "vox_offset: " << hdr.vox_offset << "\n";
-  //cout << "data_type: " << hdr.data_type << "\n";
-  //cout << "db_name: " << hdr.db_name << "\n";
-  //cout << "extents: " << hdr.extents << "\n";
-  //cout << "session_error: " << hdr.session_error << "\n";
-  //cout << "regular: " << static_cast<int>(hdr.regular) << "\n";
-  cout.setf(std::ios::hex, std::ios::basefield);
-  cout << "dim_info: 0x" << static_cast<int>(hdr.dim_info);
+  // temporary space
+  char buf[SANITIZE_BUFSIZE];
+
+  printf("sizeof_hdr: %d\n", (version >= 2 ?
+                              vtkNIFTIHeader::Nifti2HeaderSize :
+                              vtkNIFTIHeader::Nifti1HeaderSize));
+  printf("vox_offset: %lld\n", hdr.vox_offset);
+  //printf("data_type: %.10s\n", hdr.data_type);
+  //printf("db_name: %.18s\n", hdr.db_name);
+  //printf("extents: %d\n", hdr.extents);
+  //printf("session_error: %d\n", hdr.session_error);
+  //printf("regular: %d\n", hdr.regular);
+  printf("dim_info: 0x%x", hdr.dim_info);
   if (hdr.dim_info == 0)
     {
-    cout << " (unknown)\n";
+    printf(" (unknown)\n");
     }
   else
     {
-    cout << " (freq_dim=" << (hdr.dim_info & 0x3)
-         << ", phase_dim=" << ((hdr.dim_info >> 2) & 0x3)
-         << ", slice_dim=" << ((hdr.dim_info >> 4) & 0x3) << ")\n";
+    printf(" (freq_dim=%d, phase_dim=%d, slice_dim=%d\n",
+           (hdr.dim_info & 0x3),
+           ((hdr.dim_info >> 2) & 0x3),
+           ((hdr.dim_info >> 4) & 0x3));
     }
-  cout.unsetf(std::ios::hex);
-  cout << "dim:";
+  printf("dim:");
   for (int i = 0; i < 8; i++)
     {
-    cout << " " << hdr.dim[i];
+    printf(" %lld", hdr.dim[i]);
     }
-  cout << "\n";
-  cout << "pixdim:";
+  printf("\n");
+  printf("pixdim:");
   for (int i = 0; i < 8; i++)
     {
-    cout << " " << hdr.pixdim[i];
+    printf(" %g", hdr.pixdim[i]);
     }
-  cout << "\n";
-  cout.setf(std::ios::hex, std::ios::basefield);
-  cout << "xyzt_units: 0x" << static_cast<int>(hdr.xyzt_units)
-       << " (" << spaceUnits << ", " << timeUnits << ")\n";
-  cout.unsetf(std::ios::hex);
+  printf("\n");
+  printf("xyzt_units: 0x%x (%s, %s)\n",
+         hdr.xyzt_units, spaceUnits, timeUnits);
   if (version > 0)
     {
-    cout << "intent_code: " << hdr.intent_code
-         << " (" << intentCode << ")\n";
-    cout << "intent_name: \"";
-    for (size_t j = 0;
-         j < sizeof(hdr.intent_name) && hdr.intent_name[j] != '\0';
-         j++)
-      {
-      cout << (isprint(hdr.intent_name[j]) ? hdr.intent_name[j] : '?');
-      }
-    cout << "\"\n";
-    cout << "intent_p1: " << hdr.intent_p1 << "\n";
-    cout << "intent_p2: " << hdr.intent_p2 << "\n";
-    cout << "intent_p3: " << hdr.intent_p3 << "\n";
+    printf("intent_code: %d (%s)\n",
+           hdr.intent_code, intentCode);
+    printf("intent_name: \"%s\"\n",
+           stringSanitize(buf, hdr.intent_name, sizeof(hdr.intent_name)));
+    printf("intent_p1: %g\n", hdr.intent_p1);
+    printf("intent_p2: %g\n", hdr.intent_p2);
+    printf("intent_p3: %g\n", hdr.intent_p3);
     }
-  cout << "datatype: " << hdr.datatype
-     << " (" << datatypeName << ")\n";
-  cout << "bitpix: " << hdr.bitpix << "\n";
+  printf("datatype: %d (%s)\n", hdr.datatype, datatypeName);
+  printf("bitpix: %d\n", hdr.bitpix);
   if (version > 0)
     {
-    cout << "scl_slope: " << hdr.scl_slope << "\n";
-    cout << "scl_inter: " << hdr.scl_inter << "\n";
-    cout << "cal_max: " << hdr.cal_max << "\n";
-    cout << "cal_min: " << hdr.cal_min << "\n";
-    cout << "slice_code: " << static_cast<int>(hdr.slice_code)
-         << " (" << sliceCode << ")\n";
-    cout << "slice_start: " << hdr.slice_start << "\n";
-    cout << "slice_end: " << hdr.slice_end << "\n";
-    cout << "slice_duration: " << hdr.slice_duration << "\n";
-    cout << "toffset: " << hdr.toffset << "\n";
+    printf("scl_slope: %g\n", hdr.scl_slope);
+    printf("scl_inter: %g\n", hdr.scl_inter);
+    printf("cal_max: %g\n", hdr.cal_max);
+    printf("cal_min: %g\n", hdr.cal_min);
+    printf("slice_code: %d (%s)\n", hdr.slice_code, sliceCode);
+    printf("slice_start: %lld\n", hdr.slice_start);
+    printf("slice_end: %lld\n", hdr.slice_end);
+    printf("slice_duration: %g\n", hdr.slice_duration);
+    printf("toffset: %g\n", hdr.toffset);
     }
-  cout << "descrip: \"";
-  for (size_t j = 0; j < sizeof(hdr.descrip) && hdr.descrip[j] != '\0'; j++)
-    {
-    cout << (isprint(hdr.descrip[j]) ? hdr.descrip[j] : '?');
-    }
-  cout << "\"\n";
-  cout << "aux_file: \"";
-  for (size_t j = 0; j < sizeof(hdr.aux_file) && hdr.aux_file[j] != '\0'; j++)
-    {
-    cout << (isprint(hdr.aux_file[j]) ? hdr.aux_file[j] : '?');
-    }
-  cout << "\"\n";
+  printf("descrip: \"%s\"\n",
+         stringSanitize(buf, hdr.descrip, sizeof(hdr.descrip)));
+  printf("aux_file: \"%s\"\n",
+         stringSanitize(buf, hdr.aux_file, sizeof(hdr.aux_file)));
   if (version > 0)
     {
-    cout << "qform_code: " << hdr.qform_code
-         << " (" << xformCode[0] << ")\n";
-    cout << "sform_code: " << hdr.sform_code
-         << " (" << xformCode[1] << ")\n";
-    cout << "quatern_b: " << hdr.quatern_b << "\n";
-    cout << "quatern_c: " << hdr.quatern_c << "\n";
-    cout << "quatern_d: " << hdr.quatern_d << "\n";
-    cout << "qoffset_x: " << hdr.qoffset_x << "\n";
-    cout << "qoffset_y: " << hdr.qoffset_y << "\n";
-    cout << "qoffset_z: " << hdr.qoffset_z << "\n";
-    cout << "srow_x:";
+    printf("qform_code: %d (%s)\n", hdr.qform_code, xformCode[0]);
+    printf("sform_code: %d (%s)\n", hdr.sform_code, xformCode[1]);
+    printf("quatern_b: %g\n", hdr.quatern_b);
+    printf("quatern_c: %g\n", hdr.quatern_c);
+    printf("quatern_d: %g\n", hdr.quatern_d);
+    printf("qoffset_x: %g\n", hdr.qoffset_x);
+    printf("qoffset_y: %g\n", hdr.qoffset_y);
+    printf("qoffset_z: %g\n", hdr.qoffset_z);
+    printf("srow_x:");
     for (int i = 0; i < 4; i++)
       {
-      cout << " " << hdr.srow_x[i];
+      printf(" %g", hdr.srow_x[i]);
       }
-    cout << "\n";
-    cout << "srow_y:";
+    printf("\n");
+    printf("srow_y:");
     for (int i = 0; i < 4; i++)
       {
-      cout << " " << hdr.srow_y[i];
+      printf(" %g", hdr.srow_y[i]);
       }
-    cout << "\n";
-    cout << "srow_z:";
+    printf("\n");
+    printf("srow_z:");
     for (int i = 0; i < 4; i++)
       {
-      cout << " " << hdr.srow_z[i];
-      }
-    cout << "\n";
-    cout << "magic: \"";
-    for (size_t j = 0; j < sizeof(hdr.magic) && hdr.magic[j] != '\0'; j++)
-      {
-      cout << (isprint(hdr.magic[j]) ? hdr.magic[j] : '?');
+      printf(" %g", hdr.srow_z[i]);
       }
-    cout << "\"" << endl;
+    printf("\n");
+    printf("magic: \"%s\"\n",
+           stringSanitize(buf, hdr.magic, sizeof(hdr.magic)));
+    fflush(stdout);
     }
 
   return rval;
diff --git a/Programs/niftitodicom.cxx b/Programs/niftitodicom.cxx
index 25df8c9..2304af9 100644
--- a/Programs/niftitodicom.cxx
+++ b/Programs/niftitodicom.cxx
@@ -54,6 +54,7 @@
 #include <ctype.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // Kinds of reformats
@@ -826,6 +827,9 @@ void niftitodicom_convert_files(
 // This program will convert NIFTI to DICOM
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   // for the list of input DICOM files
   vtkSmartPointer<vtkStringArray> files =
     vtkSmartPointer<vtkStringArray>::New();
diff --git a/Programs/scancodump.cxx b/Programs/scancodump.cxx
index 543c59d..24afe99 100644
--- a/Programs/scancodump.cxx
+++ b/Programs/scancodump.cxx
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // print the version
@@ -62,6 +63,9 @@ const char *fileBasename(const char *filename)
 // This program will convert
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   int rval = 0;
 
   if (argc < 2)
@@ -92,57 +96,58 @@ int MAINMACRO(int argc, char *argv[])
   reader->GetDataSpacing(spacing);
   reader->GetDataExtent(extent);
 
-  cout << "Version: " << reader->GetVersion() << "\n";
-  cout << "CreationDate: " << reader->GetCreationDate() << "\n";
+  printf("Version: %s\n", reader->GetVersion());
+  printf("CreationDate: %s\n", reader->GetCreationDate());
   if (strncmp(reader->GetVersion(), "AIMDATA", 7) == 0)
     {
-    cout << "ModificationDate: " << reader->GetModificationDate() << "\n";
-    cout << "Position: "
-         << static_cast<int>(origin[0]/spacing[0] + 0.5) << " "
-         << static_cast<int>(origin[1]/spacing[1] + 0.5) << " "
-         << static_cast<int>(origin[2]/spacing[2] + 0.5) << "\n";
-    cout << "Dimensions: "
-         << (extent[1] - extent[0] + 1) << " "
-         << (extent[3] - extent[2] + 1) << " "
-         << (extent[5] - extent[4] + 1) << "\n";
-    cout << "ElementSize: "
-         << spacing[0] << " " << spacing[1] << " " << spacing[2] << " [mm]\n";
-    cout << "DataType: "
-         << (reader->GetDataScalarType() == VTK_SHORT ? "short\n" : "byte\n");
+    printf("ModificationDate: %s\n", reader->GetModificationDate());
+    printf("Position: %d %d %d\n",
+           static_cast<int>(origin[0]/spacing[0] + 0.5),
+           static_cast<int>(origin[1]/spacing[1] + 0.5),
+           static_cast<int>(origin[2]/spacing[2] + 0.5));
+    printf("Dimensions: %d %d %d\n",
+           (extent[1] - extent[0] + 1),
+           (extent[3] - extent[2] + 1),
+           (extent[5] - extent[4] + 1));
+    printf("ElementSize: %g %g %g [mm]\n",
+           spacing[0], spacing[1], spacing[2]);
+    printf("DataType: %s\n",
+           (reader->GetDataScalarType() == VTK_SHORT ? "short" : "byte"));
     }
   reader->GetScanDimensionsPixels(ivec);
-  cout << "ScanDimensionsPixels: "
-       << ivec[0] << " " << ivec[1] << " " << ivec[2] << "\n";
+  printf("ScanDimensionsPixels: %d %d %d\n",
+         ivec[0], ivec[1], ivec[2]);
   reader->GetScanDimensionsPhysical(dvec);
-  cout << "ScanDimensionsPhysical: "
-       << dvec[0] << " " << dvec[1] << " " << dvec[2] << " [mm]\n";
-  cout << "PatientName: " << reader->GetPatientName() << "\n";
-  cout << "PatientIndex: " << reader->GetPatientIndex() << "\n";
-  cout << "MeasurementIndex: " << reader->GetMeasurementIndex() << "\n";
-  cout << "Site: " << reader->GetSite() << "\n";
-  cout << "ScannerID: " << reader->GetScannerID() << "\n";
-  cout << "ScannerType: " << reader->GetScannerType() << "\n";
-  cout << "PositionSlice1: " << reader->GetStartPosition() << " [mm]\n";
-  cout << "ReferenceLine: " << reader->GetReferenceLine() << " [mm]\n";
-  cout << "NumberOfSamples: " << reader->GetNumberOfSamples() << "\n";
-  cout << "NumberOfProjections: " << reader->GetNumberOfProjections() << "\n";
-  cout << "ScanDistance: " << reader->GetScanDistance() << " [mm]\n";
-  cout << "SampleTime: " << reader->GetSampleTime() << " [ms]\n";
-  cout << "SliceThickness: " << reader->GetSliceThickness() << " [mm]\n";
-  cout << "SliceIncrement: " << reader->GetSliceIncrement() << " [mm]\n";
-  cout << "ReconstructionAlg: " << reader->GetReconstructionAlg() << "\n";
-  cout << "Energy: " << reader->GetEnergy() << " [kV]\n";
-  cout << "Intensity: " << reader->GetIntensity() << " [mA]\n";
-  cout << "MuScaling: " << reader->GetMuScaling() << " [cm]\n";
+  printf("ScanDimensionsPhysical: %g %g %g [mm]\n",
+         dvec[0], dvec[1], dvec[2]);
+  printf("PatientName: %s\n", reader->GetPatientName());
+  printf("PatientIndex: %d\n", reader->GetPatientIndex());
+  printf("MeasurementIndex: %d\n", reader->GetMeasurementIndex());
+  printf("Site: %d\n", reader->GetSite());
+  printf("ScannerID: %d\n", reader->GetScannerID());
+  printf("ScannerType: %d\n", reader->GetScannerType());
+  printf("PositionSlice1: %g [mm]\n", reader->GetStartPosition());
+  printf("ReferenceLine: %g [mm]\n", reader->GetReferenceLine());
+  printf("NumberOfSamples: %d\n", reader->GetNumberOfSamples());
+  printf("NumberOfProjections: %d\n", reader->GetNumberOfProjections());
+  printf("ScanDistance: %g [mm]\n", reader->GetScanDistance());
+  printf("SampleTime: %g [ms]\n", reader->GetSampleTime());
+  printf("SliceThickness: %g [mm]\n", reader->GetSliceThickness());
+  printf("SliceIncrement: %g [mm]\n", reader->GetSliceIncrement());
+  printf("ReconstructionAlg: %d\n", reader->GetReconstructionAlg());
+  printf("Energy: %g [kV]\n", reader->GetEnergy());
+  printf("Intensity: %g [mA]\n", reader->GetIntensity());
+  printf("MuScaling: %g [cm]\n", reader->GetMuScaling());
   reader->GetDataRange(dvec);
-  cout << "DataRange: " << dvec[0] << " " << dvec[1] << "\n";
-  cout << "CalibrationData: " << reader->GetCalibrationData() << "\n";
-  cout << "RescaleType: " << reader->GetRescaleType() << "\n";
-  cout << "RescaleUnits: " << reader->GetRescaleUnits() << "\n";
-  cout << "RescaleSlope: " << reader->GetRescaleSlope() << "\n";
-  cout << "RescaleIntercept: " << reader->GetRescaleIntercept() << "\n";
-  cout << "MuWater: " << reader->GetMuWater() << " [cm^-1]\n";
-  cout << "HeaderSize: " << reader->GetHeaderSize() << "\n";
+  printf("DataRange: %g %g\n", dvec[0], dvec[1]);
+  printf("CalibrationData: %s\n", reader->GetCalibrationData());
+  printf("RescaleType: %d\n", reader->GetRescaleType());
+  printf("RescaleUnits: %s\n", reader->GetRescaleUnits());
+  printf("RescaleSlope: %g\n", reader->GetRescaleSlope());
+  printf("RescaleIntercept: %g\n", reader->GetRescaleIntercept());
+  printf("MuWater: %g [cm^-1]\n", reader->GetMuWater());
+  printf("HeaderSize: %d\n", static_cast<int>(reader->GetHeaderSize()));
+  fflush(stdout);
 
   return 0;
 }
diff --git a/Programs/scancotodicom.cxx b/Programs/scancotodicom.cxx
index a681e18..1981151 100644
--- a/Programs/scancotodicom.cxx
+++ b/Programs/scancotodicom.cxx
@@ -43,6 +43,7 @@
 #include <limits.h>
 
 // from dicomcli
+#include "vtkConsoleOutputWindow.h"
 #include "mainmacro.h"
 
 // The file types
@@ -633,6 +634,9 @@ void scancotodicom_convert_one(
 // This program will convert ScancoCT to DICOM
 int MAINMACRO(int argc, char *argv[])
 {
+  // redirect all VTK errors to stderr
+  vtkConsoleOutputWindow::Install();
+
   // for the list of input DICOM files
   vtkSmartPointer<vtkStringArray> files =
     vtkSmartPointer<vtkStringArray>::New();
diff --git a/Source/vtkDICOMCharacterSet.cxx b/Source/vtkDICOMCharacterSet.cxx
index 8ea5af4..ffa8404 100644
--- a/Source/vtkDICOMCharacterSet.cxx
+++ b/Source/vtkDICOMCharacterSet.cxx
@@ -2126,8 +2126,10 @@ const unsigned short CodePageJISX0212[8836] = {
   0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
 };
 
-// Code page for KS X 1001 from KSX1001.TXT, with new characters U+FA2E
-// and U+FA2F from Unicode 6.1 (Source: Unihan_IRGSources.txt).
+// Code page for KS X 1001 from KSX1001.TXT, with two new symbols that were
+// added for KS X 1001:1998
+// 1) "euro sign" U+20AC
+// 2) "registered sign" 0x00AE
 const unsigned short CodePageKSX1001[8836] = {
   0x3000, 0x3001, 0x3002, 0x00B7, 0x2025, 0x2026, 0x00A8, 0x3003, 0x00AD,
   0x2015, 0x2225, 0xFF3C, 0x223C, 0x2018, 0x2019, 0x201C, 0x201D, 0x3014,
@@ -2147,7 +2149,7 @@ const unsigned short CodePageKSX1001[8836] = {
   0x25A7, 0x25A6, 0x25A9, 0x2668, 0x260F, 0x260E, 0x261C, 0x261E, 0x00B6,
   0x2020, 0x2021, 0x2195, 0x2197, 0x2199, 0x2196, 0x2198, 0x266D, 0x2669,
   0x266A, 0x266C, 0x327F, 0x321C, 0x2116, 0x33C7, 0x2122, 0x33C2, 0x33D8,
-  0x2121, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+  0x2121, 0x20AC, 0x00AE, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
   0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
   0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFF01,
   0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A,
@@ -2641,7 +2643,7 @@ const unsigned short CodePageKSX1001[8836] = {
   0xF918, 0x8AFE, 0xF919, 0xF91A, 0xF91B, 0xF91C, 0x6696, 0xF91D, 0x7156,
   0xF91E, 0xF91F, 0x96E3, 0xF920, 0x634F, 0x637A, 0x5357, 0xF921, 0x678F,
   0x6960, 0x6E73, 0xF922, 0x7537, 0xF923, 0xF924, 0xF925, 0x7D0D, 0xF926,
-  0xF927, 0x8872, 0x56CA, 0x5A18, 0xF928, 0xF929, 0xF92A, 0xF92B, 0xFA2E,
+  0xF927, 0x8872, 0x56CA, 0x5A18, 0xF928, 0xF929, 0xF92A, 0xF92B, 0xF92C,
   0x4E43, 0xF92D, 0x5167, 0x5948, 0x67F0, 0x8010, 0xF92E, 0x5973, 0x5E74,
   0x649A, 0x79CA, 0x5FF5, 0x606C, 0x62C8, 0x637B, 0x5BE7, 0x5BD7, 0x52AA,
   0xF92F, 0x5974, 0x5F29, 0x6012, 0xF930, 0xF931, 0xF932, 0x7459, 0xF933,
@@ -2867,7 +2869,7 @@ const unsigned short CodePageKSX1001[8836] = {
   0x7A4E, 0x7E93, 0xF9AF, 0xF9B0, 0x82F1, 0x8A60, 0x8FCE, 0xF9B1, 0x9348,
   0xF9B2, 0x9719, 0xF9B3, 0xF9B4, 0x4E42, 0x502A, 0xF9B5, 0x5208, 0x53E1,
   0x66F3, 0x6C6D, 0x6FCA, 0x730A, 0x777F, 0x7A62, 0x82AE, 0x85DD, 0x8602,
-  0xF9B6, 0x88D4, 0x8A63, 0x8B7D, 0x8C6B, 0xF9B7, 0x92B3, 0xFA2F, 0x9713,
+  0xF9B6, 0x88D4, 0x8A63, 0x8B7D, 0x8C6B, 0xF9B7, 0x92B3, 0xF9B8, 0x9713,
   0x9810, 0x4E94, 0x4F0D, 0x4FC9, 0x50B2, 0x5348, 0x543E, 0x5433, 0x55DA,
   0x5862, 0x58BA, 0x5967, 0x5A1B, 0x5BE4, 0x609F, 0xF9B9, 0x61CA, 0x6556,
   0x65FF, 0x6664, 0x68A7, 0x6C5A, 0x6FB3, 0x70CF, 0x71AC, 0x7352, 0x7B7D,
@@ -3116,6 +3118,11 @@ const unsigned short CodePageKSX1001[8836] = {
 // Code page for gb18030 two-byte codes from gb-18030-2005.ucm.
 // There were 24 codes with duplicate mappings, which are listed in
 // the PrivateToStandard table below.
+// This table is also used for GB2312 and GBK, to ensure compatibility.
+// However, note that GBK/GB18030 differs from GNU iconv's GB2312 table
+// for these two code points:
+// 1) here 'middle dot' U+00B7 -> iconv 'katakana middle dot' U+30FB
+// 2) here 'em dash' U+2014 -> iconv 'horizontal bar' U+2015
 const unsigned short CodePageGB18030[23940] = {
   0x4E02, 0x4E04, 0x4E05, 0x4E06, 0x4E0F, 0x4E12, 0x4E17, 0x4E1F, 0x4E20,
   0x4E21, 0x4E23, 0x4E26, 0x4E29, 0x4E2E, 0x4E2F, 0x4E31, 0x4E33, 0x4E35,
@@ -5835,18 +5842,19 @@ const unsigned short LinearGB18030[412] = {
   0x9961, 0xFF5F,  0x99E2, 0xFFE6
 };
 
-// Note: in the GB18030-2005 tables some codepoints in the private
-// range U+E000..U+F8FF migrated to standard unicode codepoints.
-// My understanding is that this allows more characters to be displayed
-// when the PUA is not mapped to GBK characters, but reduces the ability
-// of GB18030 to reversibly encode these private codepoints.
+// Note: GB18030 maps 24 characters to the private use area, though
+// as of Unicode 4.1 there are now standard unicode codes for these.
+// By moving these out of the PUA, it becomes possible to display
+// these characters on systems that support Unicode 4.1 and have the
+// necessary fonts.  However, it breaks the round-trip compatibility
+// between GB18030 and Unicode and therefore breaks GB18030-2005.
 const unsigned int PrivateToStandard[48] = {
-  0xE81E, 0x9FB4,  0xE826, 0x9FB5,  0xE82B, 0x9FB6,  0xE82C, 0x9FB7,
-  0xE832, 0x9FB8,  0xE843, 0x9FB9,  0xE854, 0x9FBA,  0xE864, 0x9FBB,
-  0xE78D, 0xFE10,  0xE78F, 0xFE11,  0xE78E, 0xFE12,  0xE790, 0xFE13,
+  0xE78D, 0xFE10,  0xE78E, 0xFE12,  0xE78F, 0xFE11,  0xE790, 0xFE13,
   0xE791, 0xFE14,  0xE792, 0xFE15,  0xE793, 0xFE16,  0xE794, 0xFE17,
   0xE795, 0xFE18,  0xE796, 0xFE19,  0xE816, 0x20087, 0xE817, 0x20089,
-  0xE818, 0x200CC, 0xE831, 0x215D7, 0xE83B, 0x2298F, 0xE855, 0x241FE
+  0xE818, 0x200CC, 0xE81E, 0x9FB4,  0xE826, 0x9FB5,  0xE82B, 0x9FB6,
+  0xE82C, 0x9FB7,  0xE831, 0x215D7, 0xE832, 0x9FB8,  0xE83B, 0x2298F,
+  0xE843, 0x9FB9,  0xE854, 0x9FBA,  0xE855, 0x241FE, 0xE864, 0x9FBB
 };
 
 // Convert a unicode code point to UTF-8
@@ -6681,17 +6689,17 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
     while (cp != ep)
       {
       int code = static_cast<unsigned char>(*cp++);
-      if ((code > 0x7F && code <= 0x9F) || code == '\\')
+      if (code <= 0x7F && code != '\\' && code != '~')
+        {
+        s.push_back(code);
+        }
+      else
         {
         if (code == '\\')
           {
           code = 0xA5; // yen symbol
           }
-        UnicodeToUTF8(code, &s);
-        }
-      else if (code > 0x9F || code == '~')
-        {
-        if (code == '~')
+        else if (code == '~')
           {
           code = 0x203E; // macron (overline)
           }
@@ -6699,16 +6707,48 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
           {
           code += 0xFEC0; // half-width katakana
           }
+        else if (cp != ep)
+          {
+          // if the byte not a valid JIS X 0201 code, then it is probably
+          // the first byte of a two-byte Shift-JIS sequence (vendors are
+          // required to convert Shift-JIS to ISO 2022 for use in DICOM,
+          // so this code is for compatibility with non-conformant files).
+          int x = code;
+          int y = static_cast<unsigned char>(*cp++);
+          code = (y == 0 ? 0 : 0xFFFD); // illegal character or null
+
+          if (y >= 0x40 && y <= 0xFC && y != 0x7F)
+            {
+            int a, b;
+            if (y < 0x9F)
+              {
+              a = 0;
+              b = y - (y < 0x7F ? 0x40 : 0x41);
+              }
+            else
+              {
+              a = 1;
+              b = y - 0x9F;
+              }
+
+            if (x >= 0x81 && x <= 0x9F)
+              {
+              a += (x - 0x81)*2;
+              code = CodePageJISX0208[a*94+b];
+              }
+            else if (x >= 0xE0 && x <= 0xEF)
+              {
+              a += (x - 0xC1)*2;
+              code = CodePageJISX0208[a*94+b];
+              }
+            }
+          }
         else
           {
           code = 0xFFFD; // illegal character
           }
         UnicodeToUTF8(code, &s);
         }
-      else
-        {
-        s.push_back(code);
-        }
       }
     }
   else if (this->Key == GB18030 || this->Key == GBK)
@@ -6769,6 +6809,12 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
                     break;
                     }
                   }
+                // this mapping was modified in GB18030-2005, after the linear
+                // table had already been defined, so it must be special-cased
+                if (code == 0x1E3F)
+                  {
+                  code = 0xE7C7;
+                  }
                 }
               }
             }
@@ -6796,12 +6842,12 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
                 }
               }
             }
-          // convert some private codes to new unicode standard codes
-          // (do this only for GB18030, for GBK stay within the BMP for
-          // maximum font compatibility between GBK and Unicode)
-          if (code >= 0xE000 && code <= 0xF8FF)
+          // convert some private codes to Unicode 4.1 standard codes in order
+          // to ensure they these characters can be displayed (though this is
+          // done at the cost of the one-to-one Unicode-to-GB18030 mapping)
+          size_t n = sizeof(PrivateToStandard)/sizeof(int);
+          if (code >= PrivateToStandard[0] && code <= PrivateToStandard[n-2])
             {
-            size_t n = sizeof(PrivateToStandard)/sizeof(int);
             for (size_t i = 0; i < n; i += 2)
               {
               if (code == PrivateToStandard[i])
@@ -6901,8 +6947,8 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
             }
           else if (code > 0x7F)
             {
-            // most likely Shift JIS codes, which are not permitted
-            // in DICOM or in iso-2022-jp
+            // possibly EUC-JP or Shift-JIS, neither of which should
+            // be used with ISO 2022 escape codes
             code = 0xFFFD;
             }
           UnicodeToUTF8(code, &s);
@@ -6922,8 +6968,12 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
               }
             // convert two bytes into unicode
             unsigned short a = code - 0xA1;
-            unsigned short b = static_cast<unsigned char>(text[i++]) - 0xA1;
-            code = CodePageKSX1001[a*94+b];
+            code = static_cast<unsigned char>(text[i++]);
+            if (code >= 0xA1 && code < 0xFF)
+              {
+              unsigned short b = code - 0xA1;
+              code = CodePageKSX1001[a*94+b];
+              }
             }
           UnicodeToUTF8(code, &s);
           }
@@ -6933,14 +6983,20 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
         // other multibyte conversions
         while (i < j)
           {
-          i++;
-          if (i == j)
+          unsigned short code = 0xFFFD;
+          if (text[i++] == '\0')
             {
-            break;
+            code = 0;
+            }
+          else if (i < j)
+            {
+            if (text[i++] == '\0')
+              {
+              code = 0;
+              }
             }
-          i++;
           // unrecognized multi-byte character
-          UnicodeToUTF8(0xFFFD, &s);
+          UnicodeToUTF8(code, &s);
           }
         }
 
@@ -6961,20 +7017,23 @@ std::string vtkDICOMCharacterSet::ConvertToUTF8(
           size_t le = strlen(escape);
           if (le > 0 && strncmp(&text[i], escape, le) == 0)
             {
-            charset = k;
-            if (charset == ISO_IR_13 && (oldcharset == ISO_2022_IR_87 ||
-                                         oldcharset == ISO_2022_IR_159))
+            if (k == ISO_IR_13 && (oldcharset == ISO_2022_IR_87 ||
+                                   oldcharset == ISO_2022_IR_159))
               {
               // The ISO_IR_13 charset goes in G1, so let's keep the
               // currently active kanji charset in G0.
               charset = oldcharset;
               }
-            else if (charset == ISO_IR_14)
+            else if (k == ISO_IR_14)
               {
               // The escape code for Japanese romaji (ISO_IR 14) switches
               // to JIS X 0201, which DICOM defines as "ISO 2022 IR 13".
               charset = ISO_IR_13;
               }
+            else
+              {
+              charset = k;
+              }
             i += le;
             break;
             }
@@ -7058,6 +7117,33 @@ size_t vtkDICOMCharacterSet::NextBackslash(
         }
       }
     }
+  else if (this->Key == ISO_IR_13)
+    {
+    // ensure backslash isn't second part of a Shift-JIS character
+    // that has been erroneously stored as ISO_IR 13
+    while (cp != ep && *cp != '\0')
+      {
+      unsigned char x = static_cast<unsigned char>(*cp);
+      if ((x >= 0x81 && x <= 0x9F) || (x >= 0xE0 && x <= 0xEF))
+        {
+        cp++;
+        if (cp != ep && static_cast<unsigned char>(*cp) >= 0x40 &&
+            static_cast<unsigned char>(*cp) <= 0xFC &&
+            static_cast<unsigned char>(*cp) != 0x7F)
+          {
+          cp++;
+          }
+        }
+      else if (*cp != '\\')
+        {
+        cp++;
+        }
+      else
+        {
+        break;
+        }
+      }
+    }
   else if ((this->Key & ISO_2022) != 0)
     {
     // ensure backslash isn't part of a G0 multi-byte code
diff --git a/Source/vtkDICOMCompiler.cxx b/Source/vtkDICOMCompiler.cxx
index b7d4e8a..4e86577 100644
--- a/Source/vtkDICOMCompiler.cxx
+++ b/Source/vtkDICOMCompiler.cxx
@@ -1591,16 +1591,22 @@ unsigned int vtkDICOMCompiler::ComputePixelDataSize()
 
 //----------------------------------------------------------------------------
 bool vtkDICOMCompiler::FlushBuffer(
-  unsigned char* &ucp, unsigned char* &)
+  unsigned char* &ucp, unsigned char* &ep)
 {
+  bool rval = true;
   const unsigned char *cp = ucp;
   unsigned char *dp = this->Buffer;
   ucp = dp;
-  size_t n = cp - dp;
+  ep = dp + this->ChunkSize;
 
-  size_t m = this->OutputFile->Write(dp, n);
+  if (cp)
+    {
+    size_t n = cp - dp;
+    size_t m = this->OutputFile->Write(dp, n);
+    rval = (n == m);
+    }
 
-  return (n == m);
+  return rval;
 }
 
 //----------------------------------------------------------------------------
diff --git a/Source/vtkDICOMCompiler.h b/Source/vtkDICOMCompiler.h
index 1be9486..f619f96 100644
--- a/Source/vtkDICOMCompiler.h
+++ b/Source/vtkDICOMCompiler.h
@@ -175,7 +175,7 @@ public:
    *  This will be called automatically whenever you provide a
    *  new meta data object for the compiler.  Note that new UIDs
    *  will not be generated if you have already provided them with
-   *  SetSOPInstanceUID() and SetSeriesUID().
+   *  SetSOPInstanceUID() and SetSeriesInstanceUID().
    */
   void GenerateSeriesUIDs();
   //@}
@@ -198,10 +198,14 @@ protected:
   //! Internal method for flushing the IO buffer.
   /*!
    *  This is an internal method that flushes the buffer to the file.
-   *  The pointer cp markes the current position in the buffer, and
-   *  ep marks the end of the buffer.  By checking ep-cp, subroutines
-   *  can check how much space is left in the buffer and call FlushBuffer
-   *  only when the buffer is nearly full.
+   *  If called with cp = 0, it will initialize cp to the beginning of
+   *  the write buffer, and ep to the end of the buffer, without writing
+   *  anything to the file.  The caller should then write to the buffer,
+   *  incrementing the pointer cp while doing so.  When cp approaches the
+   *  end of the buffer (which is stored in ep), FlushBuffer should be
+   *  called to flush the buffer contents to the file.  Every call will
+   *  reset cp to the beginning of the buffer and ep to the end of the
+   *  buffer.
    */
   virtual bool FlushBuffer(unsigned char* &cp, unsigned char* &ep);
 
diff --git a/Source/vtkDICOMDirectory.cxx b/Source/vtkDICOMDirectory.cxx
index 27e13e0..2585e50 100644
--- a/Source/vtkDICOMDirectory.cxx
+++ b/Source/vtkDICOMDirectory.cxx
@@ -1754,8 +1754,28 @@ void vtkDICOMDirectory::ProcessDirectoryFile(
               {
               path.PushBack(fileID.GetString(k));
               }
-            fileNames->InsertNextValue(path.AsString());
+            vtkIdType ki = fileNames->InsertNextValue(path.AsString());
             imageRecords.push_back(&items[j]);
+            // sort the files by instance number, they will almost always
+            // already be in order so we use a simple algorithm
+            int inst = items[j].GetAttributeValue(DC::InstanceNumber).AsInt();
+            while (ki > 0)
+              {
+              const vtkDICOMItem *prev = imageRecords[--ki];
+              int inst2 = prev->GetAttributeValue(DC::InstanceNumber).AsInt();
+              if (inst < inst2)
+                {
+                std::string s = fileNames->GetValue(ki + 1);
+                fileNames->SetValue(ki + 1, fileNames->GetValue(ki));
+                fileNames->SetValue(ki, s);
+                std::swap(imageRecords[ki], imageRecords[ki + 1]);
+                }
+              else
+                {
+                // sorting is finished!
+                break;
+                }
+              }
             }
           }
         }
diff --git a/Source/vtkDICOMDirectory.h b/Source/vtkDICOMDirectory.h
index c381dda..b237da2 100644
--- a/Source/vtkDICOMDirectory.h
+++ b/Source/vtkDICOMDirectory.h
@@ -191,7 +191,7 @@ public:
   //@}
 
   //@{
-  //! If On (the default), symbolic links will not be followed.
+  //! If On (the default), symbolic links will be followed.
   vtkSetMacro(FollowSymlinks, int);
   vtkBooleanMacro(FollowSymlinks, int);
   int GetFollowSymlinks() { return this->FollowSymlinks; }
diff --git a/Source/vtkDICOMFile.cxx b/Source/vtkDICOMFile.cxx
index b31e07d..3618733 100644
--- a/Source/vtkDICOMFile.cxx
+++ b/Source/vtkDICOMFile.cxx
@@ -88,7 +88,8 @@ vtkDICOMFile::vtkDICOMFile(const char *filename, Mode mode)
   this->Error = 0;
   this->Eof = false;
 
-  wchar_t *wideFilename = vtkDICOMFilePath::ConvertToWideChar(filename);
+  vtkDICOMFilePath fpath(filename);
+  const wchar_t *wideFilename = fpath.Wide();
   if (wideFilename)
     {
     if (mode == In)
@@ -139,7 +140,6 @@ vtkDICOMFile::vtkDICOMFile(const char *filename, Mode mode)
       }
     }
 
-  delete [] wideFilename;
 #else
   this->Handle = 0;
   this->Error = 0;
@@ -382,7 +382,8 @@ int vtkDICOMFile::Access(const char *filename, Mode mode)
 {
 #ifdef _WIN32
   int errorCode = UnknownError;
-  wchar_t *wideFilename = vtkDICOMFilePath::ConvertToWideChar(filename);
+  vtkDICOMFilePath fpath(filename);
+  const wchar_t *wideFilename = fpath.Wide();
   if (wideFilename)
     {
     errorCode = 0;
@@ -416,7 +417,6 @@ int vtkDICOMFile::Access(const char *filename, Mode mode)
       {
       errorCode = FileIsDirectory;
       }
-    delete [] wideFilename;
     }
   return errorCode;
 #else
@@ -456,7 +456,8 @@ int vtkDICOMFile::Remove(const char *filename)
 {
 #if defined(VTK_DICOM_WIN32_IO)
   int errorCode = 0;
-  wchar_t *wideFilename = vtkDICOMFilePath::ConvertToWideChar(filename);
+  vtkDICOMFilePath fpath(filename);
+  const wchar_t *wideFilename = fpath.Wide();
   if (wideFilename)
     {
     if (!DeleteFileW(wideFilename))
@@ -477,7 +478,6 @@ int vtkDICOMFile::Remove(const char *filename)
         errorCode = UnknownError;
         }
       }
-    delete [] wideFilename;
     }
   return errorCode;
 #else
@@ -511,16 +511,16 @@ bool vtkDICOMFile::SameFile(const char *file1, const char *file2)
 
   bool result = false;
 #ifdef _WIN32
-  wchar_t *widepath = vtkDICOMFilePath::ConvertToWideChar(file1);
+  vtkDICOMFilePath fpath1(file1);
+  const wchar_t *widepath = fpath1.Wide();
   HANDLE h1 = CreateFileW(widepath,
     GENERIC_READ, FILE_SHARE_READ , NULL, OPEN_EXISTING,
     FILE_FLAG_BACKUP_SEMANTICS, NULL);
-  delete [] widepath;
-  widepath = vtkDICOMFilePath::ConvertToWideChar(file2);
+  vtkDICOMFilePath fpath2(file2);
+  widepath = fpath2.Wide();
   HANDLE h2 = CreateFileW(widepath,
     GENERIC_READ, FILE_SHARE_READ , NULL, OPEN_EXISTING,
     FILE_FLAG_BACKUP_SEMANTICS, NULL);
-  delete [] widepath;
   if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE)
     {
     BY_HANDLE_FILE_INFORMATION buf;
diff --git a/Source/vtkDICOMFileDirectory.cxx b/Source/vtkDICOMFileDirectory.cxx
index 7993743..c8939cf 100644
--- a/Source/vtkDICOMFileDirectory.cxx
+++ b/Source/vtkDICOMFileDirectory.cxx
@@ -56,8 +56,7 @@ vtkDICOMFileDirectory::vtkDICOMFileDirectory(const char *dirname)
 #ifdef _WIN32
   vtkDICOMFilePath path(dirname);
   path.PushBack("*");
-  wchar_t *widename =
-    vtkDICOMFilePath::ConvertToWideChar(path.AsString().c_str());
+  const wchar_t *widename = path.Wide();
   if (widename == 0)
     {
     this->Error = UnknownError;
@@ -77,8 +76,13 @@ vtkDICOMFileDirectory::vtkDICOMFileDirectory(const char *dirname)
       }
     else
       {
+      // each utf-16 wchar converts to three or fewer utf-8 bytes
+      int n = MAX_PATH*3;
+      char name[MAX_PATH*3];
       do
         {
+        WideCharToMultiByte(
+          CP_UTF8, 0, fileData.cFileName, -1, name, n, 0, 0);
         unsigned int flags = 0;
         if ((fileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 &&
             fileData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)
@@ -89,9 +93,7 @@ vtkDICOMFileDirectory::vtkDICOMFileDirectory(const char *dirname)
           {
           flags |= TypeDirectory;
           }
-        char *name = vtkDICOMFilePath::ConvertToMultiByte(fileData.cFileName);
         this->AddEntry(name, flags, (TypeSymlink | TypeDirectory));
-        free(name);
         }
       while (FindNextFileW(h, &fileData));
       code = GetLastError();
@@ -270,9 +272,10 @@ int vtkDICOMFileDirectory::Create(const char *name)
 
   while (dirsToCreate.size() > 0 && result == 0)
     {
-    const char *dirname = dirsToCreate.back().c_str();
+    const std::string& dirname = dirsToCreate.back();
 #ifdef _WIN32
-    wchar_t *widename = vtkDICOMFilePath::ConvertToWideChar(dirname);
+    vtkDICOMFilePath dirpath(dirname);
+    const wchar_t *widename = dirpath.Wide();
     if (widename == 0)
       {
       result = UnknownError;
@@ -298,9 +301,8 @@ int vtkDICOMFileDirectory::Create(const char *name)
         result = UnknownError;
         }
       }
-    delete [] widename;
 #else
-    if (mkdir(dirname, 00777) != 0)
+    if (mkdir(dirname.c_str(), 00777) != 0)
       {
       int e = errno;
       if (e == EACCES || e == EPERM)
diff --git a/Source/vtkDICOMFilePath.cxx b/Source/vtkDICOMFilePath.cxx
index 43d3ae3..97bdb9f 100644
--- a/Source/vtkDICOMFilePath.cxx
+++ b/Source/vtkDICOMFilePath.cxx
@@ -38,11 +38,46 @@ vtkDICOMFilePath::vtkDICOMFilePath(const std::string& path)
       break;
       }
     }
+  this->WidePath = 0;
+  this->LocalPath = 0;
 #endif
   StripTrailingSlash(&this->Path);
 }
 
 //----------------------------------------------------------------------------
+#ifdef _WIN32
+vtkDICOMFilePath::vtkDICOMFilePath(const std::wstring& path)
+{
+  char *filename = ConvertToUTF8(path.c_str());
+  this->Path = filename;
+  this->Separator = '/';
+  delete [] filename;
+
+  size_t l = path.length();
+  for (size_t i = 0; i < l; i++)
+    {
+    if (IsSeparator(path[i]))
+      {
+      this->Separator = path[i];
+      break;
+      }
+    }
+  this->WidePath = 0;
+  this->LocalPath = 0;
+  StripTrailingSlash(&this->Path);
+}
+#endif
+
+//----------------------------------------------------------------------------
+vtkDICOMFilePath::~vtkDICOMFilePath()
+{
+#ifdef _WIN32
+  delete [] this->WidePath;
+  delete [] this->LocalPath;
+#endif
+}
+
+//----------------------------------------------------------------------------
 std::string vtkDICOMFilePath::Join(const std::string& second) const
 {
 #ifdef _WIN32
@@ -337,7 +372,6 @@ bool vtkDICOMFilePath::IsSymlink() const
     {
     WIN32_FIND_DATAW buf;
     HANDLE h = FindFirstFileW(widepath, &buf);
-    delete [] widepath;
     if (h != INVALID_HANDLE_VALUE)
       {
       CloseHandle(h);
@@ -348,6 +382,7 @@ bool vtkDICOMFilePath::IsSymlink() const
         }
       }
     }
+  delete [] widepath;
 #else
   struct stat fs;
   if (lstat(this->Path.c_str(), &fs) == 0 && S_ISLNK(fs.st_mode))
@@ -404,7 +439,7 @@ std::string vtkDICOMFilePath::GetRealPath() const
 
   if (n != 0)
     {
-    char *path = ConvertToMultiByte(widepath);
+    char *path = ConvertToUTF8(widepath);
     if (widepath != buffer)
       {
       delete [] widepath;
@@ -668,6 +703,30 @@ size_t vtkDICOMFilePath::RootLength(const std::string& path)
 
 //----------------------------------------------------------------------------
 #ifdef _WIN32
+const wchar_t *vtkDICOMFilePath::Wide()
+{
+  delete [] this->WidePath;
+  this->WidePath = ConvertToWideChar(this->Path.c_str());
+  return this->WidePath;
+}
+#endif
+
+//----------------------------------------------------------------------------
+#ifdef _WIN32
+const char *vtkDICOMFilePath::Local()
+{
+  delete [] this->LocalPath;
+  this->LocalPath = 0;
+  if (this->Wide())
+    {
+    this->LocalPath = ConvertToLocal(this->WidePath);
+    }
+  return this->LocalPath;
+}
+#endif
+
+//----------------------------------------------------------------------------
+#ifdef _WIN32
 bool vtkDICOMFilePath::HasExtendedPrefix(const std::string& path)
 {
   // extended prefixes are '\\?\' and '\\.\'
@@ -728,7 +787,7 @@ wchar_t *vtkDICOMFilePath::ConvertToWideChar(const char *filename)
 
 //----------------------------------------------------------------------------
 #ifdef _WIN32
-char *vtkDICOMFilePath::ConvertToMultiByte(const wchar_t *wideFilename)
+char *vtkDICOMFilePath::ConvertToUTF8(const wchar_t *wideFilename)
 {
   char *filename = 0;
   int n = WideCharToMultiByte(
@@ -747,3 +806,25 @@ char *vtkDICOMFilePath::ConvertToMultiByte(const wchar_t *wideFilename)
   return filename;
 }
 #endif
+
+//----------------------------------------------------------------------------
+#ifdef _WIN32
+char *vtkDICOMFilePath::ConvertToLocal(const wchar_t *wideFilename)
+{
+  char *filename = 0;
+  int n = WideCharToMultiByte(
+    CP_ACP, 0, wideFilename, -1, NULL, 0, 0, 0);
+  if (n > 0)
+    {
+    filename = new char[n];
+    n = WideCharToMultiByte(
+      CP_ACP, 0, wideFilename, -1, filename, n, 0, 0);
+    if (n == 0)
+      {
+      delete [] filename;
+      filename = 0;
+      }
+    }
+  return filename;
+}
+#endif
diff --git a/Source/vtkDICOMFilePath.h b/Source/vtkDICOMFilePath.h
index ea03e30..e121e4d 100644
--- a/Source/vtkDICOMFilePath.h
+++ b/Source/vtkDICOMFilePath.h
@@ -31,8 +31,16 @@ public:
    */
   vtkDICOMFilePath(const std::string& path);
 
+#ifdef _WIN32
+  //! Create a new path from a wide string.
+  /*!
+   *  This is to support unicode paths on Windows.
+   */
+  vtkDICOMFilePath(const std::wstring& path);
+#endif
+
   //! Destructor.
-  ~vtkDICOMFilePath() {}
+  ~vtkDICOMFilePath();
   //@}
 
   //@{
@@ -93,9 +101,26 @@ public:
   std::string GetRealPath() const;
   //@}
 
+#ifdef _WIN32
+  //@{
+  //! Convert the path to a wchar_t pointer for Windows methods.
+  /*!
+   *  Call this method if the path is going to be passed to a Windows
+   *  method that expects a unicode string.
+   */
+  const wchar_t *Wide();
+
+  //! Convert the path to a local 8-bit string for Windows methods.
+  /*!
+   *  Call this method if the path is going to be passed to a Windows
+   *  method that expects an 8-bit string with the local encoding.
+   */
+  const char *Local();
+  //@}
+
+#endif
+
 private:
-  friend class vtkDICOMFile;
-  friend class vtkDICOMFileDirectory;
 
   //! Check if the given character is a separator.
   static bool IsSeparator(char c) {
@@ -132,12 +157,19 @@ private:
   //! Convert to WideChar. Returns NULL or new string (free with delete []).
   static wchar_t *ConvertToWideChar(const char *filename);
 
-  //! Convert to a string. Returns NULL or new string (free with delete []).
-  static char *ConvertToMultiByte(const wchar_t *filename);
+  //! Convert to utf8. Returns NULL or new string (free with delete []).
+  static char *ConvertToUTF8(const wchar_t *filename);
+
+  //! Convert to local 8-bit. Returns NULL or new string (free with delete []).
+  static char *ConvertToLocal(const wchar_t *filename);
 #endif
 
   std::string Path;
   char Separator;
+#ifdef _WIN32
+  wchar_t *WidePath;
+  char *LocalPath;
+#endif
 };
 
 #endif /* vtkDICOMFilePath_h */
diff --git a/Source/vtkDICOMImageCodec.h b/Source/vtkDICOMImageCodec.h
index 040b61b..ed433e4 100644
--- a/Source/vtkDICOMImageCodec.h
+++ b/Source/vtkDICOMImageCodec.h
@@ -118,7 +118,7 @@ public:
 
   //! Encode a compressed image, and return an allocated destination buffer.
   /*!
-   *  The caller has the responsibility of calling "free" on the returned
+   *  The caller has the responsibility of calling "delete []" on the returned
    *  destination buffer.
    */
   int Encode(const ImageFormat& image,
diff --git a/Source/vtkDICOMMetaDataAdapter.cxx b/Source/vtkDICOMMetaDataAdapter.cxx
index 21158fe..3db21f8 100644
--- a/Source/vtkDICOMMetaDataAdapter.cxx
+++ b/Source/vtkDICOMMetaDataAdapter.cxx
@@ -20,11 +20,26 @@
 //----------------------------------------------------------------------------
 vtkDICOMMetaDataAdapter::vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta)
 {
+  this->ConstructionHelper(meta, -1);
+}
+
+//----------------------------------------------------------------------------
+vtkDICOMMetaDataAdapter::vtkDICOMMetaDataAdapter(
+  vtkDICOMMetaData *meta, int i)
+{
+  this->ConstructionHelper(meta, i);
+}
+
+//----------------------------------------------------------------------------
+void vtkDICOMMetaDataAdapter::ConstructionHelper(
+  vtkDICOMMetaData *meta, int i)
+{
   this->Meta = meta;
   this->PerFrame = 0;
   this->Shared = 0;
-  this->NumberOfInstances = 0;
   this->NullValue = 0;
+  this->NumberOfInstances = 0;
+  this->MetaInstance = (i >= 0 ? i : 0);
 
   if (meta)
     {
@@ -35,7 +50,7 @@ vtkDICOMMetaDataAdapter::vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta)
       {
       if (iter->IsPerInstance())
         {
-        this->PerFrame = &iter->GetValue(0);
+        this->PerFrame = &iter->GetValue(this->MetaInstance);
         }
       else
         {
@@ -47,7 +62,7 @@ vtkDICOMMetaDataAdapter::vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta)
       {
       if (iter->IsPerInstance())
         {
-        this->Shared = &iter->GetValue(0);
+        this->Shared = &iter->GetValue(this->MetaInstance);
         }
       else
         {
@@ -59,19 +74,20 @@ vtkDICOMMetaDataAdapter::vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta)
   if (this->Shared && this->Shared->IsValid() &&
       this->PerFrame && this->PerFrame->IsValid())
     {
-    this->NumberOfInstances =
-      meta->GetAttributeValue(DC::NumberOfFrames).AsInt();
+    this->NumberOfInstances = meta->GetAttributeValue(
+      this->MetaInstance, DC::NumberOfFrames).AsInt();
     // an invalid value to return when asked for NumberOfFrames
     this->NullValue = new vtkDICOMValue();
     }
   else if (meta)
     {
-    this->NumberOfInstances = meta->GetNumberOfInstances();
+    this->NumberOfInstances = (i < 0 ? meta->GetNumberOfInstances() : 1);
     this->Shared = 0;
     this->PerFrame = 0;
     }
 }
 
+//----------------------------------------------------------------------------
 // Destructor
 vtkDICOMMetaDataAdapter::~vtkDICOMMetaDataAdapter()
 {
@@ -153,7 +169,7 @@ const vtkDICOMValue &vtkDICOMMetaDataAdapter::GetAttributeValue(
       }
 
     // if it wasn't in a PerFrame or Shared functional group
-    const vtkDICOMValue& v = meta->GetAttributeValue(0, tag);
+    const vtkDICOMValue& v = meta->GetAttributeValue(this->MetaInstance, tag);
     if (privateValue && !v.IsValid())
       {
       // attributes found in private parts of the PerFrame or Shared are
@@ -164,7 +180,7 @@ const vtkDICOMValue &vtkDICOMMetaDataAdapter::GetAttributeValue(
     }
 
   // if no per-frame data, use file instance
-  return meta->GetAttributeValue(idx, tag);
+  return meta->GetAttributeValue(idx + this->MetaInstance, tag);
 }
 
 //----------------------------------------------------------------------------
@@ -267,4 +283,3 @@ vtkDICOMTag vtkDICOMMetaDataAdapter::ResolvePrivateTag(
   // if no per-frame data, use file instance
   return meta->ResolvePrivateTag(ptag, creator);
 }
-
diff --git a/Source/vtkDICOMMetaDataAdapter.h b/Source/vtkDICOMMetaDataAdapter.h
index db46ba0..4f3e1e2 100644
--- a/Source/vtkDICOMMetaDataAdapter.h
+++ b/Source/vtkDICOMMetaDataAdapter.h
@@ -34,8 +34,21 @@ class VTKDICOM_EXPORT vtkDICOMMetaDataAdapter
 public:
   //@{
   //! Construct an adapter for the given meta data object.
+  /*!
+   *  If the provided meta-data is from an enhanced multi-frame data set,
+   *  then the adapter will make it look like a series of data sets.  If
+   *  the provided meta-data is from a series of non-enhanced data sets,
+   *  the adapter will act as a simple pass-through.
+   */
   vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta);
 
+  //! Construct an adapter for one DICOM object instance.
+  /*!
+   *  If instance i of the provided meta-data is an enhanced multi-frame
+   *  data set, make it look like a series.
+   */
+  vtkDICOMMetaDataAdapter(vtkDICOMMetaData *meta, int i);
+
   //! Destructor release the reference to the meta data.
   ~vtkDICOMMetaDataAdapter();
   //@}
@@ -89,6 +102,10 @@ public:
   vtkDICOMMetaDataAdapter* operator->() { return this; }
   //@}
 
+protected:
+  //! Helper function for the constructors.  Set all members.
+  void ConstructionHelper(vtkDICOMMetaData *meta, int i);
+
 private:
 
   vtkDICOMMetaData *Meta;
@@ -96,6 +113,7 @@ private:
   const vtkDICOMValue *Shared;
   vtkDICOMValue *NullValue;
   int NumberOfInstances;
+  int MetaInstance;
 };
 
 #endif /* vtkDICOMMetaDataAdapter_h */
diff --git a/Source/vtkDICOMReader.cxx b/Source/vtkDICOMReader.cxx
index 118b900..047c82d 100644
--- a/Source/vtkDICOMReader.cxx
+++ b/Source/vtkDICOMReader.cxx
@@ -1708,10 +1708,13 @@ void vtkDICOMReader::UpdateMedicalImageProperties()
   vtkMatrix4x4 *matrix = this->PatientMatrix;
   vtkMedicalImageProperties *properties = this->MedicalImageProperties;
 
-  properties->SetPatientName(
-    meta->GetAttributeValue(DC::PatientName).GetCharData());
-  properties->SetPatientID(
-    meta->GetAttributeValue(DC::PatientID).GetCharData());
+  const vtkDICOMValue *vptr;
+  vptr = &meta->GetAttributeValue(DC::PatientName);
+  properties->SetPatientName(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::PatientID);
+  properties->SetPatientID(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
   properties->SetPatientAge(
     meta->GetAttributeValue(DC::PatientAge).GetCharData());
   properties->SetPatientSex(
@@ -1734,24 +1737,32 @@ void vtkDICOMReader::UpdateMedicalImageProperties()
     meta->GetAttributeValue(DC::InstanceNumber).GetCharData());
   properties->SetSeriesNumber(
     meta->GetAttributeValue(DC::SeriesNumber).GetCharData());
-  properties->SetSeriesDescription(
-    meta->GetAttributeValue(DC::SeriesDescription).GetCharData());
-  properties->SetStudyID(
-    meta->GetAttributeValue(DC::StudyID).GetCharData());
-  properties->SetStudyDescription(
-    meta->GetAttributeValue(DC::StudyDescription).GetCharData());
+  vptr = &meta->GetAttributeValue(DC::SeriesDescription);
+  properties->SetSeriesDescription(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::StudyID);
+  properties->SetStudyID(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::StudyDescription);
+  properties->SetStudyDescription(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
   properties->SetModality(
     meta->GetAttributeValue(DC::Modality).GetCharData());
-  properties->SetManufacturer(
-    meta->GetAttributeValue(DC::Manufacturer).GetCharData());
-  properties->SetManufacturerModelName(
-    meta->GetAttributeValue(DC::ManufacturerModelName).GetCharData());
-  properties->SetStationName(
-    meta->GetAttributeValue(DC::StationName).GetCharData());
-  properties->SetInstitutionName(
-    meta->GetAttributeValue(DC::InstitutionName).GetCharData());
-  properties->SetConvolutionKernel(
-    meta->GetAttributeValue(DC::ConvolutionKernel).GetCharData());
+  vptr = &meta->GetAttributeValue(DC::Manufacturer);
+  properties->SetManufacturer(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::ManufacturerModelName);
+  properties->SetManufacturerModelName(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::StationName);
+  properties->SetStationName(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::InstitutionName);
+  properties->SetInstitutionName(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
+  vptr = &meta->GetAttributeValue(DC::ConvolutionKernel);
+  properties->SetConvolutionKernel(vptr->IsValid() ?
+    vptr->AsUTF8String().c_str() : NULL);
   properties->SetSliceThickness(
     meta->GetAttributeValue(DC::SliceThickness).GetCharData());
   properties->SetKVP(
diff --git a/Source/vtkNIFTIHeader.cxx b/Source/vtkNIFTIHeader.cxx
index f303b16..a94d781 100644
--- a/Source/vtkNIFTIHeader.cxx
+++ b/Source/vtkNIFTIHeader.cxx
@@ -188,7 +188,8 @@ void vtkNIFTIHeader::GetHeader(nifti_1_header *hdr)
     hdr->pixdim[i] = vtkNIFTINormalizeFloat(this->PixDim[i]);
     }
   hdr->vox_offset = static_cast<float>(this->VoxOffset);
-  strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name));
+  strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
+  hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
   hdr->scl_slope = vtkNIFTINormalizeFloat(this->SclSlope);
   hdr->scl_inter = vtkNIFTINormalizeFloat(this->SclInter);
   hdr->cal_min = vtkNIFTINormalizeFloat(this->CalMin);
@@ -200,8 +201,10 @@ void vtkNIFTIHeader::GetHeader(nifti_1_header *hdr)
   hdr->slice_end = this->SliceEnd;
   hdr->slice_code = this->SliceCode;
   hdr->xyzt_units = this->XYZTUnits;
-  strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip));
-  strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file));
+  strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
+  hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
+  strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
+  hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
   hdr->qform_code = static_cast<short>(this->QFormCode);
   hdr->sform_code = static_cast<short>(this->SFormCode);
   hdr->quatern_b = vtkNIFTINormalizeFloat(this->QuaternB);
@@ -289,8 +292,10 @@ void vtkNIFTIHeader::GetHeader(nifti_2_header *hdr)
   hdr->toffset = vtkNIFTINormalizeDouble(this->TOffset);
   hdr->slice_start = this->SliceStart;
   hdr->slice_end = this->SliceEnd;
-  strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip));
-  strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file));
+  strncpy(hdr->descrip, this->Descrip, sizeof(hdr->descrip) - 1);
+  hdr->descrip[sizeof(hdr->descrip) - 1] = '\0';
+  strncpy(hdr->aux_file, this->AuxFile, sizeof(hdr->aux_file) - 1);
+  hdr->aux_file[sizeof(hdr->aux_file) - 1] = '\0';
   hdr->qform_code = static_cast<short>(this->QFormCode);
   hdr->sform_code = static_cast<short>(this->SFormCode);
   hdr->quatern_b = vtkNIFTINormalizeDouble(this->QuaternB);
@@ -308,7 +313,8 @@ void vtkNIFTIHeader::GetHeader(nifti_2_header *hdr)
   hdr->slice_code = this->SliceCode;
   hdr->xyzt_units = this->XYZTUnits;
   hdr->intent_code = static_cast<short>(this->IntentCode);
-  strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name));
+  strncpy(hdr->intent_name, this->IntentName, sizeof(hdr->intent_name) - 1);
+  hdr->intent_name[sizeof(hdr->intent_name) - 1] = '\0';
   hdr->dim_info = static_cast<char>(this->DimInfo);
   memset(hdr->unused_str, '\0', 15);
 }
diff --git a/Source/vtkNIFTIReader.cxx b/Source/vtkNIFTIReader.cxx
index f00a976..24634fe 100644
--- a/Source/vtkNIFTIReader.cxx
+++ b/Source/vtkNIFTIReader.cxx
@@ -29,11 +29,11 @@
 #include "vtkStringArray.h"
 #include "vtkVersion.h"
 
-#ifdef VTK_DICOM_EXPORT
-#include "vtkDICOMFile.h"
-#else
-#include "vtksys/SystemTools.hxx"
+#ifdef _WIN32
+// To allow use of wchar_t paths on Windows
+#include "vtkDICOMFilePath.h"
 #endif
+#include "vtkDICOMFile.h"
 
 // Header for NIFTI
 #include "vtkNIFTIHeader.h"
@@ -51,6 +51,17 @@
 #include <string.h>
 #include <string>
 
+#ifdef _WIN32
+// To allow use of wchar_t paths on Windows
+#include "vtkDICOMFilePath.h"
+#if VTK_MAJOR_VERSION >= 7
+#ifdef gzopen
+#undef gzopen
+#endif
+#define gzopen gzopen_w
+#endif
+#endif
+
 vtkStandardNewMacro(vtkNIFTIReader);
 
 //----------------------------------------------------------------------------
@@ -300,18 +311,11 @@ char *vtkNIFTIReader::ReplaceExtension(
     // existence of file
     for (int i = 0; i < 2; i++)
       {
-#ifdef VTK_DICOM_EXPORT
-      int code = vtkDICOMFile::Access(newname);
+      int code = vtkDICOMFile::Access(newname, vtkDICOMFile::In);
       if (code != vtkDICOMFile::FileNotFound)
         {
         return newname;
         }
-#else
-      if (vtksys::SystemTools::FileExists(newname))
-        {
-        return newname;
-        }
-#endif
       if (i == 0)
         {
         if (m < n)
@@ -397,8 +401,22 @@ int vtkNIFTIReader::CanReadFile(const char *filename)
     return 0;
     }
 
+#if _WIN32 
+  vtkDICOMFilePath fp(hdrname);
+#if VTK_MAJOR_VERSION < 7
+  // convert to the local character set
+  const char *uhdrname = fp.Local();
+#else
+  // use wide character
+  const wchar_t *uhdrname = fp.Wide();
+  fprintf(stderr, "uhdrname\n");
+#endif
+#else
+  const char *uhdrname = hdrname;
+#endif
+
   // try opening file
-  gzFile file = gzopen(hdrname, "rb");
+  gzFile file = gzopen(uhdrname, "rb");
 
   delete [] hdrname;
 
@@ -506,8 +524,25 @@ int vtkNIFTIReader::RequestInformation(
 
   vtkDebugMacro("Opening NIFTI file " << hdrname);
 
+#if _WIN32 
+  vtkDICOMFilePath fph(hdrname);
+#if VTK_MAJOR_VERSION < 7
+  // convert to the local character set
+  const char *uhdrname = fph.Local();
+#else
+  // use wide character
+  const wchar_t *uhdrname = fph.Wide();
+#endif
+#else
+  const char *uhdrname = hdrname;
+#endif
+
   // try opening file
-  gzFile file = gzopen(hdrname, "rb");
+  gzFile file = 0;
+  if (uhdrname)
+    {
+    file = gzopen(uhdrname, "rb");
+    }
 
   if (!file)
     {
@@ -1155,7 +1190,25 @@ int vtkNIFTIReader::RequestData(
   unsigned char *dataPtr =
     static_cast<unsigned char *>(data->GetScalarPointer());
 
-  gzFile file = gzopen(imgname, "rb");
+#if _WIN32 
+  vtkDICOMFilePath fpi(imgname);
+#if VTK_MAJOR_VERSION < 7
+  // convert to the local character set
+  const char *uimgname = fpi.Local();
+#else
+  // use wide character
+  const wchar_t *uimgname = fpi.Wide();
+  fprintf(stderr, "uhdrname\n");
+#endif
+#else
+  const char *uimgname = imgname;
+#endif
+
+  gzFile file = 0;
+  if (uimgname)
+    {
+    file = gzopen(uimgname, "rb");
+    }
 
   delete [] imgname;
 
diff --git a/Source/vtkNIFTIWriter.cxx b/Source/vtkNIFTIWriter.cxx
index 38ac64f..dc0c7ba 100644
--- a/Source/vtkNIFTIWriter.cxx
+++ b/Source/vtkNIFTIWriter.cxx
@@ -28,11 +28,8 @@
 #include "vtkCommand.h"
 #include "vtkVersion.h"
 
-#ifdef VTK_DICOM_EXPORT
+// For removing file if write failed
 #include "vtkDICOMFile.h"
-#else
-#include "vtksys/SystemTools.hxx"
-#endif
 
 // Header for NIFTI
 #include "vtkNIFTIHeader.h"
@@ -51,6 +48,23 @@
 #include <float.h>
 #include <math.h>
 
+#ifdef _WIN32
+// To allow use of wchar_t paths on Windows
+#include "vtkDICOMFilePath.h"
+#if VTK_MAJOR_VERSION >= 7
+#ifdef gzopen
+#undef gzopen
+#endif
+#define gzopen gzopen_w
+#define fopen _wfopen
+#define NIFTI_FILE_MODE L"wb"
+#else
+#define NIFTI_FILE_MODE "wb"
+#endif
+#else
+#define NIFTI_FILE_MODE "wb"
+#endif
+
 vtkStandardNewMacro(vtkNIFTIWriter);
 vtkCxxSetObjectMacro(vtkNIFTIWriter,QFormMatrix,vtkMatrix4x4);
 vtkCxxSetObjectMacro(vtkNIFTIWriter,SFormMatrix,vtkMatrix4x4);
@@ -499,7 +513,8 @@ int vtkNIFTIWriter::GenerateHeader(vtkInformation *info, bool singleFile)
   // set the description
   if (this->Description)
     {
-    strncpy(hdr.descrip, this->Description, 80);
+    strncpy(hdr.descrip, this->Description, sizeof(hdr.descrip) - 1);
+    hdr.descrip[sizeof(hdr.descrip) - 1] = '\0';
     }
 
   // qfac dictates the slice ordering in the file
@@ -676,21 +691,40 @@ int vtkNIFTIWriter::RequestData(
       }
     }
 
+#if _WIN32 
+  vtkDICOMFilePath fph(hdrname);
+  vtkDICOMFilePath fpi(imgname);
+#if VTK_MAJOR_VERSION < 7
+  // convert to the local character set
+  const char *uhdrname = fph.Local();
+  const char *uimgname = fpi.Local();
+#else
+  // use wide character
+  const wchar_t *uhdrname = fph.Wide();
+  const wchar_t *uimgname = fpi.Wide();
+#endif
+#else
+  const char *uhdrname = hdrname;
+  const char *uimgname = imgname;
+#endif
+
   // try opening file
   gzFile file = 0;
   FILE *ufile = 0;
-  if (isCompressed)
-    {
-    file = gzopen(hdrname, "wb");
-    }
-  else
+  if (uhdrname && uimgname)
     {
-    ufile = fopen(hdrname, "wb");
+    if (isCompressed)
+      {
+      file = gzopen(uhdrname, "wb");
+      }
+    else
+      {
+      ufile = fopen(uhdrname, NIFTI_FILE_MODE);
+      }
     }
 
   if (!file && !ufile)
     {
-    vtkErrorMacro("Cannot open file " << hdrname);
     delete [] hdrname;
     delete [] imgname;
     this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
@@ -745,12 +779,12 @@ int vtkNIFTIWriter::RequestData(
     if (isCompressed)
       {
       gzclose(file);
-      file = gzopen(imgname, "wb");
+      file = gzopen(uimgname, "wb");
       }
     else
       {
       fclose(ufile);
-      ufile = fopen(imgname, "wb");
+      ufile = fopen(uimgname, NIFTI_FILE_MODE);
       }
     }
 
@@ -940,14 +974,10 @@ int vtkNIFTIWriter::RequestData(
     {
     // erase the file, rather than leave a corrupt file on disk
     vtkErrorMacro("Out of disk space, removing incomplete file " << imgname);
-#ifdef VTK_DICOM_EXPORT
     vtkDICOMFile::Remove(imgname);
-#else
-    vtksys::SystemTools::RemoveFile(imgname);
-#endif
     if (!singleFile)
       {
-      vtksys::SystemTools::RemoveFile(hdrname);
+      vtkDICOMFile::Remove(hdrname);
       }
     }
 
diff --git a/Source/vtkScancoCTReader.cxx b/Source/vtkScancoCTReader.cxx
index 7fc9e37..561d2d9 100644
--- a/Source/vtkScancoCTReader.cxx
+++ b/Source/vtkScancoCTReader.cxx
@@ -25,6 +25,11 @@
 #include "vtkStreamingDemandDrivenPipeline.h"
 #include "vtkVersion.h"
 
+#ifdef _WIN32
+// To allow use of wchar_t paths on Windows
+#include "vtkDICOMFilePath.h"
+#endif
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
@@ -855,7 +860,14 @@ int vtkScancoCTReader::RequestInformation(
 
   vtkDebugMacro("Opening ISQ/AIM file " << filename);
 
-  ifstream infile(filename, ios::in | ios::binary);
+#ifdef _WIN32
+  vtkDICOMFilePath fp(filename);
+  const wchar_t *ufilename = fp.Wide();
+#else
+  const char *ufilename = filename;
+#endif
+
+  ifstream infile(ufilename, ios::in | ios::binary);
   if (!infile.good())
     {
     vtkErrorMacro("Cannot open file " << filename);

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



More information about the debian-med-commit mailing list