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