Mercurial > hg > orthanc
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 } |