Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkIOUtil.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkIOUtil.h"
18 
19 #include <mitkCoreObjectFactory.h>
20 #include <mitkCoreServices.h>
21 #include <mitkExceptionMacro.h>
22 #include <mitkFileReaderRegistry.h>
23 #include <mitkFileWriterRegistry.h>
24 #include <mitkIDataNodeReader.h>
25 #include <mitkIMimeTypeProvider.h>
26 #include <mitkProgressBar.h>
28 #include <usGetModuleContext.h>
29 #include <usLDAPProp.h>
30 #include <usModuleContext.h>
31 #include <usModuleResource.h>
32 #include <usModuleResourceStream.h>
33 
34 // ITK
35 #include <itksys/SystemTools.hxx>
36 
37 // VTK
38 #include <vtkPolyData.h>
39 #include <vtkSmartPointer.h>
40 #include <vtkTriangleFilter.h>
41 
42 #include <cerrno>
43 #include <cstdlib>
44 
45 static std::string GetLastErrorStr()
46 {
47 #ifdef US_PLATFORM_POSIX
48  return std::string(strerror(errno));
49 #else
50  // Retrieve the system error message for the last-error code
51  LPVOID lpMsgBuf;
52  DWORD dw = GetLastError();
53 
54  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
55  NULL,
56  dw,
57  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
58  (LPTSTR)&lpMsgBuf,
59  0,
60  NULL);
61 
62  std::string errMsg((LPCTSTR)lpMsgBuf);
63 
64  LocalFree(lpMsgBuf);
65 
66  return errMsg;
67 #endif
68 }
69 
70 #ifdef US_PLATFORM_WINDOWS
71 
72 #include <direct.h>
73 #include <io.h>
74 
75 // make the posix flags point to the obsolte bsd types on windows
76 #define S_IRUSR S_IREAD
77 #define S_IWUSR S_IWRITE
78 
79 #else
80 
81 #include <sys/time.h>
82 #include <sys/types.h>
83 #include <unistd.h>
84 
85 #endif
86 
87 #include <fcntl.h>
88 #include <sys/stat.h>
89 
90 static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
91 
92 // A cross-platform version of the mkstemps function
93 static int mkstemps_compat(char *tmpl, int suffixlen)
94 {
95  static unsigned long long value = 0;
96  int savedErrno = errno;
97 
98 // Lower bound on the number of temporary files to attempt to generate.
99 #define ATTEMPTS_MIN (62 * 62 * 62)
100 
101 /* The number of times to attempt to generate a temporary file. To
102  conform to POSIX, this must be no smaller than TMP_MAX. */
103 #if ATTEMPTS_MIN < TMP_MAX
104  const unsigned int attempts = TMP_MAX;
105 #else
106  const unsigned int attempts = ATTEMPTS_MIN;
107 #endif
108 
109  const int len = strlen(tmpl);
110  if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6))
111  {
112  errno = EINVAL;
113  return -1;
114  }
115 
116  /* This is where the Xs start. */
117  char *XXXXXX = &tmpl[len - 6 - suffixlen];
118 
119 /* Get some more or less random data. */
120 #ifdef US_PLATFORM_WINDOWS
121  {
122  SYSTEMTIME stNow;
123  FILETIME ftNow;
124 
125  // get system time
126  GetSystemTime(&stNow);
127  stNow.wMilliseconds = 500;
128  if (!SystemTimeToFileTime(&stNow, &ftNow))
129  {
130  errno = -1;
131  return -1;
132  }
133  unsigned long long randomTimeBits = ((static_cast<unsigned long long>(ftNow.dwHighDateTime) << 32) |
134  static_cast<unsigned long long>(ftNow.dwLowDateTime));
135  value = randomTimeBits ^ static_cast<unsigned long long>(GetCurrentThreadId());
136  }
137 #else
138  {
139  struct timeval tv;
140  gettimeofday(&tv, NULL);
141  unsigned long long randomTimeBits =
142  ((static_cast<unsigned long long>(tv.tv_usec) << 32) | static_cast<unsigned long long>(tv.tv_sec));
143  value = randomTimeBits ^ static_cast<unsigned long long>(getpid());
144  }
145 #endif
146 
147  for (unsigned int count = 0; count < attempts; value += 7777, ++count)
148  {
149  unsigned long long v = value;
150 
151  /* Fill in the random bits. */
152  XXXXXX[0] = validLetters[v % 62];
153  v /= 62;
154  XXXXXX[1] = validLetters[v % 62];
155  v /= 62;
156  XXXXXX[2] = validLetters[v % 62];
157  v /= 62;
158  XXXXXX[3] = validLetters[v % 62];
159  v /= 62;
160  XXXXXX[4] = validLetters[v % 62];
161  v /= 62;
162  XXXXXX[5] = validLetters[v % 62];
163 
164  int fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
165  if (fd >= 0)
166  {
167  errno = savedErrno;
168  return fd;
169  }
170  else if (errno != EEXIST)
171  {
172  return -1;
173  }
174  }
175 
176  /* We got out of the loop because we ran out of combinations to try. */
177  errno = EEXIST;
178  return -1;
179 }
180 
181 // A cross-platform version of the POSIX mkdtemp function
182 static char *mkdtemps_compat(char *tmpl, int suffixlen)
183 {
184  static unsigned long long value = 0;
185  int savedErrno = errno;
186 
187 // Lower bound on the number of temporary dirs to attempt to generate.
188 #define ATTEMPTS_MIN (62 * 62 * 62)
189 
190 /* The number of times to attempt to generate a temporary dir. To
191  conform to POSIX, this must be no smaller than TMP_MAX. */
192 #if ATTEMPTS_MIN < TMP_MAX
193  const unsigned int attempts = TMP_MAX;
194 #else
195  const unsigned int attempts = ATTEMPTS_MIN;
196 #endif
197 
198  const int len = strlen(tmpl);
199  if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6))
200  {
201  errno = EINVAL;
202  return NULL;
203  }
204 
205  /* This is where the Xs start. */
206  char *XXXXXX = &tmpl[len - 6 - suffixlen];
207 
208 /* Get some more or less random data. */
209 #ifdef US_PLATFORM_WINDOWS
210  {
211  SYSTEMTIME stNow;
212  FILETIME ftNow;
213 
214  // get system time
215  GetSystemTime(&stNow);
216  stNow.wMilliseconds = 500;
217  if (!SystemTimeToFileTime(&stNow, &ftNow))
218  {
219  errno = -1;
220  return NULL;
221  }
222  unsigned long long randomTimeBits = ((static_cast<unsigned long long>(ftNow.dwHighDateTime) << 32) |
223  static_cast<unsigned long long>(ftNow.dwLowDateTime));
224  value = randomTimeBits ^ static_cast<unsigned long long>(GetCurrentThreadId());
225  }
226 #else
227  {
228  struct timeval tv;
229  gettimeofday(&tv, NULL);
230  unsigned long long randomTimeBits =
231  ((static_cast<unsigned long long>(tv.tv_usec) << 32) | static_cast<unsigned long long>(tv.tv_sec));
232  value = randomTimeBits ^ static_cast<unsigned long long>(getpid());
233  }
234 #endif
235 
236  unsigned int count = 0;
237  for (; count < attempts; value += 7777, ++count)
238  {
239  unsigned long long v = value;
240 
241  /* Fill in the random bits. */
242  XXXXXX[0] = validLetters[v % 62];
243  v /= 62;
244  XXXXXX[1] = validLetters[v % 62];
245  v /= 62;
246  XXXXXX[2] = validLetters[v % 62];
247  v /= 62;
248  XXXXXX[3] = validLetters[v % 62];
249  v /= 62;
250  XXXXXX[4] = validLetters[v % 62];
251  v /= 62;
252  XXXXXX[5] = validLetters[v % 62];
253 
254 #ifdef US_PLATFORM_WINDOWS
255  int fd = _mkdir(tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC);
256 #else
257  int fd = mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
258 #endif
259  if (fd >= 0)
260  {
261  errno = savedErrno;
262  return tmpl;
263  }
264  else if (errno != EEXIST)
265  {
266  return NULL;
267  }
268  }
269 
270  /* We got out of the loop because we ran out of combinations to try. */
271  errno = EEXIST;
272  return NULL;
273 }
274 
275 //#endif
276 
277 //**************************************************************
278 // mitk::IOUtil method definitions
279 
280 namespace mitk
281 {
282  struct IOUtil::Impl
283  {
284  struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase
285  {
286  FixedReaderOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {}
287  virtual bool operator()(LoadInfo &loadInfo) override
288  {
289  IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader();
290  if (reader)
291  {
292  reader->SetOptions(m_Options);
293  }
294  return false;
295  }
296 
297  private:
298  const IFileReader::Options &m_Options;
299  };
300 
301  struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase
302  {
303  FixedWriterOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {}
304  virtual bool operator()(SaveInfo &saveInfo) override
305  {
306  IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter();
307  if (writer)
308  {
309  writer->SetOptions(m_Options);
310  }
311  return false;
312  }
313 
314  private:
315  const IFileWriter::Options &m_Options;
316  };
317 
318  static BaseData::Pointer LoadBaseDataFromFile(const std::string &path);
319 
320  static void SetDefaultDataNodeProperties(mitk::DataNode *node, const std::string &filePath = std::string());
321  };
322 
323 #ifdef US_PLATFORM_WINDOWS
324  std::string IOUtil::GetProgramPath()
325  {
326  char path[512];
327  std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\');
328  return std::string(path, index);
329  }
330 #elif defined(US_PLATFORM_APPLE)
331 #include <mach-o/dyld.h>
332  std::string IOUtil::GetProgramPath()
333  {
334  char path[512];
335  uint32_t size = sizeof(path);
336  if (_NSGetExecutablePath(path, &size) == 0)
337  {
338  std::size_t index = std::string(path).find_last_of('/');
339  std::string strPath = std::string(path, index);
340  // const char* execPath = strPath.c_str();
341  // mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false);
342  return strPath;
343  }
344  return std::string();
345  }
346 #else
347 #include <sstream>
348 #include <sys/types.h>
349 #include <unistd.h>
351  {
352  std::stringstream ss;
353  ss << "/proc/" << getpid() << "/exe";
354  char proc[512] = {0};
355  ssize_t ch = readlink(ss.str().c_str(), proc, 512);
356  if (ch == -1)
357  return std::string();
358  std::size_t index = std::string(proc).find_last_of('/');
359  return std::string(proc, index);
360  }
361 #endif
362 
364  {
365 #ifdef US_PLATFORM_WINDOWS
366  return '\\';
367 #else
368  return '/';
369 #endif
370  }
371 
372  std::string IOUtil::GetTempPath()
373  {
374  static std::string result;
375  if (result.empty())
376  {
377 #ifdef US_PLATFORM_WINDOWS
378  char tempPathTestBuffer[1];
379  DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer);
380  if (bufferLength == 0)
381  {
382  mitkThrow() << GetLastErrorStr();
383  }
384  std::vector<char> tempPath(bufferLength);
385  bufferLength = ::GetTempPath(bufferLength, &tempPath[0]);
386  if (bufferLength == 0)
387  {
388  mitkThrow() << GetLastErrorStr();
389  }
390  result.assign(tempPath.begin(), tempPath.begin() + static_cast<std::size_t>(bufferLength));
391 #else
392  result = "/tmp/";
393 #endif
394  }
395 
396  return result;
397  }
398 
399  std::string IOUtil::CreateTemporaryFile(const std::string &templateName, std::string path)
400  {
401  ofstream tmpOutputStream;
402  std::string returnValue = CreateTemporaryFile(tmpOutputStream, templateName, path);
403  tmpOutputStream.close();
404  return returnValue;
405  }
406 
407  std::string IOUtil::CreateTemporaryFile(std::ofstream &f, const std::string &templateName, std::string path)
408  {
409  return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path);
410  }
411 
412  std::string IOUtil::CreateTemporaryFile(std::ofstream &f,
413  std::ios_base::openmode mode,
414  const std::string &templateName,
415  std::string path)
416  {
417  if (path.empty())
418  {
419  path = GetTempPath();
420  }
421 
422  path += templateName;
423 
424  std::vector<char> dst_path(path.begin(), path.end());
425  dst_path.push_back('\0');
426 
427  std::size_t lastX = path.find_last_of('X');
428  std::size_t firstX = path.find_last_not_of('X', lastX);
429  int firstNonX = firstX == std::string::npos ? -1 : firstX - 1;
430  while (lastX != std::string::npos && (lastX - firstNonX) < 6)
431  {
432  lastX = path.find_last_of('X', firstX);
433  firstX = path.find_last_not_of('X', lastX);
434  firstNonX = firstX == std::string::npos ? -1 : firstX - 1;
435  }
436  std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1;
437 
438  int fd = mkstemps_compat(&dst_path[0], suffixlen);
439  if (fd != -1)
440  {
441  path.assign(dst_path.begin(), dst_path.end() - 1);
442  f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc);
443  close(fd);
444  }
445  else
446  {
447  mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr();
448  }
449  return path;
450  }
451 
452  std::string IOUtil::CreateTemporaryDirectory(const std::string &templateName, std::string path)
453  {
454  if (path.empty())
455  {
456  path = GetTempPath();
457  }
458 
459  path += GetDirectorySeparator() + templateName;
460  std::vector<char> dst_path(path.begin(), path.end());
461  dst_path.push_back('\0');
462 
463  std::size_t lastX = path.find_last_of('X');
464  std::size_t firstX = path.find_last_not_of('X', lastX);
465  int firstNonX = firstX == std::string::npos ? -1 : firstX - 1;
466  while (lastX != std::string::npos && (lastX - firstNonX) < 6)
467  {
468  lastX = path.find_last_of('X', firstX);
469  firstX = path.find_last_not_of('X', lastX);
470  firstNonX = firstX == std::string::npos ? -1 : firstX - 1;
471  }
472  std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1;
473 
474  if (mkdtemps_compat(&dst_path[0], suffixlen) == NULL)
475  {
476  mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr();
477  }
478 
479  path.assign(dst_path.begin(), dst_path.end() - 1);
480  return path;
481  }
482 
484  {
485  std::vector<std::string> paths;
486  paths.push_back(path);
487  return Load(paths, storage);
488  }
489 
491  const IFileReader::Options &options,
492  DataStorage &storage)
493  {
494  std::vector<LoadInfo> loadInfos;
495  loadInfos.push_back(LoadInfo(path));
497  Impl::FixedReaderOptionsFunctor optionsCallback(options);
498  std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback);
499  if (!errMsg.empty())
500  {
501  mitkThrow() << errMsg;
502  }
503  return nodeResult;
504  }
505 
506  std::vector<BaseData::Pointer> IOUtil::Load(const std::string &path)
507  {
508  std::vector<std::string> paths;
509  paths.push_back(path);
510  return Load(paths);
511  }
512 
513  std::vector<BaseData::Pointer> IOUtil::Load(const std::string &path, const IFileReader::Options &options)
514  {
515  std::vector<LoadInfo> loadInfos;
516  loadInfos.push_back(LoadInfo(path));
517  Impl::FixedReaderOptionsFunctor optionsCallback(options);
518  std::string errMsg = Load(loadInfos, NULL, NULL, &optionsCallback);
519  if (!errMsg.empty())
520  {
521  mitkThrow() << errMsg;
522  }
523  return loadInfos.front().m_Output;
524  }
525 
526  DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector<std::string> &paths, DataStorage &storage)
527  {
529  std::vector<LoadInfo> loadInfos;
530  for (auto loadInfo : paths)
531  {
532  loadInfos.push_back(loadInfo);
533  }
534  std::string errMsg = Load(loadInfos, nodeResult, &storage, NULL);
535  if (!errMsg.empty())
536  {
537  mitkThrow() << errMsg;
538  }
539  return nodeResult;
540  }
541 
542  std::vector<BaseData::Pointer> IOUtil::Load(const std::vector<std::string> &paths)
543  {
544  std::vector<BaseData::Pointer> result;
545  std::vector<LoadInfo> loadInfos;
546  for (auto loadInfo : paths)
547  {
548  loadInfos.push_back(loadInfo);
549  }
550  std::string errMsg = Load(loadInfos, NULL, NULL, NULL);
551  if (!errMsg.empty())
552  {
553  mitkThrow() << errMsg;
554  }
555 
556  for (std::vector<LoadInfo>::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd;
557  ++iter)
558  {
559  result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end());
560  }
561  return result;
562  }
563 
564  int IOUtil::LoadFiles(const std::vector<std::string> &fileNames, DataStorage &ds)
565  {
566  return static_cast<int>(Load(fileNames, ds)->Size());
567  }
568 
569  DataStorage::Pointer IOUtil::LoadFiles(const std::vector<std::string> &fileNames)
570  {
572  Load(fileNames, *ds);
573  return ds.GetPointer();
574  }
575 
576  BaseData::Pointer IOUtil::LoadBaseData(const std::string &path) { return Impl::LoadBaseDataFromFile(path); }
577  BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string &path)
578  {
579  std::vector<BaseData::Pointer> baseDataList = Load(path);
580 
581  // The Load(path) call above should throw an exception if nothing could be loaded
582  assert(!baseDataList.empty());
583  return baseDataList.front();
584  }
585 
586  DataNode::Pointer IOUtil::LoadDataNode(const std::string &path)
587  {
588  BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path);
589 
591  node->SetData(baseData);
592  Impl::SetDefaultDataNodeProperties(node, path);
593 
594  return node;
595  }
596 
597  Image::Pointer IOUtil::LoadImage(const std::string &path)
598  {
599  BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path);
600  mitk::Image::Pointer image = dynamic_cast<mitk::Image *>(baseData.GetPointer());
601  if (image.IsNull())
602  {
603  mitkThrow() << path << " is not a mitk::Image but a " << baseData->GetNameOfClass();
604  }
605  return image;
606  }
607 
608  Surface::Pointer IOUtil::LoadSurface(const std::string &path)
609  {
610  BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path);
611  mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface *>(baseData.GetPointer());
612  if (surface.IsNull())
613  {
614  mitkThrow() << path << " is not a mitk::Surface but a " << baseData->GetNameOfClass();
615  }
616  return surface;
617  }
618 
619  PointSet::Pointer IOUtil::LoadPointSet(const std::string &path)
620  {
621  BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path);
622  mitk::PointSet::Pointer pointset = dynamic_cast<mitk::PointSet *>(baseData.GetPointer());
623  if (pointset.IsNull())
624  {
625  mitkThrow() << path << " is not a mitk::PointSet but a " << baseData->GetNameOfClass();
626  }
627  return pointset;
628  }
629 
630  std::string IOUtil::Load(std::vector<LoadInfo> &loadInfos,
631  DataStorage::SetOfObjects *nodeResult,
632  DataStorage *ds,
633  ReaderOptionsFunctorBase *optionsCallback)
634  {
635  if (loadInfos.empty())
636  {
637  return "No input files given";
638  }
639 
640  int filesToRead = loadInfos.size();
641  mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToRead);
642 
643  std::string errMsg;
644 
645  std::map<std::string, FileReaderSelector::Item> usedReaderItems;
646 
647  for (auto &loadInfo : loadInfos)
648  {
649  std::vector<FileReaderSelector::Item> readers = loadInfo.m_ReaderSelector.Get();
650 
651  if (readers.empty())
652  {
653  if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str()))
654  {
655  errMsg += "File '" + loadInfo.m_Path + "' does not exist\n";
656  }
657  else
658  {
659  errMsg += "No reader available for '" + loadInfo.m_Path + "'\n";
660  }
661  continue;
662  }
663 
664  bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty();
665 
666  // check if we already used a reader which should be re-used
667  std::vector<MimeType> currMimeTypes = loadInfo.m_ReaderSelector.GetMimeTypes();
668  std::string selectedMimeType;
669  for (std::vector<MimeType>::const_iterator mimeTypeIter = currMimeTypes.begin(),
670  mimeTypeIterEnd = currMimeTypes.end();
671  mimeTypeIter != mimeTypeIterEnd;
672  ++mimeTypeIter)
673  {
674  std::map<std::string, FileReaderSelector::Item>::const_iterator oldSelectedItemIter =
675  usedReaderItems.find(mimeTypeIter->GetName());
676  if (oldSelectedItemIter != usedReaderItems.end())
677  {
678  // we found an already used item for a mime-type which is contained
679  // in the current reader set, check all current readers if there service
680  // id equals the old reader
681  for (std::vector<FileReaderSelector::Item>::const_iterator currReaderItem = readers.begin(),
682  currReaderItemEnd = readers.end();
683  currReaderItem != currReaderItemEnd;
684  ++currReaderItem)
685  {
686  if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() &&
687  currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() &&
688  currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel())
689  {
690  // okay, we used the same reader already, re-use its options
691  selectedMimeType = mimeTypeIter->GetName();
692  callOptionsCallback = false;
693  loadInfo.m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId());
694  loadInfo.m_ReaderSelector.GetSelected().GetReader()->SetOptions(
695  oldSelectedItemIter->second.GetReader()->GetOptions());
696  break;
697  }
698  }
699  if (!selectedMimeType.empty())
700  break;
701  }
702  }
703 
704  if (callOptionsCallback && optionsCallback)
705  {
706  callOptionsCallback = (*optionsCallback)(loadInfo);
707  if (!callOptionsCallback && !loadInfo.m_Cancel)
708  {
709  usedReaderItems.erase(selectedMimeType);
710  FileReaderSelector::Item selectedItem = loadInfo.m_ReaderSelector.GetSelected();
711  usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), selectedItem));
712  }
713  }
714 
715  if (loadInfo.m_Cancel)
716  {
717  errMsg += "Reading operation(s) cancelled.";
718  break;
719  }
720 
721  IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader();
722  if (reader == NULL)
723  {
724  errMsg += "Unexpected NULL reader.";
725  break;
726  }
727 
728  // Do the actual reading
729  try
730  {
732  if (ds != NULL)
733  {
734  nodes = reader->Read(*ds);
735  }
736  else
737  {
739  std::vector<mitk::BaseData::Pointer> baseData = reader->Read();
740  for (std::vector<mitk::BaseData::Pointer>::iterator iter = baseData.begin(); iter != baseData.end(); ++iter)
741  {
742  if (iter->IsNotNull())
743  {
745  node->SetData(*iter);
746  nodes->InsertElement(nodes->Size(), node);
747  }
748  }
749  }
750 
751  for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), nodeIterEnd = nodes->End();
752  nodeIter != nodeIterEnd;
753  ++nodeIter)
754  {
755  const mitk::DataNode::Pointer &node = nodeIter->Value();
756  mitk::BaseData::Pointer data = node->GetData();
757  if (data.IsNull())
758  {
759  continue;
760  }
761 
762  mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(loadInfo.m_Path);
763  data->SetProperty("path", pathProp);
764 
765  loadInfo.m_Output.push_back(data);
766  if (nodeResult)
767  {
768  nodeResult->push_back(nodeIter->Value());
769  }
770  }
771 
772  if (loadInfo.m_Output.empty() || (nodeResult && nodeResult->Size() == 0))
773  {
774  errMsg += "Unknown read error occurred reading " + loadInfo.m_Path;
775  }
776  }
777  catch (const std::exception &e)
778  {
779  errMsg += "Exception occured when reading file " + loadInfo.m_Path + ":\n" + e.what() + "\n\n";
780  }
782  --filesToRead;
783  }
784 
785  if (!errMsg.empty())
786  {
787  MITK_ERROR << errMsg;
788  }
789 
790  mitk::ProgressBar::GetInstance()->Progress(2 * filesToRead);
791 
792  return errMsg;
793  }
794 
795  std::vector<BaseData::Pointer> IOUtil::Load(const us::ModuleResource &usResource, std::ios_base::openmode mode)
796  {
797  us::ModuleResourceStream resStream(usResource, mode);
798 
800  std::vector<MimeType> mimetypes = mimeTypeProvider->GetMimeTypesForFile(usResource.GetResourcePath());
801 
802  std::vector<mitk::BaseData::Pointer> data;
803  if (mimetypes.empty())
804  {
805  mitkThrow() << "No mimetype for resource stream: " << usResource.GetResourcePath();
806  return data;
807  }
808 
809  mitk::FileReaderRegistry fileReaderRegistry;
810  std::vector<us::ServiceReference<IFileReader>> refs = fileReaderRegistry.GetReferences(mimetypes[0]);
811  if (refs.empty())
812  {
813  mitkThrow() << "No reader available for resource stream: " << usResource.GetResourcePath();
814  return data;
815  }
816 
817  mitk::IFileReader *reader = fileReaderRegistry.GetReader(refs[0]);
818  reader->SetInput(usResource.GetResourcePath(), &resStream);
819  data = reader->Read();
820 
821  return data;
822  }
823 
824  void IOUtil::Save(const BaseData *data, const std::string &path) { Save(data, path, IFileWriter::Options()); }
825  void IOUtil::Save(const BaseData *data, const std::string &path, const IFileWriter::Options &options)
826  {
827  Save(data, std::string(), path, options);
828  }
829 
830  void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension)
831  {
832  Save(data, mimeType, path, IFileWriter::Options(), addExtension);
833  }
834 
835  void IOUtil::Save(const BaseData *data,
836  const std::string &mimeType,
837  const std::string &path,
838  const IFileWriter::Options &options,
839  bool addExtension)
840  {
841  if ((data == NULL) || (data->IsEmpty()))
842  mitkThrow() << "BaseData cannotbe null or empty for save methods in IOUtil.h.";
843 
844  std::string errMsg;
845  if (options.empty())
846  {
847  errMsg = Save(data, mimeType, path, NULL, addExtension);
848  }
849  else
850  {
851  Impl::FixedWriterOptionsFunctor optionsCallback(options);
852  errMsg = Save(data, mimeType, path, &optionsCallback, addExtension);
853  }
854 
855  if (!errMsg.empty())
856  {
857  mitkThrow() << errMsg;
858  }
859  }
860 
861  void IOUtil::Save(std::vector<IOUtil::SaveInfo> &saveInfos)
862  {
863  std::string errMsg = Save(saveInfos, NULL);
864  if (!errMsg.empty())
865  {
866  mitkThrow() << errMsg;
867  }
868  }
869 
870  bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string &path)
871  {
872  Save(image, path);
873  return true;
874  }
875 
876  bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string &path)
877  {
878  Save(surface, path);
879  return true;
880  }
881 
882  bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string &path)
883  {
884  Save(pointset, path);
885  return true;
886  }
887 
888  bool IOUtil::SaveBaseData(mitk::BaseData *data, const std::string &path)
889  {
890  Save(data, path);
891  return true;
892  }
893 
894  std::string IOUtil::Save(const BaseData *data,
895  const std::string &mimeTypeName,
896  const std::string &path,
897  WriterOptionsFunctorBase *optionsCallback,
898  bool addExtension)
899  {
900  if (path.empty())
901  {
902  return "No output filename given";
903  }
904 
906 
907  MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName);
908 
909  SaveInfo saveInfo(data, mimeType, path);
910 
911  std::string ext = itksys::SystemTools::GetFilenameExtension(path);
912 
913  if (saveInfo.m_WriterSelector.IsEmpty())
914  {
915  return std::string("No suitable writer found for the current data of type ") + data->GetNameOfClass() +
916  (mimeType.IsValid() ? (std::string(" and mime-type ") + mimeType.GetName()) : std::string()) +
917  (ext.empty() ? std::string() : (std::string(" with extension ") + ext));
918  }
919 
920  // Add an extension if not already specified
921  if (ext.empty() && addExtension)
922  {
923  saveInfo.m_MimeType.GetExtensions().empty() ? std::string() : "." + saveInfo.m_MimeType.GetExtensions().front();
924  }
925 
926  std::vector<SaveInfo> infos;
927  infos.push_back(saveInfo);
928  return Save(infos, optionsCallback);
929  }
930 
931  std::string IOUtil::Save(std::vector<SaveInfo> &saveInfos, WriterOptionsFunctorBase *optionsCallback)
932  {
933  if (saveInfos.empty())
934  {
935  return "No data for saving available";
936  }
937 
938  int filesToWrite = saveInfos.size();
939  mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToWrite);
940 
941  std::string errMsg;
942 
943  std::set<SaveInfo> usedSaveInfos;
944 
945  for (auto &saveInfo : saveInfos)
946  {
947  const std::string baseDataType = saveInfo.m_BaseData->GetNameOfClass();
948 
949  std::vector<FileWriterSelector::Item> writers = saveInfo.m_WriterSelector.Get();
950 
951  // Error out if no compatible Writer was found
952  if (writers.empty())
953  {
954  errMsg += std::string("No writer available for ") + baseDataType + " data.\n";
955  continue;
956  }
957 
958  bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty();
959 
960  // check if we already used a writer for this base data type
961  // which should be re-used
962  std::set<SaveInfo>::const_iterator oldSaveInfoIter = usedSaveInfos.find(saveInfo);
963  if (oldSaveInfoIter != usedSaveInfos.end())
964  {
965  // we previously saved a base data object of the same data with the same mime-type,
966  // check if the same writer is contained in the current writer set and if the
967  // confidence level matches
968  FileWriterSelector::Item oldSelectedItem =
969  oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId());
970  for (std::vector<FileWriterSelector::Item>::const_iterator currWriterItem = writers.begin(),
971  currWriterItemEnd = writers.end();
972  currWriterItem != currWriterItemEnd;
973  ++currWriterItem)
974  {
975  if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() &&
976  currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel())
977  {
978  // okay, we used the same writer already, re-use its options
979  callOptionsCallback = false;
980  saveInfo.m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId());
981  saveInfo.m_WriterSelector.GetSelected().GetWriter()->SetOptions(oldSelectedItem.GetWriter()->GetOptions());
982  break;
983  }
984  }
985  }
986 
987  if (callOptionsCallback && optionsCallback)
988  {
989  callOptionsCallback = (*optionsCallback)(saveInfo);
990  if (!callOptionsCallback && !saveInfo.m_Cancel)
991  {
992  usedSaveInfos.erase(saveInfo);
993  usedSaveInfos.insert(saveInfo);
994  }
995  }
996 
997  if (saveInfo.m_Cancel)
998  {
999  errMsg += "Writing operation(s) cancelled.";
1000  break;
1001  }
1002 
1003  IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter();
1004  if (writer == NULL)
1005  {
1006  errMsg += "Unexpected NULL writer.";
1007  break;
1008  }
1009 
1010  // Do the actual writing
1011  try
1012  {
1013  writer->SetOutputLocation(saveInfo.m_Path);
1014  writer->Write();
1015  }
1016  catch (const std::exception &e)
1017  {
1018  errMsg += std::string("Exception occurred when writing to ") + saveInfo.m_Path + ":\n" + e.what() + "\n";
1019  }
1021  --filesToWrite;
1022  }
1023 
1024  if (!errMsg.empty())
1025  {
1026  MITK_ERROR << errMsg;
1027  }
1028 
1029  mitk::ProgressBar::GetInstance()->Progress(2 * filesToWrite);
1030 
1031  return errMsg;
1032  }
1033 
1034  // This method can be removed after the deprecated LoadDataNode() method was removed
1035  void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath)
1036  {
1037  // path
1038  mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenamePath(filePath));
1039  node->SetProperty(StringProperty::PATH, pathProp);
1040 
1041  // name already defined?
1042  mitk::StringProperty::Pointer nameProp = dynamic_cast<mitk::StringProperty *>(node->GetProperty("name"));
1043  if (nameProp.IsNull() || (strcmp(nameProp->GetValue(), "No Name!") == 0))
1044  {
1045  // name already defined in BaseData
1046  mitk::StringProperty::Pointer baseDataNameProp =
1047  dynamic_cast<mitk::StringProperty *>(node->GetData()->GetProperty("name").GetPointer());
1048  if (baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(), "No Name!") == 0))
1049  {
1050  // name neither defined in node, nor in BaseData -> name = filename
1051  nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(filePath));
1052  node->SetProperty("name", nameProp);
1053  }
1054  else
1055  {
1056  // name defined in BaseData!
1057  nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue());
1058  node->SetProperty("name", nameProp);
1059  }
1060  }
1061 
1062  // visibility
1063  if (!node->GetProperty("visible"))
1064  {
1065  node->SetVisibility(true);
1066  }
1067  }
1068 
1069  IOUtil::SaveInfo::SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path)
1070  : m_BaseData(baseData),
1071  m_WriterSelector(baseData, mimeType.GetName(), path),
1072  m_MimeType(mimeType.IsValid() ? mimeType // use the original mime-type
1073  :
1074  (m_WriterSelector.IsEmpty() ?
1075  mimeType // no writer found, use the original invalid mime-type
1076  :
1077  m_WriterSelector.GetDefault().GetMimeType() // use the found default mime-type
1078  )),
1079  m_Path(path),
1080  m_Cancel(false)
1081  {
1082  }
1083 
1085  {
1086  int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass());
1087  if (r == 0)
1088  {
1089  return m_WriterSelector.GetSelected().GetMimeType() < other.m_WriterSelector.GetSelected().GetMimeType();
1090  }
1091  return r < 0;
1092  }
1093 
1094  IOUtil::LoadInfo::LoadInfo(const std::string &path) : m_Path(path), m_ReaderSelector(path), m_Cancel(false) {}
1095 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:32
static mitk::Surface::Pointer LoadSurface(const std::string &path)
LoadSurface Convenience method to load an arbitrary mitkSurface.
Definition: mitkIOUtil.cpp:608
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
static char GetDirectorySeparator()
Definition: mitkIOUtil.cpp:363
Data management class that handles 'was created by' relations.
std::string GetResourcePath() const
itk::SmartPointer< Self > Pointer
FileWriterSelector m_WriterSelector
Contains a set of IFileWriter objects.
Definition: mitkIOUtil.h:74
void SetVisibility(bool visible, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="visible")
Convenience method for setting visibility properties (instances of BoolProperty)
static IMimeTypeProvider * GetMimeTypeProvider(us::ModuleContext *context=us::GetModuleContext())
Get an IMimeTypeProvider instance.
itk::VectorContainer< unsigned int, mitk::DataNode::Pointer > SetOfObjects
A Container of objects that is used as a result set of GetSubset() query operations (Set of...
mitk::IFileReader * GetReader(const ReaderReference &ref, us::ModuleContext *context=us::GetModuleContext())
Base of all data objects.
Definition: mitkBaseData.h:39
static std::string GetTempPath()
Definition: mitkIOUtil.cpp:372
#define MITK_ERROR
Definition: mitkLogMacros.h:24
virtual MimeType GetMimeTypeForName(const std::string &name) const =0
bool IsValid() const
DataCollection - Class to facilitate loading/accessing structured data.
std::map< std::string, us::Any > Options
Options for reading or writing data.
Definition: mitkIFileIO.h:73
LoadInfo(const std::string &path)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
const BaseData * m_BaseData
The BaseData object to save.
Definition: mitkIOUtil.h:71
virtual void SetOutputLocation(const std::string &location)=0
Set the output location.
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
static mitk::BaseData::Pointer LoadBaseData(const std::string &path)
Create a BaseData object from the given file.
Definition: mitkIOUtil.cpp:576
static bool SaveSurface(mitk::Surface::Pointer surface, const std::string &path)
SaveSurface Convenience method to save an arbitrary mitkSurface.
Definition: mitkIOUtil.cpp:876
std::vector< std::string > GetExtensions() const
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
virtual std::vector< itk::SmartPointer< BaseData > > Read()=0
Reads the specified file or input stream and returns its contents.
bool operator<(const SaveInfo &other) const
std::string GetName() const
#define ATTEMPTS_MIN
MimeType m_MimeType
The selected mime-type, used to restrict results from FileWriterSelector.
Definition: mitkIOUtil.h:76
static bool SaveImage(mitk::Image::Pointer image, const std::string &path)
SaveImage Convenience method to save an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:870
static bool SaveBaseData(mitk::BaseData *data, const std::string &path)
SaveBaseData Convenience method to save arbitrary baseData.
Definition: mitkIOUtil.cpp:888
static int mkstemps_compat(char *tmpl, int suffixlen)
Definition: mitkIOUtil.cpp:93
SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path)
static std::string GetLastErrorStr()
Definition: mitkIOUtil.cpp:45
virtual void SetInput(const std::string &location)=0
Set the input location.
Data structure which stores a set of points. Superclass of mitk::Mesh.
Definition: mitkPointSet.h:79
static int LoadFiles(const std::vector< std::string > &fileNames, DataStorage &storage)
Definition: mitkIOUtil.cpp:564
static Pointer New()
#define mitkThrow()
Image class for storing images.
Definition: mitkImage.h:76
static char * mkdtemps_compat(char *tmpl, int suffixlen)
Definition: mitkIOUtil.cpp:182
static mitk::PointSet::Pointer LoadPointSet(const std::string &path)
LoadPointSet Convenience method to load an arbitrary mitkPointSet.
Definition: mitkIOUtil.cpp:619
virtual void Write()=0
Write the input data.
static const char * PATH
The MimeType class represens a registered mime-type. It is an immutable wrapper for mitk::CustomMimeT...
Definition: mitkMimeType.h:45
static mitk::DataNode::Pointer LoadDataNode(const std::string &path)
LoadDataNode Method to load an arbitrary DataNode.
Definition: mitkIOUtil.cpp:586
static std::string CreateTemporaryDirectory(const std::string &templateName="XXXXXX", std::string path=std::string())
Definition: mitkIOUtil.cpp:452
static std::string GetProgramPath()
Definition: mitkIOUtil.cpp:350
virtual Options GetOptions() const =0
returns a list of the supported options
void AddStepsToDo(unsigned int steps)
Adds steps to totalSteps.
static std::string CreateTemporaryFile(std::ofstream &tmpStream, const std::string &templateName="XXXXXX", std::string path=std::string())
Definition: mitkIOUtil.cpp:407
virtual bool IsEmpty() const
Check whether object contains data (at least at one point in time), e.g., a set of points may be empt...
static std::string GetName(std::string fileName, std::string suffix)
A RAII helper class for core service objects.
static DataStorage::SetOfObjects::Pointer Load(const std::string &path, DataStorage &storage)
Load a file into the given DataStorage.
Definition: mitkIOUtil.cpp:483
void SetProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer=nullptr)
Set the property (instance of BaseProperty) with key propertyKey in the PropertyList of the renderer ...
static std::vector< ReaderReference > GetReferences(const MimeType &mimeType, us::ModuleContext *context=us::GetModuleContext())
Property for strings.
IFileWriter::ConfidenceLevel GetConfidenceLevel() const
mitk::BaseProperty::Pointer GetProperty(const char *propertyKey) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList, and set it to this, respectively;.
The common interface for all MITK file readers.
The common interface of all MITK file writers.
static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string &path)
SavePointSet Convenience method to save an mitkPointSet.
Definition: mitkIOUtil.cpp:882
itk::SmartPointer< Self > Pointer
Definition: mitkBaseData.h:42
static mitk::Image::Pointer LoadImage(const std::string &path)
LoadImage Convenience method to load an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:597
static Pointer New()
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static const char validLetters[]
Definition: mitkIOUtil.cpp:90
virtual std::vector< MimeType > GetMimeTypesForFile(const std::string &filePath) const =0
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.