comparison Core/Toolbox.cpp @ 2140:aa4b8895cd23

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 Nov 2016 16:12:47 +0100
parents 595cf22b3e7e
children a260a8ad83f1
comparison
equal deleted inserted replaced
2139:764c9157301b 2140:aa4b8895cd23
121 #error Support your platform here 121 #error Support your platform here
122 #endif 122 #endif
123 } 123 }
124 124
125 125
126 #if ORTHANC_SANDBOXED == 0
127 static bool finish_;
128 static ServerBarrierEvent barrierEvent_;
129
130 #if defined(_WIN32)
131 static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
132 {
133 // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
134 finish_ = true;
135 return true;
136 }
137 #else
138 static void SignalHandler(int signal)
139 {
140 if (signal == SIGHUP)
141 {
142 barrierEvent_ = ServerBarrierEvent_Reload;
143 }
144
145 finish_ = true;
146 }
147 #endif
148
149
150 static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
151 {
152 #if defined(_WIN32)
153 SetConsoleCtrlHandler(ConsoleControlHandler, true);
154 #else
155 signal(SIGINT, SignalHandler);
156 signal(SIGQUIT, SignalHandler);
157 signal(SIGTERM, SignalHandler);
158 signal(SIGHUP, SignalHandler);
159 #endif
160
161 // Active loop that awakens every 100ms
162 finish_ = false;
163 barrierEvent_ = ServerBarrierEvent_Stop;
164 while (!(*stopFlag || finish_))
165 {
166 Toolbox::USleep(100 * 1000);
167 }
168
169 #if defined(_WIN32)
170 SetConsoleCtrlHandler(ConsoleControlHandler, false);
171 #else
172 signal(SIGINT, NULL);
173 signal(SIGQUIT, NULL);
174 signal(SIGTERM, NULL);
175 signal(SIGHUP, NULL);
176 #endif
177
178 return barrierEvent_;
179 }
180
181
182 ServerBarrierEvent Toolbox::ServerBarrier(const bool& stopFlag)
183 {
184 return ServerBarrierInternal(&stopFlag);
185 }
186
187 ServerBarrierEvent Toolbox::ServerBarrier()
188 {
189 const bool stopFlag = false;
190 return ServerBarrierInternal(&stopFlag);
191 }
192 #endif /* ORTHANC_SANDBOXED */
193
194
195 void Toolbox::ToUpperCase(std::string& s) 126 void Toolbox::ToUpperCase(std::string& s)
196 { 127 {
197 std::transform(s.begin(), s.end(), s.begin(), toupper); 128 std::transform(s.begin(), s.end(), s.begin(), toupper);
198 } 129 }
199 130
215 const std::string& source) 146 const std::string& source)
216 { 147 {
217 result = source; 148 result = source;
218 ToLowerCase(result); 149 ToLowerCase(result);
219 } 150 }
220
221
222 static std::streamsize GetStreamSize(std::istream& f)
223 {
224 // http://www.cplusplus.com/reference/iostream/istream/tellg/
225 f.seekg(0, std::ios::end);
226 std::streamsize size = f.tellg();
227 f.seekg(0, std::ios::beg);
228
229 return size;
230 }
231
232
233 #if ORTHANC_SANDBOXED == 0
234 void Toolbox::ReadFile(std::string& content,
235 const std::string& path)
236 {
237 if (!IsRegularFile(path))
238 {
239 LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
240 throw OrthancException(ErrorCode_RegularFileExpected);
241 }
242
243 boost::filesystem::ifstream f;
244 f.open(path, std::ifstream::in | std::ifstream::binary);
245 if (!f.good())
246 {
247 throw OrthancException(ErrorCode_InexistentFile);
248 }
249
250 std::streamsize size = GetStreamSize(f);
251 content.resize(size);
252 if (size != 0)
253 {
254 f.read(reinterpret_cast<char*>(&content[0]), size);
255 }
256
257 f.close();
258 }
259 #endif
260
261
262 #if ORTHANC_SANDBOXED == 0
263 bool Toolbox::ReadHeader(std::string& header,
264 const std::string& path,
265 size_t headerSize)
266 {
267 if (!IsRegularFile(path))
268 {
269 LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
270 throw OrthancException(ErrorCode_RegularFileExpected);
271 }
272
273 boost::filesystem::ifstream f;
274 f.open(path, std::ifstream::in | std::ifstream::binary);
275 if (!f.good())
276 {
277 throw OrthancException(ErrorCode_InexistentFile);
278 }
279
280 bool full = true;
281
282 {
283 std::streamsize size = GetStreamSize(f);
284 if (size <= 0)
285 {
286 headerSize = 0;
287 full = false;
288 }
289 else if (static_cast<size_t>(size) < headerSize)
290 {
291 headerSize = size; // Truncate to the size of the file
292 full = false;
293 }
294 }
295
296 header.resize(headerSize);
297 if (headerSize != 0)
298 {
299 f.read(reinterpret_cast<char*>(&header[0]), headerSize);
300 }
301
302 f.close();
303
304 return full;
305 }
306 #endif
307
308
309 #if ORTHANC_SANDBOXED == 0
310 void Toolbox::WriteFile(const void* content,
311 size_t size,
312 const std::string& path)
313 {
314 boost::filesystem::ofstream f;
315 f.open(path, std::ofstream::out | std::ofstream::binary);
316 if (!f.good())
317 {
318 throw OrthancException(ErrorCode_CannotWriteFile);
319 }
320
321 if (size != 0)
322 {
323 f.write(reinterpret_cast<const char*>(content), size);
324
325 if (!f.good())
326 {
327 f.close();
328 throw OrthancException(ErrorCode_FileStorageCannotWrite);
329 }
330 }
331
332 f.close();
333 }
334 #endif
335
336
337 #if ORTHANC_SANDBOXED == 0
338 void Toolbox::WriteFile(const std::string& content,
339 const std::string& path)
340 {
341 WriteFile(content.size() > 0 ? content.c_str() : NULL,
342 content.size(), path);
343 }
344 #endif
345
346
347 #if ORTHANC_SANDBOXED == 0
348 void Toolbox::RemoveFile(const std::string& path)
349 {
350 if (boost::filesystem::exists(path))
351 {
352 if (IsRegularFile(path))
353 {
354 boost::filesystem::remove(path);
355 }
356 else
357 {
358 throw OrthancException(ErrorCode_RegularFileExpected);
359 }
360 }
361 }
362 #endif
363 151
364 152
365 void Toolbox::SplitUriComponents(UriComponents& components, 153 void Toolbox::SplitUriComponents(UriComponents& components,
366 const std::string& uri) 154 const std::string& uri)
367 { 155 {
527 return r; 315 return r;
528 } 316 }
529 } 317 }
530 318
531 319
532
533 #if ORTHANC_SANDBOXED == 0
534 uint64_t Toolbox::GetFileSize(const std::string& path)
535 {
536 try
537 {
538 return static_cast<uint64_t>(boost::filesystem::file_size(path));
539 }
540 catch (boost::filesystem::filesystem_error&)
541 {
542 throw OrthancException(ErrorCode_InexistentFile);
543 }
544 }
545 #endif
546
547
548 #if ORTHANC_ENABLE_MD5 == 1 320 #if ORTHANC_ENABLE_MD5 == 1
549 static char GetHexadecimalCharacter(uint8_t value) 321 static char GetHexadecimalCharacter(uint8_t value)
550 { 322 {
551 assert(value < 16); 323 assert(value < 16);
552 324
656 const std::string& content) 428 const std::string& content)
657 { 429 {
658 result = "data:" + mime + ";base64," + base64_encode(content); 430 result = "data:" + mime + ";base64," + base64_encode(content);
659 } 431 }
660 432
661 #endif
662
663
664
665 #if defined(_WIN32)
666 static std::string GetPathToExecutableInternal()
667 {
668 // Yes, this is ugly, but there is no simple way to get the
669 // required buffer size, so we use a big constant
670 std::vector<char> buffer(32768);
671 /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
672 return std::string(&buffer[0]);
673 }
674
675 #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
676 static std::string GetPathToExecutableInternal()
677 {
678 std::vector<char> buffer(PATH_MAX + 1);
679 ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
680 if (bytes == 0)
681 {
682 throw OrthancException(ErrorCode_PathToExecutable);
683 }
684
685 return std::string(&buffer[0]);
686 }
687
688 #elif defined(__APPLE__) && defined(__MACH__)
689 static std::string GetPathToExecutableInternal()
690 {
691 char pathbuf[PATH_MAX + 1];
692 unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
693
694 _NSGetExecutablePath( pathbuf, &bufsize);
695
696 return std::string(pathbuf);
697 }
698
699 #elif ORTHANC_SANDBOXED == 1
700 // Sandboxed Orthanc, no access to the executable
701
702 #else
703 #error Support your platform here
704 #endif
705
706
707 #if ORTHANC_SANDBOXED == 0
708 std::string Toolbox::GetPathToExecutable()
709 {
710 boost::filesystem::path p(GetPathToExecutableInternal());
711 return boost::filesystem::absolute(p).string();
712 }
713
714
715 std::string Toolbox::GetDirectoryOfExecutable()
716 {
717 boost::filesystem::path p(GetPathToExecutableInternal());
718 return boost::filesystem::absolute(p.parent_path()).string();
719 }
720 #endif 433 #endif
721 434
722 435
723 static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding) 436 static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
724 { 437 {
993 else 706 else
994 { 707 {
995 return IsSHA1(s.c_str(), s.size()); 708 return IsSHA1(s.c_str(), s.size());
996 } 709 }
997 } 710 }
998
999
1000 #if BOOST_HAS_DATE_TIME == 1
1001 std::string Toolbox::GetNowIsoString()
1002 {
1003 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
1004 return boost::posix_time::to_iso_string(now);
1005 }
1006
1007 void Toolbox::GetNowDicom(std::string& date,
1008 std::string& time)
1009 {
1010 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
1011 tm tm = boost::posix_time::to_tm(now);
1012
1013 char s[32];
1014 sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
1015 date.assign(s);
1016
1017 // TODO milliseconds
1018 sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
1019 time.assign(s);
1020 }
1021 #endif
1022 711
1023 712
1024 std::string Toolbox::StripSpaces(const std::string& source) 713 std::string Toolbox::StripSpaces(const std::string& source)
1025 { 714 {
1026 size_t first = 0; 715 size_t first = 0;
1176 865
1177 result.push_back(currentItem); 866 result.push_back(currentItem);
1178 } 867 }
1179 868
1180 869
1181 #if ORTHANC_SANDBOXED == 0
1182 void Toolbox::MakeDirectory(const std::string& path)
1183 {
1184 if (boost::filesystem::exists(path))
1185 {
1186 if (!boost::filesystem::is_directory(path))
1187 {
1188 throw OrthancException(ErrorCode_DirectoryOverFile);
1189 }
1190 }
1191 else
1192 {
1193 if (!boost::filesystem::create_directories(path))
1194 {
1195 throw OrthancException(ErrorCode_MakeDirectory);
1196 }
1197 }
1198 }
1199 #endif
1200
1201
1202 #if ORTHANC_SANDBOXED == 0
1203 bool Toolbox::IsExistingFile(const std::string& path)
1204 {
1205 return boost::filesystem::exists(path);
1206 }
1207 #endif
1208
1209
1210 #if ORTHANC_ENABLE_PUGIXML == 1 870 #if ORTHANC_ENABLE_PUGIXML == 1
1211 class ChunkedBufferWriter : public pugi::xml_writer 871 class ChunkedBufferWriter : public pugi::xml_writer
1212 { 872 {
1213 private: 873 private:
1214 ChunkedBuffer buffer_; 874 ChunkedBuffer buffer_;
1326 writer.Flatten(target); 986 writer.Flatten(target);
1327 } 987 }
1328 988
1329 #endif 989 #endif
1330 990
1331
1332 #if ORTHANC_SANDBOXED == 0
1333 void Toolbox::ExecuteSystemCommand(const std::string& command,
1334 const std::vector<std::string>& arguments)
1335 {
1336 // Convert the arguments as a C array
1337 std::vector<char*> args(arguments.size() + 2);
1338
1339 args.front() = const_cast<char*>(command.c_str());
1340
1341 for (size_t i = 0; i < arguments.size(); i++)
1342 {
1343 args[i + 1] = const_cast<char*>(arguments[i].c_str());
1344 }
1345
1346 args.back() = NULL;
1347
1348 int status;
1349
1350 #if defined(_WIN32)
1351 // http://msdn.microsoft.com/en-us/library/275khfab.aspx
1352 status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
1353
1354 #else
1355 int pid = fork();
1356
1357 if (pid == -1)
1358 {
1359 // Error in fork()
1360 #if ORTHANC_ENABLE_LOGGING == 1
1361 LOG(ERROR) << "Cannot fork a child process";
1362 #endif
1363
1364 throw OrthancException(ErrorCode_SystemCommand);
1365 }
1366 else if (pid == 0)
1367 {
1368 // Execute the system command in the child process
1369 execvp(command.c_str(), &args[0]);
1370
1371 // We should never get here
1372 _exit(1);
1373 }
1374 else
1375 {
1376 // Wait for the system command to exit
1377 waitpid(pid, &status, 0);
1378 }
1379 #endif
1380
1381 if (status != 0)
1382 {
1383 #if ORTHANC_ENABLE_LOGGING == 1
1384 LOG(ERROR) << "System command failed with status code " << status;
1385 #endif
1386
1387 throw OrthancException(ErrorCode_SystemCommand);
1388 }
1389 }
1390 #endif
1391 991
1392 992
1393 bool Toolbox::IsInteger(const std::string& str) 993 bool Toolbox::IsInteger(const std::string& str)
1394 { 994 {
1395 std::string s = StripSpaces(str); 995 std::string s = StripSpaces(str);
1494 else 1094 else
1495 { 1095 {
1496 return str.compare(0, prefix.size(), prefix) == 0; 1096 return str.compare(0, prefix.size(), prefix) == 0;
1497 } 1097 }
1498 } 1098 }
1499
1500
1501 #if ORTHANC_SANDBOXED == 0
1502 int Toolbox::GetProcessId()
1503 {
1504 #if defined(_WIN32)
1505 return static_cast<int>(_getpid());
1506 #else
1507 return static_cast<int>(getpid());
1508 #endif
1509 }
1510 #endif
1511
1512
1513 #if ORTHANC_SANDBOXED == 0
1514 bool Toolbox::IsRegularFile(const std::string& path)
1515 {
1516 namespace fs = boost::filesystem;
1517
1518 try
1519 {
1520 if (fs::exists(path))
1521 {
1522 fs::file_status status = fs::status(path);
1523 return (status.type() == boost::filesystem::regular_file ||
1524 status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
1525 }
1526 }
1527 catch (fs::filesystem_error&)
1528 {
1529 }
1530
1531 return false;
1532 }
1533 #endif
1534
1535
1536 FILE* Toolbox::OpenFile(const std::string& path,
1537 FileMode mode)
1538 {
1539 #if defined(_WIN32)
1540 // TODO Deal with special characters by converting to the current locale
1541 #endif
1542
1543 const char* m;
1544 switch (mode)
1545 {
1546 case FileMode_ReadBinary:
1547 m = "rb";
1548 break;
1549
1550 case FileMode_WriteBinary:
1551 m = "wb";
1552 break;
1553
1554 default:
1555 throw OrthancException(ErrorCode_ParameterOutOfRange);
1556 }
1557
1558 return fopen(path.c_str(), m);
1559 }
1560
1561 1099
1562 1100
1563 static bool IsUnreservedCharacter(char c) 1101 static bool IsUnreservedCharacter(char c)
1564 { 1102 {
1565 // This function checks whether "c" is an unserved character 1103 // This function checks whether "c" is an unserved character
1696 else 1234 else
1697 { 1235 {
1698 return static_cast<unsigned int>(v); 1236 return static_cast<unsigned int>(v);
1699 } 1237 }
1700 } 1238 }
1239
1240
1241 #if ORTHANC_SANDBOXED == 0
1242
1243 static bool finish_;
1244 static ServerBarrierEvent barrierEvent_;
1245
1246 #if defined(_WIN32)
1247 static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
1248 {
1249 // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
1250 finish_ = true;
1251 return true;
1252 }
1253 #else
1254 static void SignalHandler(int signal)
1255 {
1256 if (signal == SIGHUP)
1257 {
1258 barrierEvent_ = ServerBarrierEvent_Reload;
1259 }
1260
1261 finish_ = true;
1262 }
1263 #endif
1264
1265
1266 static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
1267 {
1268 #if defined(_WIN32)
1269 SetConsoleCtrlHandler(ConsoleControlHandler, true);
1270 #else
1271 signal(SIGINT, SignalHandler);
1272 signal(SIGQUIT, SignalHandler);
1273 signal(SIGTERM, SignalHandler);
1274 signal(SIGHUP, SignalHandler);
1275 #endif
1276
1277 // Active loop that awakens every 100ms
1278 finish_ = false;
1279 barrierEvent_ = ServerBarrierEvent_Stop;
1280 while (!(*stopFlag || finish_))
1281 {
1282 Toolbox::USleep(100 * 1000);
1283 }
1284
1285 #if defined(_WIN32)
1286 SetConsoleCtrlHandler(ConsoleControlHandler, false);
1287 #else
1288 signal(SIGINT, NULL);
1289 signal(SIGQUIT, NULL);
1290 signal(SIGTERM, NULL);
1291 signal(SIGHUP, NULL);
1292 #endif
1293
1294 return barrierEvent_;
1295 }
1296
1297
1298 ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag)
1299 {
1300 return ServerBarrierInternal(&stopFlag);
1301 }
1302
1303
1304 ServerBarrierEvent SystemToolbox::ServerBarrier()
1305 {
1306 const bool stopFlag = false;
1307 return ServerBarrierInternal(&stopFlag);
1308 }
1309
1310
1311 static std::streamsize GetStreamSize(std::istream& f)
1312 {
1313 // http://www.cplusplus.com/reference/iostream/istream/tellg/
1314 f.seekg(0, std::ios::end);
1315 std::streamsize size = f.tellg();
1316 f.seekg(0, std::ios::beg);
1317
1318 return size;
1319 }
1320
1321
1322 void SystemToolbox::ReadFile(std::string& content,
1323 const std::string& path)
1324 {
1325 if (!IsRegularFile(path))
1326 {
1327 LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
1328 throw OrthancException(ErrorCode_RegularFileExpected);
1329 }
1330
1331 boost::filesystem::ifstream f;
1332 f.open(path, std::ifstream::in | std::ifstream::binary);
1333 if (!f.good())
1334 {
1335 throw OrthancException(ErrorCode_InexistentFile);
1336 }
1337
1338 std::streamsize size = GetStreamSize(f);
1339 content.resize(size);
1340 if (size != 0)
1341 {
1342 f.read(reinterpret_cast<char*>(&content[0]), size);
1343 }
1344
1345 f.close();
1346 }
1347
1348
1349 bool SystemToolbox::ReadHeader(std::string& header,
1350 const std::string& path,
1351 size_t headerSize)
1352 {
1353 if (!IsRegularFile(path))
1354 {
1355 LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
1356 throw OrthancException(ErrorCode_RegularFileExpected);
1357 }
1358
1359 boost::filesystem::ifstream f;
1360 f.open(path, std::ifstream::in | std::ifstream::binary);
1361 if (!f.good())
1362 {
1363 throw OrthancException(ErrorCode_InexistentFile);
1364 }
1365
1366 bool full = true;
1367
1368 {
1369 std::streamsize size = GetStreamSize(f);
1370 if (size <= 0)
1371 {
1372 headerSize = 0;
1373 full = false;
1374 }
1375 else if (static_cast<size_t>(size) < headerSize)
1376 {
1377 headerSize = size; // Truncate to the size of the file
1378 full = false;
1379 }
1380 }
1381
1382 header.resize(headerSize);
1383 if (headerSize != 0)
1384 {
1385 f.read(reinterpret_cast<char*>(&header[0]), headerSize);
1386 }
1387
1388 f.close();
1389
1390 return full;
1391 }
1392
1393
1394 void SystemToolbox::WriteFile(const void* content,
1395 size_t size,
1396 const std::string& path)
1397 {
1398 boost::filesystem::ofstream f;
1399 f.open(path, std::ofstream::out | std::ofstream::binary);
1400 if (!f.good())
1401 {
1402 throw OrthancException(ErrorCode_CannotWriteFile);
1403 }
1404
1405 if (size != 0)
1406 {
1407 f.write(reinterpret_cast<const char*>(content), size);
1408
1409 if (!f.good())
1410 {
1411 f.close();
1412 throw OrthancException(ErrorCode_FileStorageCannotWrite);
1413 }
1414 }
1415
1416 f.close();
1417 }
1418
1419
1420 void SystemToolbox::WriteFile(const std::string& content,
1421 const std::string& path)
1422 {
1423 WriteFile(content.size() > 0 ? content.c_str() : NULL,
1424 content.size(), path);
1425 }
1426
1427
1428 void SystemToolbox::RemoveFile(const std::string& path)
1429 {
1430 if (boost::filesystem::exists(path))
1431 {
1432 if (IsRegularFile(path))
1433 {
1434 boost::filesystem::remove(path);
1435 }
1436 else
1437 {
1438 throw OrthancException(ErrorCode_RegularFileExpected);
1439 }
1440 }
1441 }
1442
1443
1444 uint64_t SystemToolbox::GetFileSize(const std::string& path)
1445 {
1446 try
1447 {
1448 return static_cast<uint64_t>(boost::filesystem::file_size(path));
1449 }
1450 catch (boost::filesystem::filesystem_error&)
1451 {
1452 throw OrthancException(ErrorCode_InexistentFile);
1453 }
1454 }
1455
1456
1457 void SystemToolbox::MakeDirectory(const std::string& path)
1458 {
1459 if (boost::filesystem::exists(path))
1460 {
1461 if (!boost::filesystem::is_directory(path))
1462 {
1463 throw OrthancException(ErrorCode_DirectoryOverFile);
1464 }
1465 }
1466 else
1467 {
1468 if (!boost::filesystem::create_directories(path))
1469 {
1470 throw OrthancException(ErrorCode_MakeDirectory);
1471 }
1472 }
1473 }
1474
1475
1476 bool SystemToolbox::IsExistingFile(const std::string& path)
1477 {
1478 return boost::filesystem::exists(path);
1479 }
1480
1481
1482 #if defined(_WIN32)
1483 static std::string GetPathToExecutableInternal()
1484 {
1485 // Yes, this is ugly, but there is no simple way to get the
1486 // required buffer size, so we use a big constant
1487 std::vector<char> buffer(32768);
1488 /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
1489 return std::string(&buffer[0]);
1490 }
1491
1492 #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
1493 static std::string GetPathToExecutableInternal()
1494 {
1495 std::vector<char> buffer(PATH_MAX + 1);
1496 ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
1497 if (bytes == 0)
1498 {
1499 throw OrthancException(ErrorCode_PathToExecutable);
1500 }
1501
1502 return std::string(&buffer[0]);
1503 }
1504
1505 #elif defined(__APPLE__) && defined(__MACH__)
1506 static std::string GetPathToExecutableInternal()
1507 {
1508 char pathbuf[PATH_MAX + 1];
1509 unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
1510
1511 _NSGetExecutablePath( pathbuf, &bufsize);
1512
1513 return std::string(pathbuf);
1514 }
1515
1516 #else
1517 #error Support your platform here
1518 #endif
1519
1520
1521 std::string SystemToolbox::GetPathToExecutable()
1522 {
1523 boost::filesystem::path p(GetPathToExecutableInternal());
1524 return boost::filesystem::absolute(p).string();
1525 }
1526
1527
1528 std::string SystemToolbox::GetDirectoryOfExecutable()
1529 {
1530 boost::filesystem::path p(GetPathToExecutableInternal());
1531 return boost::filesystem::absolute(p.parent_path()).string();
1532 }
1533
1534
1535 void SystemToolbox::ExecuteSystemCommand(const std::string& command,
1536 const std::vector<std::string>& arguments)
1537 {
1538 // Convert the arguments as a C array
1539 std::vector<char*> args(arguments.size() + 2);
1540
1541 args.front() = const_cast<char*>(command.c_str());
1542
1543 for (size_t i = 0; i < arguments.size(); i++)
1544 {
1545 args[i + 1] = const_cast<char*>(arguments[i].c_str());
1546 }
1547
1548 args.back() = NULL;
1549
1550 int status;
1551
1552 #if defined(_WIN32)
1553 // http://msdn.microsoft.com/en-us/library/275khfab.aspx
1554 status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
1555
1556 #else
1557 int pid = fork();
1558
1559 if (pid == -1)
1560 {
1561 // Error in fork()
1562 #if ORTHANC_ENABLE_LOGGING == 1
1563 LOG(ERROR) << "Cannot fork a child process";
1564 #endif
1565
1566 throw OrthancException(ErrorCode_SystemCommand);
1567 }
1568 else if (pid == 0)
1569 {
1570 // Execute the system command in the child process
1571 execvp(command.c_str(), &args[0]);
1572
1573 // We should never get here
1574 _exit(1);
1575 }
1576 else
1577 {
1578 // Wait for the system command to exit
1579 waitpid(pid, &status, 0);
1580 }
1581 #endif
1582
1583 if (status != 0)
1584 {
1585 #if ORTHANC_ENABLE_LOGGING == 1
1586 LOG(ERROR) << "System command failed with status code " << status;
1587 #endif
1588
1589 throw OrthancException(ErrorCode_SystemCommand);
1590 }
1591 }
1592
1593
1594 int SystemToolbox::GetProcessId()
1595 {
1596 #if defined(_WIN32)
1597 return static_cast<int>(_getpid());
1598 #else
1599 return static_cast<int>(getpid());
1600 #endif
1601 }
1602
1603
1604 bool SystemToolbox::IsRegularFile(const std::string& path)
1605 {
1606 namespace fs = boost::filesystem;
1607
1608 try
1609 {
1610 if (fs::exists(path))
1611 {
1612 fs::file_status status = fs::status(path);
1613 return (status.type() == boost::filesystem::regular_file ||
1614 status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
1615 }
1616 }
1617 catch (fs::filesystem_error&)
1618 {
1619 }
1620
1621 return false;
1622 }
1623
1624
1625 FILE* SystemToolbox::OpenFile(const std::string& path,
1626 FileMode mode)
1627 {
1628 #if defined(_WIN32)
1629 // TODO Deal with special characters by converting to the current locale
1630 #endif
1631
1632 const char* m;
1633 switch (mode)
1634 {
1635 case FileMode_ReadBinary:
1636 m = "rb";
1637 break;
1638
1639 case FileMode_WriteBinary:
1640 m = "wb";
1641 break;
1642
1643 default:
1644 throw OrthancException(ErrorCode_ParameterOutOfRange);
1645 }
1646
1647 return fopen(path.c_str(), m);
1648 }
1649
1650
1651 #if BOOST_HAS_DATE_TIME == 1
1652 std::string SystemToolbox::GetNowIsoString()
1653 {
1654 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
1655 return boost::posix_time::to_iso_string(now);
1656 }
1657
1658 void SystemToolbox::GetNowDicom(std::string& date,
1659 std::string& time)
1660 {
1661 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
1662 tm tm = boost::posix_time::to_tm(now);
1663
1664 char s[32];
1665 sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
1666 date.assign(s);
1667
1668 // TODO milliseconds
1669 sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
1670 time.assign(s);
1671 }
1672 #endif
1673
1674
1675 #endif /* ORTHANC_SANDBOXED */
1701 } 1676 }