Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.