Mercurial > hg > orthanc
comparison OrthancFramework/Sources/SystemToolbox.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | Core/SystemToolbox.cpp@94f4a18a79cc |
children | bf7b9edf6b81 |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "PrecompiledHeaders.h" | |
35 #include "SystemToolbox.h" | |
36 | |
37 | |
38 #if defined(_WIN32) | |
39 # include <windows.h> | |
40 # include <process.h> // For "_spawnvp()" and "_getpid()" | |
41 # include <stdlib.h> // For "environ" | |
42 #else | |
43 # include <unistd.h> // For "execvp()" | |
44 # include <sys/wait.h> // For "waitpid()" | |
45 #endif | |
46 | |
47 | |
48 #if defined(__APPLE__) && defined(__MACH__) | |
49 # include <mach-o/dyld.h> /* _NSGetExecutablePath */ | |
50 # include <limits.h> /* PATH_MAX */ | |
51 #endif | |
52 | |
53 | |
54 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) | |
55 # include <limits.h> /* PATH_MAX */ | |
56 # include <signal.h> | |
57 # include <unistd.h> | |
58 #endif | |
59 | |
60 | |
61 #if defined(__OpenBSD__) | |
62 # include <sys/sysctl.h> // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS" | |
63 #endif | |
64 | |
65 | |
66 #include "Logging.h" | |
67 #include "OrthancException.h" | |
68 #include "Toolbox.h" | |
69 | |
70 #include <boost/filesystem.hpp> | |
71 #include <boost/filesystem/fstream.hpp> | |
72 #include <boost/date_time/posix_time/posix_time.hpp> | |
73 #include <boost/thread.hpp> | |
74 | |
75 | |
76 /*========================================================================= | |
77 The section below comes from the Boost 1.68.0 project: | |
78 https://github.com/boostorg/program_options/blob/boost-1.68.0/src/parsers.cpp | |
79 | |
80 Copyright Vladimir Prus 2002-2004. | |
81 Distributed under the Boost Software License, Version 1.0. | |
82 (See accompanying file LICENSE_1_0.txt | |
83 or copy at http://www.boost.org/LICENSE_1_0.txt) | |
84 =========================================================================*/ | |
85 | |
86 // The 'environ' should be declared in some cases. E.g. Linux man page says: | |
87 // (This variable must be declared in the user program, but is declared in | |
88 // the header file unistd.h in case the header files came from libc4 or libc5, | |
89 // and in case they came from glibc and _GNU_SOURCE was defined.) | |
90 // To be safe, declare it here. | |
91 | |
92 // It appears that on Mac OS X the 'environ' variable is not | |
93 // available to dynamically linked libraries. | |
94 // See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843 | |
95 // See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html | |
96 #if defined(__APPLE__) && defined(__DYNAMIC__) | |
97 // The proper include for this is crt_externs.h, however it's not | |
98 // available on iOS. The right replacement is not known. See | |
99 // https://svn.boost.org/trac/boost/ticket/5053 | |
100 extern "C" | |
101 { | |
102 extern char ***_NSGetEnviron(void); | |
103 } | |
104 # define environ (*_NSGetEnviron()) | |
105 #else | |
106 # if defined(__MWERKS__) | |
107 # include <crtl.h> | |
108 # else | |
109 # if !defined(_WIN32) || defined(__COMO_VERSION__) | |
110 extern char** environ; | |
111 # endif | |
112 # endif | |
113 #endif | |
114 | |
115 | |
116 /*========================================================================= | |
117 End of section from the Boost 1.68.0 project | |
118 =========================================================================*/ | |
119 | |
120 | |
121 namespace Orthanc | |
122 { | |
123 static bool finish_; | |
124 static ServerBarrierEvent barrierEvent_; | |
125 | |
126 #if defined(_WIN32) | |
127 static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) | |
128 { | |
129 // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx | |
130 finish_ = true; | |
131 return true; | |
132 } | |
133 #else | |
134 static void SignalHandler(int signal) | |
135 { | |
136 if (signal == SIGHUP) | |
137 { | |
138 barrierEvent_ = ServerBarrierEvent_Reload; | |
139 } | |
140 | |
141 finish_ = true; | |
142 } | |
143 #endif | |
144 | |
145 | |
146 static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) | |
147 { | |
148 #if defined(_WIN32) | |
149 SetConsoleCtrlHandler(ConsoleControlHandler, true); | |
150 #else | |
151 signal(SIGINT, SignalHandler); | |
152 signal(SIGQUIT, SignalHandler); | |
153 signal(SIGTERM, SignalHandler); | |
154 signal(SIGHUP, SignalHandler); | |
155 #endif | |
156 | |
157 // Active loop that awakens every 100ms | |
158 finish_ = false; | |
159 barrierEvent_ = ServerBarrierEvent_Stop; | |
160 while (!(*stopFlag || finish_)) | |
161 { | |
162 SystemToolbox::USleep(100 * 1000); | |
163 } | |
164 | |
165 #if defined(_WIN32) | |
166 SetConsoleCtrlHandler(ConsoleControlHandler, false); | |
167 #else | |
168 signal(SIGINT, NULL); | |
169 signal(SIGQUIT, NULL); | |
170 signal(SIGTERM, NULL); | |
171 signal(SIGHUP, NULL); | |
172 #endif | |
173 | |
174 return barrierEvent_; | |
175 } | |
176 | |
177 | |
178 ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag) | |
179 { | |
180 return ServerBarrierInternal(&stopFlag); | |
181 } | |
182 | |
183 | |
184 ServerBarrierEvent SystemToolbox::ServerBarrier() | |
185 { | |
186 const bool stopFlag = false; | |
187 return ServerBarrierInternal(&stopFlag); | |
188 } | |
189 | |
190 | |
191 void SystemToolbox::USleep(uint64_t microSeconds) | |
192 { | |
193 #if defined(_WIN32) | |
194 ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000))); | |
195 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__native_client__) | |
196 usleep(microSeconds); | |
197 #else | |
198 #error Support your platform here | |
199 #endif | |
200 } | |
201 | |
202 | |
203 static std::streamsize GetStreamSize(std::istream& f) | |
204 { | |
205 // http://www.cplusplus.com/reference/iostream/istream/tellg/ | |
206 f.seekg(0, std::ios::end); | |
207 std::streamsize size = f.tellg(); | |
208 f.seekg(0, std::ios::beg); | |
209 | |
210 return size; | |
211 } | |
212 | |
213 | |
214 void SystemToolbox::ReadFile(std::string& content, | |
215 const std::string& path, | |
216 bool log) | |
217 { | |
218 if (!IsRegularFile(path)) | |
219 { | |
220 throw OrthancException(ErrorCode_RegularFileExpected, | |
221 "The path does not point to a regular file: " + path, | |
222 log); | |
223 } | |
224 | |
225 boost::filesystem::ifstream f; | |
226 f.open(path, std::ifstream::in | std::ifstream::binary); | |
227 if (!f.good()) | |
228 { | |
229 throw OrthancException(ErrorCode_InexistentFile, | |
230 "File not found: " + path, | |
231 log); | |
232 } | |
233 | |
234 std::streamsize size = GetStreamSize(f); | |
235 content.resize(static_cast<size_t>(size)); | |
236 if (size != 0) | |
237 { | |
238 f.read(&content[0], size); | |
239 } | |
240 | |
241 f.close(); | |
242 } | |
243 | |
244 | |
245 bool SystemToolbox::ReadHeader(std::string& header, | |
246 const std::string& path, | |
247 size_t headerSize) | |
248 { | |
249 if (!IsRegularFile(path)) | |
250 { | |
251 throw OrthancException(ErrorCode_RegularFileExpected, | |
252 "The path does not point to a regular file: " + path); | |
253 } | |
254 | |
255 boost::filesystem::ifstream f; | |
256 f.open(path, std::ifstream::in | std::ifstream::binary); | |
257 if (!f.good()) | |
258 { | |
259 throw OrthancException(ErrorCode_InexistentFile); | |
260 } | |
261 | |
262 bool full = true; | |
263 | |
264 { | |
265 std::streamsize size = GetStreamSize(f); | |
266 if (size <= 0) | |
267 { | |
268 headerSize = 0; | |
269 full = false; | |
270 } | |
271 else if (static_cast<size_t>(size) < headerSize) | |
272 { | |
273 headerSize = static_cast<size_t>(size); // Truncate to the size of the file | |
274 full = false; | |
275 } | |
276 } | |
277 | |
278 header.resize(headerSize); | |
279 if (headerSize != 0) | |
280 { | |
281 f.read(&header[0], headerSize); | |
282 } | |
283 | |
284 f.close(); | |
285 | |
286 return full; | |
287 } | |
288 | |
289 | |
290 void SystemToolbox::WriteFile(const void* content, | |
291 size_t size, | |
292 const std::string& path) | |
293 { | |
294 boost::filesystem::ofstream f; | |
295 f.open(path, std::ofstream::out | std::ofstream::binary); | |
296 if (!f.good()) | |
297 { | |
298 throw OrthancException(ErrorCode_CannotWriteFile); | |
299 } | |
300 | |
301 if (size != 0) | |
302 { | |
303 f.write(reinterpret_cast<const char*>(content), size); | |
304 | |
305 if (!f.good()) | |
306 { | |
307 f.close(); | |
308 throw OrthancException(ErrorCode_FileStorageCannotWrite); | |
309 } | |
310 } | |
311 | |
312 f.close(); | |
313 } | |
314 | |
315 | |
316 void SystemToolbox::WriteFile(const std::string& content, | |
317 const std::string& path) | |
318 { | |
319 WriteFile(content.size() > 0 ? content.c_str() : NULL, | |
320 content.size(), path); | |
321 } | |
322 | |
323 | |
324 void SystemToolbox::RemoveFile(const std::string& path) | |
325 { | |
326 if (boost::filesystem::exists(path)) | |
327 { | |
328 if (IsRegularFile(path)) | |
329 { | |
330 boost::filesystem::remove(path); | |
331 } | |
332 else | |
333 { | |
334 throw OrthancException(ErrorCode_RegularFileExpected); | |
335 } | |
336 } | |
337 } | |
338 | |
339 | |
340 uint64_t SystemToolbox::GetFileSize(const std::string& path) | |
341 { | |
342 try | |
343 { | |
344 return static_cast<uint64_t>(boost::filesystem::file_size(path)); | |
345 } | |
346 catch (boost::filesystem::filesystem_error&) | |
347 { | |
348 throw OrthancException(ErrorCode_InexistentFile); | |
349 } | |
350 } | |
351 | |
352 | |
353 void SystemToolbox::MakeDirectory(const std::string& path) | |
354 { | |
355 if (boost::filesystem::exists(path)) | |
356 { | |
357 if (!boost::filesystem::is_directory(path)) | |
358 { | |
359 throw OrthancException(ErrorCode_DirectoryOverFile); | |
360 } | |
361 } | |
362 else | |
363 { | |
364 if (!boost::filesystem::create_directories(path)) | |
365 { | |
366 throw OrthancException(ErrorCode_MakeDirectory); | |
367 } | |
368 } | |
369 } | |
370 | |
371 | |
372 bool SystemToolbox::IsExistingFile(const std::string& path) | |
373 { | |
374 return boost::filesystem::exists(path); | |
375 } | |
376 | |
377 | |
378 #if defined(_WIN32) | |
379 static std::string GetPathToExecutableInternal() | |
380 { | |
381 // Yes, this is ugly, but there is no simple way to get the | |
382 // required buffer size, so we use a big constant | |
383 std::vector<char> buffer(32768); | |
384 /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1)); | |
385 return std::string(&buffer[0]); | |
386 } | |
387 | |
388 #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) | |
389 static std::string GetPathToExecutableInternal() | |
390 { | |
391 // NOTE: For FreeBSD, using KERN_PROC_PATHNAME might be a better alternative | |
392 | |
393 std::vector<char> buffer(PATH_MAX + 1); | |
394 ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); | |
395 if (bytes == 0) | |
396 { | |
397 throw OrthancException(ErrorCode_PathToExecutable); | |
398 } | |
399 | |
400 return std::string(&buffer[0]); | |
401 } | |
402 | |
403 #elif defined(__APPLE__) && defined(__MACH__) | |
404 static std::string GetPathToExecutableInternal() | |
405 { | |
406 char pathbuf[PATH_MAX + 1]; | |
407 unsigned int bufsize = static_cast<int>(sizeof(pathbuf)); | |
408 | |
409 _NSGetExecutablePath( pathbuf, &bufsize); | |
410 | |
411 return std::string(pathbuf); | |
412 } | |
413 | |
414 #elif defined(__OpenBSD__) | |
415 static std::string GetPathToExecutableInternal() | |
416 { | |
417 // This is an adapted version of the patch proposed in issue #64 | |
418 // without an explicit call to "malloc()" to prevent memory leak | |
419 // https://bitbucket.org/sjodogne/orthanc/issues/64/add-openbsd-support | |
420 // https://stackoverflow.com/q/31494901/881731 | |
421 | |
422 const int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; | |
423 | |
424 size_t len; | |
425 if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1) | |
426 { | |
427 throw OrthancException(ErrorCode_PathToExecutable); | |
428 } | |
429 | |
430 std::string tmp; | |
431 tmp.resize(len); | |
432 | |
433 char** buffer = reinterpret_cast<char**>(&tmp[0]); | |
434 | |
435 if (sysctl(mib, 4, buffer, &len, NULL, 0) == -1) | |
436 { | |
437 throw OrthancException(ErrorCode_PathToExecutable); | |
438 } | |
439 else | |
440 { | |
441 return std::string(buffer[0]); | |
442 } | |
443 } | |
444 | |
445 #else | |
446 #error Support your platform here | |
447 #endif | |
448 | |
449 | |
450 std::string SystemToolbox::GetPathToExecutable() | |
451 { | |
452 boost::filesystem::path p(GetPathToExecutableInternal()); | |
453 return boost::filesystem::absolute(p).string(); | |
454 } | |
455 | |
456 | |
457 std::string SystemToolbox::GetDirectoryOfExecutable() | |
458 { | |
459 boost::filesystem::path p(GetPathToExecutableInternal()); | |
460 return boost::filesystem::absolute(p.parent_path()).string(); | |
461 } | |
462 | |
463 | |
464 void SystemToolbox::ExecuteSystemCommand(const std::string& command, | |
465 const std::vector<std::string>& arguments) | |
466 { | |
467 // Convert the arguments as a C array | |
468 std::vector<char*> args(arguments.size() + 2); | |
469 | |
470 args.front() = const_cast<char*>(command.c_str()); | |
471 | |
472 for (size_t i = 0; i < arguments.size(); i++) | |
473 { | |
474 args[i + 1] = const_cast<char*>(arguments[i].c_str()); | |
475 } | |
476 | |
477 args.back() = NULL; | |
478 | |
479 int status; | |
480 | |
481 #if defined(_WIN32) | |
482 // http://msdn.microsoft.com/en-us/library/275khfab.aspx | |
483 status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); | |
484 | |
485 #else | |
486 int pid = fork(); | |
487 | |
488 if (pid == -1) | |
489 { | |
490 // Error in fork() | |
491 throw OrthancException(ErrorCode_SystemCommand, "Cannot fork a child process"); | |
492 } | |
493 else if (pid == 0) | |
494 { | |
495 // Execute the system command in the child process | |
496 execvp(command.c_str(), &args[0]); | |
497 | |
498 // We should never get here | |
499 _exit(1); | |
500 } | |
501 else | |
502 { | |
503 // Wait for the system command to exit | |
504 waitpid(pid, &status, 0); | |
505 } | |
506 #endif | |
507 | |
508 if (status != 0) | |
509 { | |
510 throw OrthancException(ErrorCode_SystemCommand, | |
511 "System command failed with status code " + | |
512 boost::lexical_cast<std::string>(status)); | |
513 } | |
514 } | |
515 | |
516 | |
517 int SystemToolbox::GetProcessId() | |
518 { | |
519 #if defined(_WIN32) | |
520 return static_cast<int>(_getpid()); | |
521 #else | |
522 return static_cast<int>(getpid()); | |
523 #endif | |
524 } | |
525 | |
526 | |
527 bool SystemToolbox::IsRegularFile(const std::string& path) | |
528 { | |
529 namespace fs = boost::filesystem; | |
530 | |
531 try | |
532 { | |
533 if (fs::exists(path)) | |
534 { | |
535 fs::file_status status = fs::status(path); | |
536 return (status.type() == boost::filesystem::regular_file || | |
537 status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 | |
538 } | |
539 } | |
540 catch (fs::filesystem_error&) | |
541 { | |
542 } | |
543 | |
544 return false; | |
545 } | |
546 | |
547 | |
548 FILE* SystemToolbox::OpenFile(const std::string& path, | |
549 FileMode mode) | |
550 { | |
551 #if defined(_WIN32) | |
552 // TODO Deal with special characters by converting to the current locale | |
553 #endif | |
554 | |
555 const char* m; | |
556 switch (mode) | |
557 { | |
558 case FileMode_ReadBinary: | |
559 m = "rb"; | |
560 break; | |
561 | |
562 case FileMode_WriteBinary: | |
563 m = "wb"; | |
564 break; | |
565 | |
566 default: | |
567 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
568 } | |
569 | |
570 return fopen(path.c_str(), m); | |
571 } | |
572 | |
573 | |
574 static boost::posix_time::ptime GetNow(bool utc) | |
575 { | |
576 if (utc) | |
577 { | |
578 return boost::posix_time::second_clock::universal_time(); | |
579 } | |
580 else | |
581 { | |
582 return boost::posix_time::second_clock::local_time(); | |
583 } | |
584 } | |
585 | |
586 | |
587 std::string SystemToolbox::GetNowIsoString(bool utc) | |
588 { | |
589 return boost::posix_time::to_iso_string(GetNow(utc)); | |
590 } | |
591 | |
592 | |
593 void SystemToolbox::GetNowDicom(std::string& date, | |
594 std::string& time, | |
595 bool utc) | |
596 { | |
597 boost::posix_time::ptime now = GetNow(utc); | |
598 tm tm = boost::posix_time::to_tm(now); | |
599 | |
600 char s[32]; | |
601 sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | |
602 date.assign(s); | |
603 | |
604 // TODO milliseconds | |
605 sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); | |
606 time.assign(s); | |
607 } | |
608 | |
609 | |
610 unsigned int SystemToolbox::GetHardwareConcurrency() | |
611 { | |
612 // Get the number of available hardware threads (e.g. number of | |
613 // CPUs or cores or hyperthreading units) | |
614 unsigned int threads = boost::thread::hardware_concurrency(); | |
615 | |
616 if (threads <= 0) | |
617 { | |
618 return 1; | |
619 } | |
620 else | |
621 { | |
622 return threads; | |
623 } | |
624 } | |
625 | |
626 | |
627 MimeType SystemToolbox::AutodetectMimeType(const std::string& path) | |
628 { | |
629 std::string extension = boost::filesystem::extension(path); | |
630 Toolbox::ToLowerCase(extension); | |
631 | |
632 // http://en.wikipedia.org/wiki/Mime_types | |
633 // Text types | |
634 if (extension == ".txt") | |
635 { | |
636 return MimeType_PlainText; | |
637 } | |
638 else if (extension == ".html") | |
639 { | |
640 return MimeType_Html; | |
641 } | |
642 else if (extension == ".xml") | |
643 { | |
644 return MimeType_Xml; | |
645 } | |
646 else if (extension == ".css") | |
647 { | |
648 return MimeType_Css; | |
649 } | |
650 | |
651 // Application types | |
652 else if (extension == ".js") | |
653 { | |
654 return MimeType_JavaScript; | |
655 } | |
656 else if (extension == ".json" || | |
657 extension == ".nmf" /* manifest */) | |
658 { | |
659 return MimeType_Json; | |
660 } | |
661 else if (extension == ".pdf") | |
662 { | |
663 return MimeType_Pdf; | |
664 } | |
665 else if (extension == ".wasm") | |
666 { | |
667 return MimeType_WebAssembly; | |
668 } | |
669 else if (extension == ".nexe") | |
670 { | |
671 return MimeType_NaCl; | |
672 } | |
673 else if (extension == ".pexe") | |
674 { | |
675 return MimeType_PNaCl; | |
676 } | |
677 | |
678 // Images types | |
679 else if (extension == ".jpg" || | |
680 extension == ".jpeg") | |
681 { | |
682 return MimeType_Jpeg; | |
683 } | |
684 else if (extension == ".gif") | |
685 { | |
686 return MimeType_Gif; | |
687 } | |
688 else if (extension == ".png") | |
689 { | |
690 return MimeType_Png; | |
691 } | |
692 else if (extension == ".pam") | |
693 { | |
694 return MimeType_Pam; | |
695 } | |
696 else if (extension == ".svg") | |
697 { | |
698 return MimeType_Svg; | |
699 } | |
700 | |
701 // Various types | |
702 else if (extension == ".woff") | |
703 { | |
704 return MimeType_Woff; | |
705 } | |
706 else if (extension == ".woff2") | |
707 { | |
708 return MimeType_Woff2; | |
709 } | |
710 | |
711 // Default type | |
712 else | |
713 { | |
714 LOG(INFO) << "Unknown MIME type for extension \"" << extension << "\""; | |
715 return MimeType_Binary; | |
716 } | |
717 } | |
718 | |
719 | |
720 void SystemToolbox::GetEnvironmentVariables(std::map<std::string, std::string>& env) | |
721 { | |
722 env.clear(); | |
723 | |
724 for (char **p = environ; *p != NULL; p++) | |
725 { | |
726 std::string v(*p); | |
727 size_t pos = v.find('='); | |
728 | |
729 if (pos != std::string::npos) | |
730 { | |
731 std::string key = v.substr(0, pos); | |
732 std::string value = v.substr(pos + 1); | |
733 env[key] = value; | |
734 } | |
735 } | |
736 } | |
737 | |
738 | |
739 std::string SystemToolbox::InterpretRelativePath(const std::string& baseDirectory, | |
740 const std::string& relativePath) | |
741 { | |
742 boost::filesystem::path base(baseDirectory); | |
743 boost::filesystem::path relative(relativePath); | |
744 | |
745 /** | |
746 The following lines should be equivalent to this one: | |
747 | |
748 return (base / relative).string(); | |
749 | |
750 However, for some unknown reason, some versions of Boost do not | |
751 make the proper path resolution when "baseDirectory" is an | |
752 absolute path. So, a hack is used below. | |
753 **/ | |
754 | |
755 if (relative.is_absolute()) | |
756 { | |
757 return relative.string(); | |
758 } | |
759 else | |
760 { | |
761 return (base / relative).string(); | |
762 } | |
763 } | |
764 } |