Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
usUtils.cpp
Go to the documentation of this file.
1 /*=============================================================================
2 
3  Library: CppMicroServices
4 
5  Copyright (c) German Cancer Research Center,
6  Division of Medical and Biological Informatics
7 
8  Licensed under the Apache License, Version 2.0 (the "License");
9  you may not use this file except in compliance with the License.
10  You may obtain a copy of the License at
11 
12  http://www.apache.org/licenses/LICENSE-2.0
13 
14  Unless required by applicable law or agreed to in writing, software
15  distributed under the License is distributed on an "AS IS" BASIS,
16  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  See the License for the specific language governing permissions and
18  limitations under the License.
19 
20 =============================================================================*/
21 
22 #include "usUtils_p.h"
23 
24 #include "usLog_p.h"
25 #include "usModuleInfo.h"
26 #include "usModuleSettings.h"
27 
28 #include <string>
29 #include <cstdio>
30 #include <cctype>
31 #include <algorithm>
32 #include <typeinfo>
33 
34 #ifdef US_PLATFORM_POSIX
35  #include <errno.h>
36  #include <string.h>
37  #include <dlfcn.h>
38  #include <dirent.h>
39 #else
40  #ifndef WIN32_LEAN_AND_MEAN
41  #define WIN32_LEAN_AND_MEAN
42  #endif
43  #include <windows.h>
44  #include <crtdbg.h>
45  #include "dirent_win32.h"
46 #endif
47 
48 //-------------------------------------------------------------------
49 // Module auto-loading
50 //-------------------------------------------------------------------
51 
52 namespace {
53 
54 #if !defined(US_PLATFORM_LINUX)
55 std::string library_suffix()
56 {
57 #ifdef US_PLATFORM_WINDOWS
58  return ".dll";
59 #elif defined(US_PLATFORM_APPLE)
60  return ".dylib";
61 #else
62  return ".so";
63 #endif
64 }
65 #endif
66 
67 #ifdef US_PLATFORM_POSIX
68 
69 const char DIR_SEP = '/';
70 
71 bool load_impl(const std::string& modulePath)
72 {
73  void* handle = dlopen(modulePath.c_str(), RTLD_NOW | RTLD_LOCAL);
74  if (handle == NULL)
75  {
76  US_WARN << dlerror();
77  }
78  return (handle != NULL);
79 }
80 
81 #elif defined(US_PLATFORM_WINDOWS)
82 
83 const char DIR_SEP = '\\';
84 
85 bool load_impl(const std::string& modulePath)
86 {
87  void* handle = LoadLibrary(modulePath.c_str());
88  if (handle == NULL)
89  {
90  US_WARN << us::GetLastErrorStr();
91  }
92  return (handle != NULL);
93 }
94 
95 #else
96 
97  #ifdef US_ENABLE_AUTOLOADING_SUPPORT
98  #error "Missing load_impl implementation for this platform."
99  #else
100 bool load_impl(const std::string&) { return false; }
101  #endif
102 
103 #endif
104 
105 }
106 
107 US_BEGIN_NAMESPACE
108 
109 std::vector<std::string> AutoLoadModulesFromPath(const std::string& absoluteBasePath, const std::string& subDir)
110 {
111  std::vector<std::string> loadedModules;
112 
113  std::string loadPath = absoluteBasePath + DIR_SEP + subDir;
114 
115  DIR* dir = opendir(loadPath.c_str());
116 #ifdef CMAKE_INTDIR
117  // Try intermediate output directories
118  if (dir == NULL)
119  {
120  std::size_t indexOfLastSeparator = absoluteBasePath.find_last_of(DIR_SEP);
121  if (indexOfLastSeparator != std::string::npos)
122  {
123  std::string intermediateDir = absoluteBasePath.substr(indexOfLastSeparator+1);
124  bool equalSubDir = intermediateDir.size() == std::strlen(CMAKE_INTDIR);
125  for (std::size_t i = 0; equalSubDir && i < intermediateDir.size(); ++i)
126  {
127  if (std::tolower(intermediateDir[i]) != std::tolower(CMAKE_INTDIR[i]))
128  {
129  equalSubDir = false;
130  }
131  }
132  if (equalSubDir)
133  {
134  loadPath = absoluteBasePath.substr(0, indexOfLastSeparator+1) + subDir + DIR_SEP + CMAKE_INTDIR;
135  dir = opendir(loadPath.c_str());
136  }
137  }
138  }
139 #endif
140 
141  if (dir != NULL)
142  {
143  struct dirent *ent = NULL;
144  while ((ent = readdir(dir)) != NULL)
145  {
146  bool loadFile = true;
147 #ifdef _DIRENT_HAVE_D_TYPE
148  if (ent->d_type != DT_UNKNOWN && ent->d_type != DT_REG)
149  {
150  loadFile = false;
151  }
152 #endif
153 
154  std::string entryFileName(ent->d_name);
155 
156  // On Linux, library file names can have version numbers appended. On other platforms, we
157  // check the file ending. This could be refined for Linux in the future.
158 #if !defined(US_PLATFORM_LINUX)
159  if (entryFileName.rfind(library_suffix()) != (entryFileName.size() - library_suffix().size()))
160  {
161  loadFile = false;
162  }
163 #endif
164  if (!loadFile) continue;
165 
166  std::string libPath = loadPath;
167  if (!libPath.empty() && libPath.find_last_of(DIR_SEP) != libPath.size() -1)
168  {
169  libPath += DIR_SEP;
170  }
171  libPath += entryFileName;
172  US_DEBUG << "Auto-loading module " << libPath;
173 
174  if (!load_impl(libPath))
175  {
176  US_WARN << "Auto-loading of module " << libPath << " failed.";
177  }
178  else
179  {
180  loadedModules.push_back(libPath);
181  }
182  }
183  closedir(dir);
184  }
185  return loadedModules;
186 }
187 
188 std::vector<std::string> AutoLoadModules(const ModuleInfo& moduleInfo)
189 {
190  std::vector<std::string> loadedModules;
191 
192  if (moduleInfo.autoLoadDir.empty())
193  {
194  return loadedModules;
195  }
196 
197  ModuleSettings::PathList autoLoadPaths = ModuleSettings::GetAutoLoadPaths();
198 
199  std::size_t indexOfLastSeparator = moduleInfo.location.find_last_of(DIR_SEP);
200  std::string moduleBasePath = moduleInfo.location.substr(0, indexOfLastSeparator);
201 
202  for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin();
203  i != autoLoadPaths.end(); ++i)
204  {
205  if (*i == ModuleSettings::CURRENT_MODULE_PATH())
206  {
207  // Load all modules from a directory located relative to this modules location
208  // and named after this modules library name.
209  *i = moduleBasePath;
210  }
211  }
212 
213  // We could have introduced a duplicate above, so remove it.
214  std::sort(autoLoadPaths.begin(), autoLoadPaths.end());
215  autoLoadPaths.erase(std::unique(autoLoadPaths.begin(), autoLoadPaths.end()), autoLoadPaths.end());
216  for (ModuleSettings::PathList::iterator i = autoLoadPaths.begin();
217  i != autoLoadPaths.end(); ++i)
218  {
219  if (i->empty()) continue;
220  std::vector<std::string> paths = AutoLoadModulesFromPath(*i, moduleInfo.autoLoadDir);
221  loadedModules.insert(loadedModules.end(), paths.begin(), paths.end());
222  }
223  return loadedModules;
224 }
225 
226 US_END_NAMESPACE
227 
228 //-------------------------------------------------------------------
229 // Error handling
230 //-------------------------------------------------------------------
231 
232 US_BEGIN_NAMESPACE
233 
234 std::string GetLastErrorStr()
235 {
236 #ifdef US_PLATFORM_POSIX
237  return std::string(strerror(errno));
238 #else
239  // Retrieve the system error message for the last-error code
240  LPVOID lpMsgBuf;
241  DWORD dw = GetLastError();
242 
243  FormatMessage(
244  FORMAT_MESSAGE_ALLOCATE_BUFFER |
245  FORMAT_MESSAGE_FROM_SYSTEM |
246  FORMAT_MESSAGE_IGNORE_INSERTS,
247  NULL,
248  dw,
249  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
250  (LPTSTR) &lpMsgBuf,
251  0, NULL );
252 
253  std::string errMsg((LPCTSTR)lpMsgBuf);
254 
255  LocalFree(lpMsgBuf);
256 
257  return errMsg;
258 #endif
259 }
260 
261 static MsgHandler handler = 0;
262 
263 MsgHandler installMsgHandler(MsgHandler h)
264 {
265  MsgHandler old = handler;
266  handler = h;
267  return old;
268 }
269 
270 void message_output(MsgType msgType, const char *buf)
271 {
272  if (handler)
273  {
274  (*handler)(msgType, buf);
275  }
276  else
277  {
278  fprintf(stderr, "%s\n", buf);
279  fflush(stderr);
280  }
281 
282  if (msgType == ErrorMsg)
283  {
284  #if defined(_MSC_VER) && !defined(NDEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
285  // get the current report mode
286  int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
287  _CrtSetReportMode(_CRT_ERROR, reportMode);
288  int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, CppMicroServices_VERSION_STR, buf);
289  if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW)
290  return; // ignore
291  else if (ret == 1)
292  _CrtDbgBreak();
293  #endif
294 
295  #ifdef US_PLATFORM_POSIX
296  abort(); // trap; generates core dump
297  #else
298  exit(1); // goodbye cruel world
299  #endif
300  }
301 }
302 
303 #ifdef US_HAVE_CXXABI_H
304 #include <cxxabi.h>
305 #endif
306 
307 US_Core_EXPORT ::std::string GetDemangledName(const ::std::type_info& typeInfo)
308 {
309  ::std::string result;
310 #ifdef US_HAVE_CXXABI_H
311  int status = 0;
312  char* demangled = abi::__cxa_demangle(typeInfo.name(), 0, 0, &status);
313  if (demangled && status == 0)
314  {
315  result = demangled;
316  free(demangled);
317  }
318 #elif defined(US_PLATFORM_WINDOWS)
319  const char* demangled = typeInfo.name();
320  if (demangled != NULL)
321  {
322  result = demangled;
323  // remove "struct" qualifiers
324  std::size_t pos = 0;
325  while (pos != std::string::npos)
326  {
327  if ((pos = result.find("struct ", pos)) != std::string::npos)
328  {
329  result = result.substr(0, pos) + result.substr(pos + 7);
330  pos += 8;
331  }
332  }
333  // remove "class" qualifiers
334  pos = 0;
335  while (pos != std::string::npos)
336  {
337  if ((pos = result.find("class ", pos)) != std::string::npos)
338  {
339  result = result.substr(0, pos) + result.substr(pos + 6);
340  pos += 7;
341  }
342  }
343  }
344 #else
345  (void)typeInfo;
346 #endif
347  return result;
348 }
349 
350 US_END_NAMESPACE
static MsgHandler handler
Definition: usUtils.cpp:261
US_Core_EXPORT::std::string GetDemangledName(const ::std::type_info &typeInfo)
Definition: usUtils.cpp:307
static int closedir(DIR *dirp)
Definition: dirent_win32.h:323
int d_type
Definition: dirent_win32.h:160
char d_name[MAX_PATH+1]
Definition: dirent_win32.h:158
static DIR * opendir(const char *dirname)
Definition: dirent_win32.h:201
static std::string GetLastErrorStr()
Definition: mitkIOUtil.cpp:45
void message_output(MsgType msgType, const char *buf)
Definition: usUtils.cpp:270
std::string autoLoadDir
Definition: usModuleInfo.h:49
std::string location
Definition: usModuleInfo.h:48
static struct dirent * readdir(DIR *dirp)
Definition: dirent_win32.h:270
#define DT_REG
Definition: dirent_win32.h:126
std::vector< std::string > AutoLoadModulesFromPath(const std::string &absoluteBasePath, const std::string &subDir)
Definition: usUtils.cpp:109
#define DT_UNKNOWN
Definition: dirent_win32.h:125
std::vector< std::string > AutoLoadModules(const ModuleInfo &moduleInfo)
Definition: usUtils.cpp:188
MsgHandler installMsgHandler(MsgHandler h)
Definition: usUtils.cpp:263
std::string GetLastErrorStr()
Definition: usUtils.cpp:234
std::vector< std::string > PathList