Mercurial > hg > orthanc-webviewer
changeset 25:15acbf5e7545
refactoring
line wrap: on
line diff
--- a/Orthanc/ChunkedBuffer.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h" -#include "ChunkedBuffer.h" - -#include <cassert> -#include <string.h> - - -namespace Orthanc -{ - void ChunkedBuffer::Clear() - { - numBytes_ = 0; - - for (Chunks::iterator it = chunks_.begin(); - it != chunks_.end(); ++it) - { - delete *it; - } - } - - - void ChunkedBuffer::AddChunk(const char* chunkData, - size_t chunkSize) - { - if (chunkSize == 0) - { - return; - } - - assert(chunkData != NULL); - chunks_.push_back(new std::string(chunkData, chunkSize)); - numBytes_ += chunkSize; - } - - - void ChunkedBuffer::AddChunk(const std::string& chunk) - { - if (chunk.size() > 0) - { - AddChunk(&chunk[0], chunk.size()); - } - } - - - void ChunkedBuffer::Flatten(std::string& result) - { - result.resize(numBytes_); - - size_t pos = 0; - for (Chunks::iterator it = chunks_.begin(); - it != chunks_.end(); ++it) - { - assert(*it != NULL); - - size_t s = (*it)->size(); - if (s != 0) - { - memcpy(&result[pos], (*it)->c_str(), s); - pos += s; - } - - delete *it; - } - - chunks_.clear(); - } -}
--- a/Orthanc/ChunkedBuffer.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include <list> -#include <string> - -namespace Orthanc -{ - class ChunkedBuffer - { - private: - typedef std::list<std::string*> Chunks; - size_t numBytes_; - Chunks chunks_; - - void Clear(); - - public: - ChunkedBuffer() : numBytes_(0) - { - } - - ~ChunkedBuffer() - { - Clear(); - } - - size_t GetNumBytes() const - { - return numBytes_; - } - - void AddChunk(const char* chunkData, - size_t chunkSize); - - void AddChunk(const std::string& chunk); - - void Flatten(std::string& result); - }; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ChunkedBuffer.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,99 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "ChunkedBuffer.h" + +#include <cassert> +#include <string.h> + + +namespace Orthanc +{ + void ChunkedBuffer::Clear() + { + numBytes_ = 0; + + for (Chunks::iterator it = chunks_.begin(); + it != chunks_.end(); ++it) + { + delete *it; + } + } + + + void ChunkedBuffer::AddChunk(const char* chunkData, + size_t chunkSize) + { + if (chunkSize == 0) + { + return; + } + + assert(chunkData != NULL); + chunks_.push_back(new std::string(chunkData, chunkSize)); + numBytes_ += chunkSize; + } + + + void ChunkedBuffer::AddChunk(const std::string& chunk) + { + if (chunk.size() > 0) + { + AddChunk(&chunk[0], chunk.size()); + } + } + + + void ChunkedBuffer::Flatten(std::string& result) + { + result.resize(numBytes_); + + size_t pos = 0; + for (Chunks::iterator it = chunks_.begin(); + it != chunks_.end(); ++it) + { + assert(*it != NULL); + + size_t s = (*it)->size(); + if (s != 0) + { + memcpy(&result[pos], (*it)->c_str(), s); + pos += s; + } + + delete *it; + } + + chunks_.clear(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ChunkedBuffer.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,71 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <list> +#include <string> + +namespace Orthanc +{ + class ChunkedBuffer + { + private: + typedef std::list<std::string*> Chunks; + size_t numBytes_; + Chunks chunks_; + + void Clear(); + + public: + ChunkedBuffer() : numBytes_(0) + { + } + + ~ChunkedBuffer() + { + Clear(); + } + + size_t GetNumBytes() const + { + return numBytes_; + } + + void AddChunk(const char* chunkData, + size_t chunkSize); + + void AddChunk(const std::string& chunk); + + void Flatten(std::string& result); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Enumerations.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,628 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "Enumerations.h" + +#include "OrthancException.h" +#include "Toolbox.h" + +namespace Orthanc +{ + const char* EnumerationToString(HttpMethod method) + { + switch (method) + { + case HttpMethod_Get: + return "GET"; + + case HttpMethod_Post: + return "POST"; + + case HttpMethod_Delete: + return "DELETE"; + + case HttpMethod_Put: + return "PUT"; + + default: + return "?"; + } + } + + + const char* EnumerationToString(HttpStatus status) + { + switch (status) + { + case HttpStatus_100_Continue: + return "Continue"; + + case HttpStatus_101_SwitchingProtocols: + return "Switching Protocols"; + + case HttpStatus_102_Processing: + return "Processing"; + + case HttpStatus_200_Ok: + return "OK"; + + case HttpStatus_201_Created: + return "Created"; + + case HttpStatus_202_Accepted: + return "Accepted"; + + case HttpStatus_203_NonAuthoritativeInformation: + return "Non-Authoritative Information"; + + case HttpStatus_204_NoContent: + return "No Content"; + + case HttpStatus_205_ResetContent: + return "Reset Content"; + + case HttpStatus_206_PartialContent: + return "Partial Content"; + + case HttpStatus_207_MultiStatus: + return "Multi-Status"; + + case HttpStatus_208_AlreadyReported: + return "Already Reported"; + + case HttpStatus_226_IMUsed: + return "IM Used"; + + case HttpStatus_300_MultipleChoices: + return "Multiple Choices"; + + case HttpStatus_301_MovedPermanently: + return "Moved Permanently"; + + case HttpStatus_302_Found: + return "Found"; + + case HttpStatus_303_SeeOther: + return "See Other"; + + case HttpStatus_304_NotModified: + return "Not Modified"; + + case HttpStatus_305_UseProxy: + return "Use Proxy"; + + case HttpStatus_307_TemporaryRedirect: + return "Temporary Redirect"; + + case HttpStatus_400_BadRequest: + return "Bad Request"; + + case HttpStatus_401_Unauthorized: + return "Unauthorized"; + + case HttpStatus_402_PaymentRequired: + return "Payment Required"; + + case HttpStatus_403_Forbidden: + return "Forbidden"; + + case HttpStatus_404_NotFound: + return "Not Found"; + + case HttpStatus_405_MethodNotAllowed: + return "Method Not Allowed"; + + case HttpStatus_406_NotAcceptable: + return "Not Acceptable"; + + case HttpStatus_407_ProxyAuthenticationRequired: + return "Proxy Authentication Required"; + + case HttpStatus_408_RequestTimeout: + return "Request Timeout"; + + case HttpStatus_409_Conflict: + return "Conflict"; + + case HttpStatus_410_Gone: + return "Gone"; + + case HttpStatus_411_LengthRequired: + return "Length Required"; + + case HttpStatus_412_PreconditionFailed: + return "Precondition Failed"; + + case HttpStatus_413_RequestEntityTooLarge: + return "Request Entity Too Large"; + + case HttpStatus_414_RequestUriTooLong: + return "Request-URI Too Long"; + + case HttpStatus_415_UnsupportedMediaType: + return "Unsupported Media Type"; + + case HttpStatus_416_RequestedRangeNotSatisfiable: + return "Requested Range Not Satisfiable"; + + case HttpStatus_417_ExpectationFailed: + return "Expectation Failed"; + + case HttpStatus_422_UnprocessableEntity: + return "Unprocessable Entity"; + + case HttpStatus_423_Locked: + return "Locked"; + + case HttpStatus_424_FailedDependency: + return "Failed Dependency"; + + case HttpStatus_426_UpgradeRequired: + return "Upgrade Required"; + + case HttpStatus_500_InternalServerError: + return "Internal Server Error"; + + case HttpStatus_501_NotImplemented: + return "Not Implemented"; + + case HttpStatus_502_BadGateway: + return "Bad Gateway"; + + case HttpStatus_503_ServiceUnavailable: + return "Service Unavailable"; + + case HttpStatus_504_GatewayTimeout: + return "Gateway Timeout"; + + case HttpStatus_505_HttpVersionNotSupported: + return "HTTP Version Not Supported"; + + case HttpStatus_506_VariantAlsoNegotiates: + return "Variant Also Negotiates"; + + case HttpStatus_507_InsufficientStorage: + return "Insufficient Storage"; + + case HttpStatus_509_BandwidthLimitExceeded: + return "Bandwidth Limit Exceeded"; + + case HttpStatus_510_NotExtended: + return "Not Extended"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(ResourceType type) + { + switch (type) + { + case ResourceType_Patient: + return "Patient"; + + case ResourceType_Study: + return "Study"; + + case ResourceType_Series: + return "Series"; + + case ResourceType_Instance: + return "Instance"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(ImageFormat format) + { + switch (format) + { + case ImageFormat_Png: + return "Png"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(Encoding encoding) + { + switch (encoding) + { + case Encoding_Ascii: + return "Ascii"; + + case Encoding_Utf8: + return "Utf8"; + + case Encoding_Latin1: + return "Latin1"; + + case Encoding_Latin2: + return "Latin2"; + + case Encoding_Latin3: + return "Latin3"; + + case Encoding_Latin4: + return "Latin4"; + + case Encoding_Latin5: + return "Latin5"; + + case Encoding_Cyrillic: + return "Cyrillic"; + + case Encoding_Windows1251: + return "Windows1251"; + + case Encoding_Arabic: + return "Arabic"; + + case Encoding_Greek: + return "Greek"; + + case Encoding_Hebrew: + return "Hebrew"; + + case Encoding_Thai: + return "Thai"; + + case Encoding_Japanese: + return "Japanese"; + + case Encoding_Chinese: + return "Chinese"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(PhotometricInterpretation photometric) + { + switch (photometric) + { + case PhotometricInterpretation_RGB: + return "RGB"; + + case PhotometricInterpretation_Monochrome1: + return "Monochrome1"; + + case PhotometricInterpretation_Monochrome2: + return "Monochrome2"; + + case PhotometricInterpretation_ARGB: + return "ARGB"; + + case PhotometricInterpretation_CMYK: + return "CMYK"; + + case PhotometricInterpretation_HSV: + return "HSV"; + + case PhotometricInterpretation_Palette: + return "Palette color"; + + case PhotometricInterpretation_YBRFull: + return "YBR full"; + + case PhotometricInterpretation_YBRFull422: + return "YBR full 422"; + + case PhotometricInterpretation_YBRPartial420: + return "YBR partial 420"; + + case PhotometricInterpretation_YBRPartial422: + return "YBR partial 422"; + + case PhotometricInterpretation_YBR_ICT: + return "YBR ICT"; + + case PhotometricInterpretation_YBR_RCT: + return "YBR RCT"; + + case PhotometricInterpretation_Unknown: + return "Unknown"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + Encoding StringToEncoding(const char* encoding) + { + std::string s(encoding); + Toolbox::ToUpperCase(s); + + if (s == "UTF8") + { + return Encoding_Utf8; + } + + if (s == "ASCII") + { + return Encoding_Ascii; + } + + if (s == "LATIN1") + { + return Encoding_Latin1; + } + + if (s == "LATIN2") + { + return Encoding_Latin2; + } + + if (s == "LATIN3") + { + return Encoding_Latin3; + } + + if (s == "LATIN4") + { + return Encoding_Latin4; + } + + if (s == "LATIN5") + { + return Encoding_Latin5; + } + + if (s == "CYRILLIC") + { + return Encoding_Cyrillic; + } + + if (s == "WINDOWS1251") + { + return Encoding_Windows1251; + } + + if (s == "ARABIC") + { + return Encoding_Arabic; + } + + if (s == "GREEK") + { + return Encoding_Greek; + } + + if (s == "HEBREW") + { + return Encoding_Hebrew; + } + + if (s == "THAI") + { + return Encoding_Thai; + } + + if (s == "JAPANESE") + { + return Encoding_Japanese; + } + + if (s == "CHINESE") + { + return Encoding_Chinese; + } + + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + + ResourceType StringToResourceType(const char* type) + { + std::string s(type); + Toolbox::ToUpperCase(s); + + if (s == "PATIENT" || s == "PATIENTS") + { + return ResourceType_Patient; + } + else if (s == "STUDY" || s == "STUDIES") + { + return ResourceType_Study; + } + else if (s == "SERIES") + { + return ResourceType_Series; + } + else if (s == "INSTANCE" || s == "IMAGE" || + s == "INSTANCES" || s == "IMAGES") + { + return ResourceType_Instance; + } + + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + + ImageFormat StringToImageFormat(const char* format) + { + std::string s(format); + Toolbox::ToUpperCase(s); + + if (s == "PNG") + { + return ImageFormat_Png; + } + + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + + unsigned int GetBytesPerPixel(PixelFormat format) + { + switch (format) + { + case PixelFormat_Grayscale8: + return 1; + + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + return 2; + + case PixelFormat_RGB24: + return 3; + + case PixelFormat_RGBA32: + return 4; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + bool GetDicomEncoding(Encoding& encoding, + const char* specificCharacterSet) + { + std::string s = specificCharacterSet; + Toolbox::ToUpperCase(s); + + // http://www.dabsoft.ch/dicom/3/C.12.1.1.2/ + // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java + if (s == "ISO_IR 6" || + s == "ISO_IR 192" || + s == "ISO 2022 IR 6") + { + encoding = Encoding_Utf8; + } + else if (s == "ISO_IR 100" || + s == "ISO 2022 IR 100") + { + encoding = Encoding_Latin1; + } + else if (s == "ISO_IR 101" || + s == "ISO 2022 IR 101") + { + encoding = Encoding_Latin2; + } + else if (s == "ISO_IR 109" || + s == "ISO 2022 IR 109") + { + encoding = Encoding_Latin3; + } + else if (s == "ISO_IR 110" || + s == "ISO 2022 IR 110") + { + encoding = Encoding_Latin4; + } + else if (s == "ISO_IR 148" || + s == "ISO 2022 IR 148") + { + encoding = Encoding_Latin5; + } + else if (s == "ISO_IR 144" || + s == "ISO 2022 IR 144") + { + encoding = Encoding_Cyrillic; + } + else if (s == "ISO_IR 127" || + s == "ISO 2022 IR 127") + { + encoding = Encoding_Arabic; + } + else if (s == "ISO_IR 126" || + s == "ISO 2022 IR 126") + { + encoding = Encoding_Greek; + } + else if (s == "ISO_IR 138" || + s == "ISO 2022 IR 138") + { + encoding = Encoding_Hebrew; + } + else if (s == "ISO_IR 166" || s == "ISO 2022 IR 166") + { + encoding = Encoding_Thai; + } + else if (s == "ISO_IR 13" || s == "ISO 2022 IR 13") + { + encoding = Encoding_Japanese; + } + else if (s == "GB18030") + { + encoding = Encoding_Chinese; + } + /* + else if (s == "ISO 2022 IR 149") + { + TODO + } + else if (s == "ISO 2022 IR 159") + { + TODO + } + else if (s == "ISO 2022 IR 87") + { + TODO + } + */ + else + { + return false; + } + + // The encoding was properly detected + return true; + } + + + const char* GetMimeType(FileContentType type) + { + switch (type) + { + case FileContentType_Dicom: + return "application/dicom"; + + case FileContentType_DicomAsJson: + return "application/json"; + + default: + return "application/octet-stream"; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Enumerations.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,345 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +namespace Orthanc +{ + enum Endianness + { + Endianness_Unknown, + Endianness_Big, + Endianness_Little + }; + + enum ErrorCode + { + // Generic error codes + ErrorCode_Success, + ErrorCode_Custom, + ErrorCode_InternalError, + ErrorCode_NotImplemented, + ErrorCode_ParameterOutOfRange, + ErrorCode_NotEnoughMemory, + ErrorCode_BadParameterType, + ErrorCode_BadSequenceOfCalls, + ErrorCode_InexistentItem, + ErrorCode_BadRequest, + ErrorCode_NetworkProtocol, + ErrorCode_SystemCommand, + ErrorCode_Database, + + // Specific error codes + ErrorCode_UriSyntax, + ErrorCode_InexistentFile, + ErrorCode_CannotWriteFile, + ErrorCode_BadFileFormat, + ErrorCode_Timeout, + ErrorCode_UnknownResource, + ErrorCode_IncompatibleDatabaseVersion, + ErrorCode_FullStorage, + ErrorCode_CorruptedFile, + ErrorCode_InexistentTag, + ErrorCode_ReadOnly, + ErrorCode_IncompatibleImageFormat, + ErrorCode_IncompatibleImageSize, + ErrorCode_SharedLibrary, + ErrorCode_Plugin + }; + + + /** + * {summary}{The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image.} + **/ + enum PixelFormat + { + /** + * {summary}{Color image in RGB24 format.} + * {description}{This format describes a color image. The pixels are stored in 3 + * consecutive bytes. The memory layout is RGB.} + **/ + PixelFormat_RGB24 = 1, + + /** + * {summary}{Color image in RGBA32 format.} + * {description}{This format describes a color image. The pixels are stored in 4 + * consecutive bytes. The memory layout is RGBA.} + **/ + PixelFormat_RGBA32 = 2, + + /** + * {summary}{Graylevel 8bpp image.} + * {description}{The image is graylevel. Each pixel is unsigned and stored in one byte.} + **/ + PixelFormat_Grayscale8 = 3, + + /** + * {summary}{Graylevel, unsigned 16bpp image.} + * {description}{The image is graylevel. Each pixel is unsigned and stored in two bytes.} + **/ + PixelFormat_Grayscale16 = 4, + + /** + * {summary}{Graylevel, signed 16bpp image.} + * {description}{The image is graylevel. Each pixel is signed and stored in two bytes.} + **/ + PixelFormat_SignedGrayscale16 = 5 + }; + + + /** + * {summary}{The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image.} + **/ + enum ImageExtractionMode + { + /** + * {summary}{Rescaled to 8bpp.} + * {description}{The minimum value of the image is set to 0, and its maximum value is set to 255.} + **/ + ImageExtractionMode_Preview = 1, + + /** + * {summary}{Truncation to the [0, 255] range.} + **/ + ImageExtractionMode_UInt8 = 2, + + /** + * {summary}{Truncation to the [0, 65535] range.} + **/ + ImageExtractionMode_UInt16 = 3, + + /** + * {summary}{Truncation to the [-32768, 32767] range.} + **/ + ImageExtractionMode_Int16 = 4 + }; + + + /** + * Most common, non-joke and non-experimental HTTP status codes + * http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + **/ + enum HttpStatus + { + HttpStatus_None = -1, + + // 1xx Informational + HttpStatus_100_Continue = 100, + HttpStatus_101_SwitchingProtocols = 101, + HttpStatus_102_Processing = 102, + + // 2xx Success + HttpStatus_200_Ok = 200, + HttpStatus_201_Created = 201, + HttpStatus_202_Accepted = 202, + HttpStatus_203_NonAuthoritativeInformation = 203, + HttpStatus_204_NoContent = 204, + HttpStatus_205_ResetContent = 205, + HttpStatus_206_PartialContent = 206, + HttpStatus_207_MultiStatus = 207, + HttpStatus_208_AlreadyReported = 208, + HttpStatus_226_IMUsed = 226, + + // 3xx Redirection + HttpStatus_300_MultipleChoices = 300, + HttpStatus_301_MovedPermanently = 301, + HttpStatus_302_Found = 302, + HttpStatus_303_SeeOther = 303, + HttpStatus_304_NotModified = 304, + HttpStatus_305_UseProxy = 305, + HttpStatus_307_TemporaryRedirect = 307, + + // 4xx Client Error + HttpStatus_400_BadRequest = 400, + HttpStatus_401_Unauthorized = 401, + HttpStatus_402_PaymentRequired = 402, + HttpStatus_403_Forbidden = 403, + HttpStatus_404_NotFound = 404, + HttpStatus_405_MethodNotAllowed = 405, + HttpStatus_406_NotAcceptable = 406, + HttpStatus_407_ProxyAuthenticationRequired = 407, + HttpStatus_408_RequestTimeout = 408, + HttpStatus_409_Conflict = 409, + HttpStatus_410_Gone = 410, + HttpStatus_411_LengthRequired = 411, + HttpStatus_412_PreconditionFailed = 412, + HttpStatus_413_RequestEntityTooLarge = 413, + HttpStatus_414_RequestUriTooLong = 414, + HttpStatus_415_UnsupportedMediaType = 415, + HttpStatus_416_RequestedRangeNotSatisfiable = 416, + HttpStatus_417_ExpectationFailed = 417, + HttpStatus_422_UnprocessableEntity = 422, + HttpStatus_423_Locked = 423, + HttpStatus_424_FailedDependency = 424, + HttpStatus_426_UpgradeRequired = 426, + + // 5xx Server Error + HttpStatus_500_InternalServerError = 500, + HttpStatus_501_NotImplemented = 501, + HttpStatus_502_BadGateway = 502, + HttpStatus_503_ServiceUnavailable = 503, + HttpStatus_504_GatewayTimeout = 504, + HttpStatus_505_HttpVersionNotSupported = 505, + HttpStatus_506_VariantAlsoNegotiates = 506, + HttpStatus_507_InsufficientStorage = 507, + HttpStatus_509_BandwidthLimitExceeded = 509, + HttpStatus_510_NotExtended = 510 + }; + + + enum HttpMethod + { + HttpMethod_Get = 0, + HttpMethod_Post = 1, + HttpMethod_Delete = 2, + HttpMethod_Put = 3 + }; + + + enum ImageFormat + { + ImageFormat_Png = 1 + }; + + + // http://www.dabsoft.ch/dicom/3/C.12.1.1.2/ + enum Encoding + { + Encoding_Ascii, + Encoding_Utf8, + Encoding_Latin1, + Encoding_Latin2, + Encoding_Latin3, + Encoding_Latin4, + Encoding_Latin5, // Turkish + Encoding_Cyrillic, + Encoding_Windows1251, // Windows-1251 (commonly used for Cyrillic) + Encoding_Arabic, + Encoding_Greek, + Encoding_Hebrew, + Encoding_Thai, // TIS 620-2533 + Encoding_Japanese, // JIS X 0201 (Shift JIS): Katakana + Encoding_Chinese // GB18030 - Chinese simplified + //Encoding_JapaneseKanji, // Multibyte - JIS X 0208: Kanji + //Encoding_JapaneseSupplementaryKanji, // Multibyte - JIS X 0212: Supplementary Kanji set + //Encoding_Korean, // Multibyte - KS X 1001: Hangul and Hanja + }; + + + // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.2/ + enum PhotometricInterpretation + { + PhotometricInterpretation_ARGB, // Retired + PhotometricInterpretation_CMYK, // Retired + PhotometricInterpretation_HSV, // Retired + PhotometricInterpretation_Monochrome1, + PhotometricInterpretation_Monochrome2, + PhotometricInterpretation_Palette, + PhotometricInterpretation_RGB, + PhotometricInterpretation_YBRFull, + PhotometricInterpretation_YBRFull422, + PhotometricInterpretation_YBRPartial420, + PhotometricInterpretation_YBRPartial422, + PhotometricInterpretation_YBR_ICT, + PhotometricInterpretation_YBR_RCT, + PhotometricInterpretation_Unknown + }; + + enum DicomModule + { + DicomModule_Patient, + DicomModule_Study, + DicomModule_Series, + DicomModule_Instance, + DicomModule_Image + }; + + + /** + * WARNING: Do not change the explicit values in the enumerations + * below this point. This would result in incompatible databases + * between versions of Orthanc! + **/ + + enum CompressionType + { + CompressionType_None = 1, + CompressionType_Zlib = 2 + }; + + enum FileContentType + { + // If you add a value below, insert it in "PluginStorageArea" in + // the file "Plugins/Engine/OrthancPlugins.cpp" + FileContentType_Unknown = 0, + FileContentType_Dicom = 1, + FileContentType_DicomAsJson = 2, + + // Make sure that the value "65535" can be stored into this enumeration + FileContentType_StartUser = 1024, + FileContentType_EndUser = 65535 + }; + + enum ResourceType + { + ResourceType_Patient = 1, + ResourceType_Study = 2, + ResourceType_Series = 3, + ResourceType_Instance = 4 + }; + + + const char* EnumerationToString(HttpMethod method); + + const char* EnumerationToString(HttpStatus status); + + const char* EnumerationToString(ResourceType type); + + const char* EnumerationToString(ImageFormat format); + + const char* EnumerationToString(Encoding encoding); + + const char* EnumerationToString(PhotometricInterpretation photometric); + + Encoding StringToEncoding(const char* encoding); + + ResourceType StringToResourceType(const char* type); + + ImageFormat StringToImageFormat(const char* format); + + unsigned int GetBytesPerPixel(PixelFormat format); + + bool GetDicomEncoding(Encoding& encoding, + const char* specificCharacterSet); + + const char* GetMimeType(FileContentType type); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/FileStorage/FilesystemStorage.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,265 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "FilesystemStorage.h" + +// http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system +// http://stackoverflow.com/questions/446358/storing-a-large-number-of-images + +#include "../OrthancException.h" +#include "../Toolbox.h" +#include "../Uuid.h" + +#include <boost/filesystem/fstream.hpp> + +#if HAVE_GOOGLE_LOG == 1 +#include <glog/logging.h> +#endif + +static std::string ToString(const boost::filesystem::path& p) +{ +#if BOOST_HAS_FILESYSTEM_V3 == 1 + return p.filename().string(); +#else + return p.filename(); +#endif +} + + +namespace Orthanc +{ + boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const + { + namespace fs = boost::filesystem; + + if (!Toolbox::IsUuid(uuid)) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + fs::path path = root_; + + path /= std::string(&uuid[0], &uuid[2]); + path /= std::string(&uuid[2], &uuid[4]); + path /= uuid; + +#if BOOST_HAS_FILESYSTEM_V3 == 1 + path.make_preferred(); +#endif + + return path; + } + + FilesystemStorage::FilesystemStorage(std::string root) + { + //root_ = boost::filesystem::absolute(root).string(); + root_ = root; + + Toolbox::MakeDirectory(root); + } + + void FilesystemStorage::Create(const std::string& uuid, + const void* content, + size_t size, + FileContentType /*type*/) + { + boost::filesystem::path path; + + path = GetPath(uuid); + + if (boost::filesystem::exists(path)) + { + // Extremely unlikely case: This Uuid has already been created + // in the past. + throw OrthancException(ErrorCode_InternalError); + } + + if (boost::filesystem::exists(path.parent_path())) + { + if (!boost::filesystem::is_directory(path.parent_path())) + { + throw OrthancException("The subdirectory to be created is already occupied by a regular file"); + } + } + else + { + if (!boost::filesystem::create_directories(path.parent_path())) + { + throw OrthancException("Unable to create a subdirectory in the file storage"); + } + } + + boost::filesystem::ofstream f; + f.open(path, std::ofstream::out | std::ios::binary); + if (!f.good()) + { + throw OrthancException("Unable to create a new file in the file storage"); + } + + if (size != 0) + { + f.write(static_cast<const char*>(content), size); + if (!f.good()) + { + f.close(); + throw OrthancException("Unable to write to the new file in the file storage"); + } + } + + f.close(); + } + + + void FilesystemStorage::Read(std::string& content, + const std::string& uuid, + FileContentType /*type*/) + { + content.clear(); + Toolbox::ReadFile(content, GetPath(uuid).string()); + } + + + uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const + { + boost::filesystem::path path = GetPath(uuid); + return boost::filesystem::file_size(path); + } + + + + void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const + { + namespace fs = boost::filesystem; + + result.clear(); + + if (fs::exists(root_) && fs::is_directory(root_)) + { + for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) + { + if (fs::is_regular_file(current->status())) + { + try + { + fs::path d = current->path(); + std::string uuid = ToString(d); + if (Toolbox::IsUuid(uuid)) + { + fs::path p0 = d.parent_path().parent_path().parent_path(); + std::string p1 = ToString(d.parent_path().parent_path()); + std::string p2 = ToString(d.parent_path()); + if (p1.length() == 2 && + p2.length() == 2 && + p1 == uuid.substr(0, 2) && + p2 == uuid.substr(2, 2) && + p0 == root_) + { + result.insert(uuid); + } + } + } + catch (fs::filesystem_error) + { + } + } + } + } + } + + + void FilesystemStorage::Clear() + { + namespace fs = boost::filesystem; + typedef std::set<std::string> List; + + List result; + ListAllFiles(result); + + for (List::const_iterator it = result.begin(); it != result.end(); ++it) + { + Remove(*it, FileContentType_Unknown /*ignored in this class*/); + } + } + + + void FilesystemStorage::Remove(const std::string& uuid, + FileContentType /*type*/) + { +#if HAVE_GOOGLE_LOG == 1 + LOG(INFO) << "Deleting file " << uuid; +#endif + + namespace fs = boost::filesystem; + + fs::path p = GetPath(uuid); + + try + { + fs::remove(p); + } + catch (...) + { + // Ignore the error + } + + // Remove the two parent directories, ignoring the error code if + // these directories are not empty + + try + { +#if BOOST_HAS_FILESYSTEM_V3 == 1 + boost::system::error_code err; + fs::remove(p.parent_path(), err); + fs::remove(p.parent_path().parent_path(), err); +#else + fs::remove(p.parent_path()); + fs::remove(p.parent_path().parent_path()); +#endif + } + catch (...) + { + // Ignore the error + } + } + + + uintmax_t FilesystemStorage::GetCapacity() const + { + return boost::filesystem::space(root_).capacity; + } + + uintmax_t FilesystemStorage::GetAvailableSpace() const + { + return boost::filesystem::space(root_).available; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/FileStorage/FilesystemStorage.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,79 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IStorageArea.h" + +#include <stdint.h> +#include <boost/filesystem.hpp> +#include <set> + +namespace Orthanc +{ + class FilesystemStorage : public IStorageArea + { + // TODO REMOVE THIS + friend class FilesystemHttpSender; + friend class FileStorageAccessor; + + private: + boost::filesystem::path root_; + + boost::filesystem::path GetPath(const std::string& uuid) const; + + public: + FilesystemStorage(std::string root); + + virtual void Create(const std::string& uuid, + const void* content, + size_t size, + FileContentType type); + + virtual void Read(std::string& content, + const std::string& uuid, + FileContentType type); + + virtual void Remove(const std::string& uuid, + FileContentType type); + + void ListAllFiles(std::set<std::string>& result) const; + + uintmax_t GetSize(const std::string& uuid) const; + + void Clear(); + + uintmax_t GetCapacity() const; + + uintmax_t GetAvailableSpace() const; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/FileStorage/IStorageArea.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,61 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../Enumerations.h" + +#include <string> +#include <boost/noncopyable.hpp> + +namespace Orthanc +{ + class IStorageArea : public boost::noncopyable + { + public: + virtual ~IStorageArea() + { + } + + virtual void Create(const std::string& uuid, + const void* content, + size_t size, + FileContentType type) = 0; + + virtual void Read(std::string& content, + const std::string& uuid, + FileContentType type) = 0; + + virtual void Remove(const std::string& uuid, + FileContentType type) = 0; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/IDynamicObject.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,52 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <boost/noncopyable.hpp> + +namespace Orthanc +{ + /** + * This class should be the ancestor to any class whose type is + * determined at the runtime, and that can be dynamically allocated. + * Being a child of IDynamicObject only implies the existence of a + * virtual destructor. + **/ + class IDynamicObject : public boost::noncopyable + { + public: + virtual ~IDynamicObject() + { + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageAccessor.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,231 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "ImageAccessor.h" + +#include "../OrthancException.h" +#include "../ChunkedBuffer.h" + +#include <stdint.h> +#include <cassert> +#include <boost/lexical_cast.hpp> + +#if HAVE_GOOGLE_LOG == 1 +#include <glog/logging.h> +#endif + + +namespace Orthanc +{ + template <typename PixelType> + static void ToMatlabStringInternal(ChunkedBuffer& target, + const ImageAccessor& source) + { + target.AddChunk("double([ "); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y)); + + std::string s; + if (y > 0) + { + s = "; "; + } + + s.reserve(source.GetWidth() * 8); + + for (unsigned int x = 0; x < source.GetWidth(); x++, p++) + { + s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " "; + } + + target.AddChunk(s); + } + + target.AddChunk("])"); + } + + + static void RGB24ToMatlabString(ChunkedBuffer& target, + const ImageAccessor& source) + { + assert(source.GetFormat() == PixelFormat_RGB24); + + target.AddChunk("double(permute(reshape([ "); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y)); + + std::string s; + s.reserve(source.GetWidth() * 3 * 8); + + for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++) + { + s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " "; + } + + target.AddChunk(s); + } + + target.AddChunk("], [ 3 " + boost::lexical_cast<std::string>(source.GetHeight()) + + " " + boost::lexical_cast<std::string>(source.GetWidth()) + " ]), [ 3 2 1 ]))"); + } + + + void* ImageAccessor::GetBuffer() const + { + if (readOnly_) + { +#if HAVE_GOOGLE_LOG == 1 + LOG(ERROR) << "Trying to write on a read-only image"; +#endif + + throw OrthancException(ErrorCode_ReadOnly); + } + + return buffer_; + } + + + const void* ImageAccessor::GetConstRow(unsigned int y) const + { + if (buffer_ != NULL) + { + return reinterpret_cast<const uint8_t*>(buffer_) + y * pitch_; + } + else + { + return NULL; + } + } + + + void* ImageAccessor::GetRow(unsigned int y) const + { + if (readOnly_) + { +#if HAVE_GOOGLE_LOG == 1 + LOG(ERROR) << "Trying to write on a read-only image"; +#endif + + throw OrthancException(ErrorCode_ReadOnly); + } + + if (buffer_ != NULL) + { + return reinterpret_cast<uint8_t*>(buffer_) + y * pitch_; + } + else + { + return NULL; + } + } + + + void ImageAccessor::AssignEmpty(PixelFormat format) + { + readOnly_ = false; + format_ = format; + width_ = 0; + height_ = 0; + pitch_ = 0; + buffer_ = NULL; + } + + + void ImageAccessor::AssignReadOnly(PixelFormat format, + unsigned int width, + unsigned int height, + unsigned int pitch, + const void *buffer) + { + readOnly_ = true; + format_ = format; + width_ = width; + height_ = height; + pitch_ = pitch; + buffer_ = const_cast<void*>(buffer); + + assert(GetBytesPerPixel() * width_ <= pitch_); + } + + + void ImageAccessor::AssignWritable(PixelFormat format, + unsigned int width, + unsigned int height, + unsigned int pitch, + void *buffer) + { + readOnly_ = false; + format_ = format; + width_ = width; + height_ = height; + pitch_ = pitch; + buffer_ = buffer; + + assert(GetBytesPerPixel() * width_ <= pitch_); + } + + + void ImageAccessor::ToMatlabString(std::string& target) const + { + ChunkedBuffer buffer; + + switch (GetFormat()) + { + case PixelFormat_Grayscale8: + ToMatlabStringInternal<uint8_t>(buffer, *this); + break; + + case PixelFormat_Grayscale16: + ToMatlabStringInternal<uint16_t>(buffer, *this); + break; + + case PixelFormat_SignedGrayscale16: + ToMatlabStringInternal<int16_t>(buffer, *this); + break; + + case PixelFormat_RGB24: + RGB24ToMatlabString(buffer, *this); + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + + buffer.Flatten(target); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageAccessor.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,119 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../Enumerations.h" + +#include <string> + +namespace Orthanc +{ + class ImageAccessor + { + private: + bool readOnly_; + PixelFormat format_; + unsigned int width_; + unsigned int height_; + unsigned int pitch_; + void *buffer_; + + public: + ImageAccessor() + { + AssignEmpty(PixelFormat_Grayscale8); + } + + bool IsReadOnly() const + { + return readOnly_; + } + + PixelFormat GetFormat() const + { + return format_; + } + + unsigned int GetBytesPerPixel() const + { + return ::Orthanc::GetBytesPerPixel(format_); + } + + unsigned int GetWidth() const + { + return width_; + } + + unsigned int GetHeight() const + { + return height_; + } + + unsigned int GetPitch() const + { + return pitch_; + } + + unsigned int GetSize() const + { + return GetHeight() * GetPitch(); + } + + const void* GetConstBuffer() const + { + return buffer_; + } + + void* GetBuffer() const; + + const void* GetConstRow(unsigned int y) const; + + void* GetRow(unsigned int y) const; + + void AssignEmpty(PixelFormat format); + + void AssignReadOnly(PixelFormat format, + unsigned int width, + unsigned int height, + unsigned int pitch, + const void *buffer); + + void AssignWritable(PixelFormat format, + unsigned int width, + unsigned int height, + unsigned int pitch, + void *buffer); + + void ToMatlabString(std::string& target) const; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageBuffer.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,192 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "ImageBuffer.h" + +#include "../OrthancException.h" + +#include <stdio.h> +#include <stdlib.h> + +namespace Orthanc +{ + void ImageBuffer::Allocate() + { + if (changed_) + { + Deallocate(); + + /* + if (forceMinimalPitch_) + { + TODO: Align pitch and memory buffer to optimal size for SIMD. + } + */ + + pitch_ = GetBytesPerPixel() * width_; + size_t size = pitch_ * height_; + + if (size == 0) + { + buffer_ = NULL; + } + else + { + buffer_ = malloc(size); + if (buffer_ == NULL) + { + throw OrthancException(ErrorCode_NotEnoughMemory); + } + } + + changed_ = false; + } + } + + + void ImageBuffer::Deallocate() + { + if (buffer_ != NULL) + { + free(buffer_); + buffer_ = NULL; + changed_ = true; + } + } + + + ImageBuffer::ImageBuffer(unsigned int width, + unsigned int height, + PixelFormat format) + { + Initialize(); + SetWidth(width); + SetHeight(height); + SetFormat(format); + } + + + void ImageBuffer::Initialize() + { + changed_ = false; + forceMinimalPitch_ = true; + format_ = PixelFormat_Grayscale8; + width_ = 0; + height_ = 0; + pitch_ = 0; + buffer_ = NULL; + } + + + void ImageBuffer::SetFormat(PixelFormat format) + { + if (format != format_) + { + changed_ = true; + format_ = format; + } + } + + + void ImageBuffer::SetWidth(unsigned int width) + { + if (width != width_) + { + changed_ = true; + width_ = width; + } + } + + + void ImageBuffer::SetHeight(unsigned int height) + { + if (height != height_) + { + changed_ = true; + height_ = height; + } + } + + + ImageAccessor ImageBuffer::GetAccessor() + { + Allocate(); + + ImageAccessor accessor; + accessor.AssignWritable(format_, width_, height_, pitch_, buffer_); + return accessor; + } + + + ImageAccessor ImageBuffer::GetConstAccessor() + { + Allocate(); + + ImageAccessor accessor; + accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_); + return accessor; + } + + + void ImageBuffer::SetMinimalPitchForced(bool force) + { + if (force != forceMinimalPitch_) + { + changed_ = true; + forceMinimalPitch_ = force; + } + } + + + void ImageBuffer::AcquireOwnership(ImageBuffer& other) + { + // Remove the content of the current image + Deallocate(); + + // Force the allocation of the other image (if not already + // allocated) + other.Allocate(); + + // Transfer the content of the other image + changed_ = false; + forceMinimalPitch_ = other.forceMinimalPitch_; + format_ = other.format_; + width_ = other.width_; + height_ = other.height_; + pitch_ = other.pitch_; + buffer_ = other.buffer_; + + // Force the reinitialization of the other image + other.Initialize(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageBuffer.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,115 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ImageAccessor.h" + +#include <vector> +#include <stdint.h> +#include <boost/noncopyable.hpp> + +namespace Orthanc +{ + class ImageBuffer : public boost::noncopyable + { + private: + bool changed_; + + bool forceMinimalPitch_; // Currently unused + PixelFormat format_; + unsigned int width_; + unsigned int height_; + unsigned int pitch_; + void *buffer_; + + void Initialize(); + + void Allocate(); + + void Deallocate(); + + public: + ImageBuffer(unsigned int width, + unsigned int height, + PixelFormat format); + + ImageBuffer() + { + Initialize(); + } + + ~ImageBuffer() + { + Deallocate(); + } + + PixelFormat GetFormat() const + { + return format_; + } + + void SetFormat(PixelFormat format); + + unsigned int GetWidth() const + { + return width_; + } + + void SetWidth(unsigned int width); + + unsigned int GetHeight() const + { + return height_; + } + + void SetHeight(unsigned int height); + + unsigned int GetBytesPerPixel() const + { + return ::Orthanc::GetBytesPerPixel(format_); + } + + ImageAccessor GetAccessor(); + + ImageAccessor GetConstAccessor(); + + bool IsMinimalPitchForced() const + { + return forceMinimalPitch_; + } + + void SetMinimalPitchForced(bool force); + + void AcquireOwnership(ImageBuffer& other); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageProcessing.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,532 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "ImageProcessing.h" + +#include "../OrthancException.h" + +#include <boost/math/special_functions/round.hpp> + +#include <cassert> +#include <string.h> +#include <limits> +#include <stdint.h> + +namespace Orthanc +{ + template <typename TargetType, typename SourceType> + static void ConvertInternal(ImageAccessor& target, + const ImageAccessor& source) + { + const TargetType minValue = std::numeric_limits<TargetType>::min(); + const TargetType maxValue = std::numeric_limits<TargetType>::max(); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y)); + const SourceType* s = reinterpret_cast<const SourceType*>(source.GetConstRow(y)); + + for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s++) + { + if (static_cast<int32_t>(*s) < static_cast<int32_t>(minValue)) + { + *t = minValue; + } + else if (static_cast<int32_t>(*s) > static_cast<int32_t>(maxValue)) + { + *t = maxValue; + } + else + { + *t = static_cast<TargetType>(*s); + } + } + } + } + + + template <typename TargetType> + static void ConvertColorToGrayscale(ImageAccessor& target, + const ImageAccessor& source) + { + assert(source.GetFormat() == PixelFormat_RGB24); + + const TargetType minValue = std::numeric_limits<TargetType>::min(); + const TargetType maxValue = std::numeric_limits<TargetType>::max(); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y)); + const uint8_t* s = reinterpret_cast<const uint8_t*>(source.GetConstRow(y)); + + for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s += 3) + { + // Y = 0.2126 R + 0.7152 G + 0.0722 B + int32_t v = (2126 * static_cast<int32_t>(s[0]) + + 7152 * static_cast<int32_t>(s[1]) + + 0722 * static_cast<int32_t>(s[2])) / 1000; + + if (static_cast<int32_t>(v) < static_cast<int32_t>(minValue)) + { + *t = minValue; + } + else if (static_cast<int32_t>(v) > static_cast<int32_t>(maxValue)) + { + *t = maxValue; + } + else + { + *t = static_cast<TargetType>(v); + } + } + } + } + + + template <typename PixelType> + static void SetInternal(ImageAccessor& image, + int64_t constant) + { + for (unsigned int y = 0; y < image.GetHeight(); y++) + { + PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); + + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + *p = static_cast<PixelType>(constant); + } + } + } + + + template <typename PixelType> + static void GetMinMaxValueInternal(PixelType& minValue, + PixelType& maxValue, + const ImageAccessor& source) + { + // Deal with the special case of empty image + if (source.GetWidth() == 0 || + source.GetHeight() == 0) + { + minValue = 0; + maxValue = 0; + return; + } + + minValue = std::numeric_limits<PixelType>::max(); + maxValue = std::numeric_limits<PixelType>::min(); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y)); + + for (unsigned int x = 0; x < source.GetWidth(); x++, p++) + { + if (*p < minValue) + { + minValue = *p; + } + + if (*p > maxValue) + { + maxValue = *p; + } + } + } + } + + + + template <typename PixelType> + static void AddConstantInternal(ImageAccessor& image, + int64_t constant) + { + if (constant == 0) + { + return; + } + + const int64_t minValue = std::numeric_limits<PixelType>::min(); + const int64_t maxValue = std::numeric_limits<PixelType>::max(); + + for (unsigned int y = 0; y < image.GetHeight(); y++) + { + PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); + + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + int64_t v = static_cast<int64_t>(*p) + constant; + + if (v > maxValue) + { + *p = std::numeric_limits<PixelType>::max(); + } + else if (v < minValue) + { + *p = std::numeric_limits<PixelType>::min(); + } + else + { + *p = static_cast<PixelType>(v); + } + } + } + } + + + + template <typename PixelType> + void MultiplyConstantInternal(ImageAccessor& image, + float factor) + { + if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon()) + { + return; + } + + const int64_t minValue = std::numeric_limits<PixelType>::min(); + const int64_t maxValue = std::numeric_limits<PixelType>::max(); + + for (unsigned int y = 0; y < image.GetHeight(); y++) + { + PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); + + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + int64_t v = boost::math::llround(static_cast<float>(*p) * factor); + + if (v > maxValue) + { + *p = std::numeric_limits<PixelType>::max(); + } + else if (v < minValue) + { + *p = std::numeric_limits<PixelType>::min(); + } + else + { + *p = static_cast<PixelType>(v); + } + } + } + } + + + template <typename PixelType> + void ShiftScaleInternal(ImageAccessor& image, + float offset, + float scaling) + { + const float minValue = static_cast<float>(std::numeric_limits<PixelType>::min()); + const float maxValue = static_cast<float>(std::numeric_limits<PixelType>::max()); + + for (unsigned int y = 0; y < image.GetHeight(); y++) + { + PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); + + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + float v = (static_cast<float>(*p) + offset) * scaling; + + if (v > maxValue) + { + *p = std::numeric_limits<PixelType>::max(); + } + else if (v < minValue) + { + *p = std::numeric_limits<PixelType>::min(); + } + else + { + *p = static_cast<PixelType>(boost::math::iround(v)); + } + } + } + } + + + void ImageProcessing::Copy(ImageAccessor& target, + const ImageAccessor& source) + { + if (target.GetWidth() != source.GetWidth() || + target.GetHeight() != source.GetHeight()) + { + throw OrthancException(ErrorCode_IncompatibleImageSize); + } + + if (target.GetFormat() != source.GetFormat()) + { + throw OrthancException(ErrorCode_IncompatibleImageFormat); + } + + unsigned int lineSize = GetBytesPerPixel(source.GetFormat()) * source.GetWidth(); + + assert(source.GetPitch() >= lineSize && target.GetPitch() >= lineSize); + + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + memcpy(target.GetRow(y), source.GetConstRow(y), lineSize); + } + } + + + void ImageProcessing::Convert(ImageAccessor& target, + const ImageAccessor& source) + { + if (target.GetWidth() != source.GetWidth() || + target.GetHeight() != source.GetHeight()) + { + throw OrthancException(ErrorCode_IncompatibleImageSize); + } + + if (source.GetFormat() == target.GetFormat()) + { + Copy(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale16 && + source.GetFormat() == PixelFormat_Grayscale8) + { + ConvertInternal<uint16_t, uint8_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_SignedGrayscale16 && + source.GetFormat() == PixelFormat_Grayscale8) + { + ConvertInternal<int16_t, uint8_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale8 && + source.GetFormat() == PixelFormat_Grayscale16) + { + ConvertInternal<uint8_t, uint16_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_SignedGrayscale16 && + source.GetFormat() == PixelFormat_Grayscale16) + { + ConvertInternal<int16_t, uint16_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale8 && + source.GetFormat() == PixelFormat_SignedGrayscale16) + { + ConvertInternal<uint8_t, int16_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale16 && + source.GetFormat() == PixelFormat_SignedGrayscale16) + { + ConvertInternal<uint16_t, int16_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale8 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale<uint8_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Grayscale16 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale<uint16_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_SignedGrayscale16 && + source.GetFormat() == PixelFormat_RGB24) + { + ConvertColorToGrayscale<int16_t>(target, source); + return; + } + + throw OrthancException(ErrorCode_NotImplemented); + } + + + + void ImageProcessing::Set(ImageAccessor& image, + int64_t value) + { + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + SetInternal<uint8_t>(image, value); + return; + + case PixelFormat_Grayscale16: + SetInternal<uint16_t>(image, value); + return; + + case PixelFormat_SignedGrayscale16: + SetInternal<int16_t>(image, value); + return; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void ImageProcessing::ShiftRight(ImageAccessor& image, + unsigned int shift) + { + if (image.GetWidth() == 0 || + image.GetHeight() == 0 || + shift == 0) + { + // Nothing to do + return; + } + + throw OrthancException(ErrorCode_NotImplemented); + } + + + void ImageProcessing::GetMinMaxValue(int64_t& minValue, + int64_t& maxValue, + const ImageAccessor& image) + { + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + { + uint8_t a, b; + GetMinMaxValueInternal<uint8_t>(a, b, image); + minValue = a; + maxValue = b; + break; + } + + case PixelFormat_Grayscale16: + { + uint16_t a, b; + GetMinMaxValueInternal<uint16_t>(a, b, image); + minValue = a; + maxValue = b; + break; + } + + case PixelFormat_SignedGrayscale16: + { + int16_t a, b; + GetMinMaxValueInternal<int16_t>(a, b, image); + minValue = a; + maxValue = b; + break; + } + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + + void ImageProcessing::AddConstant(ImageAccessor& image, + int64_t value) + { + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + AddConstantInternal<uint8_t>(image, value); + return; + + case PixelFormat_Grayscale16: + AddConstantInternal<uint16_t>(image, value); + return; + + case PixelFormat_SignedGrayscale16: + AddConstantInternal<int16_t>(image, value); + return; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void ImageProcessing::MultiplyConstant(ImageAccessor& image, + float factor) + { + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + MultiplyConstantInternal<uint8_t>(image, factor); + return; + + case PixelFormat_Grayscale16: + MultiplyConstantInternal<uint16_t>(image, factor); + return; + + case PixelFormat_SignedGrayscale16: + MultiplyConstantInternal<int16_t>(image, factor); + return; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void ImageProcessing::ShiftScale(ImageAccessor& image, + float offset, + float scaling) + { + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + ShiftScaleInternal<uint8_t>(image, offset, scaling); + return; + + case PixelFormat_Grayscale16: + ShiftScaleInternal<uint16_t>(image, offset, scaling); + return; + + case PixelFormat_SignedGrayscale16: + ShiftScaleInternal<int16_t>(image, offset, scaling); + return; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/ImageProcessing.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,70 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ImageAccessor.h" + +#include <stdint.h> + +namespace Orthanc +{ + class ImageProcessing + { + public: + static void Copy(ImageAccessor& target, + const ImageAccessor& source); + + static void Convert(ImageAccessor& target, + const ImageAccessor& source); + + static void Set(ImageAccessor& image, + int64_t value); + + static void ShiftRight(ImageAccessor& target, + unsigned int shift); + + static void GetMinMaxValue(int64_t& minValue, + int64_t& maxValue, + const ImageAccessor& image); + + static void AddConstant(ImageAccessor& image, + int64_t value); + + static void MultiplyConstant(ImageAccessor& image, + float factor); + + static void ShiftScale(ImageAccessor& image, + float offset, + float scaling); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/PngWriter.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,269 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "PngWriter.h" + +#include <vector> +#include <stdint.h> +#include <png.h> +#include "../OrthancException.h" +#include "../ChunkedBuffer.h" +#include "../Toolbox.h" + + +// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4 +// http://zarb.org/~gc/html/libpng.html +/* + void write_row_callback(png_ptr, png_uint_32 row, int pass) + { + }*/ + + + + +/* bool isError_; + +// http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2 + +static void ErrorHandler(png_structp png, png_const_charp message) +{ +printf("** [%s]\n", message); + +PngWriter* that = (PngWriter*) png_get_error_ptr(png); +that->isError_ = true; +printf("** %d\n", (int)that); + +//((PngWriter*) payload)->isError_ = true; +} + +static void WarningHandler(png_structp png, png_const_charp message) +{ + printf("++ %d\n", (int)message); +}*/ + + +namespace Orthanc +{ + struct PngWriter::PImpl + { + png_structp png_; + png_infop info_; + + // Filled by Prepare() + std::vector<uint8_t*> rows_; + int bitDepth_; + int colorType_; + }; + + + + PngWriter::PngWriter() : pimpl_(new PImpl) + { + pimpl_->png_ = NULL; + pimpl_->info_ = NULL; + + pimpl_->png_ = png_create_write_struct + (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler); + if (!pimpl_->png_) + { + throw OrthancException(ErrorCode_NotEnoughMemory); + } + + pimpl_->info_ = png_create_info_struct(pimpl_->png_); + if (!pimpl_->info_) + { + png_destroy_write_struct(&pimpl_->png_, NULL); + throw OrthancException(ErrorCode_NotEnoughMemory); + } + } + + PngWriter::~PngWriter() + { + if (pimpl_->info_) + { + png_destroy_info_struct(pimpl_->png_, &pimpl_->info_); + } + + if (pimpl_->png_) + { + png_destroy_write_struct(&pimpl_->png_, NULL); + } + } + + + + void PngWriter::Prepare(unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + pimpl_->rows_.resize(height); + for (unsigned int y = 0; y < height; y++) + { + pimpl_->rows_[y] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer)) + y * pitch; + } + + switch (format) + { + case PixelFormat_RGB24: + pimpl_->bitDepth_ = 8; + pimpl_->colorType_ = PNG_COLOR_TYPE_RGB; + break; + + case PixelFormat_RGBA32: + pimpl_->bitDepth_ = 8; + pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA; + break; + + case PixelFormat_Grayscale8: + pimpl_->bitDepth_ = 8; + pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; + break; + + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + pimpl_->bitDepth_ = 16; + pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void PngWriter::Compress(unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format) + { + png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height, + pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_write_info(pimpl_->png_, pimpl_->info_); + + if (height > 0) + { + switch (format) + { + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + { + int transforms = 0; + if (Toolbox::DetectEndianness() == Endianness_Little) + { + transforms = PNG_TRANSFORM_SWAP_ENDIAN; + } + + png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]); + png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL); + + break; + } + + default: + png_write_image(pimpl_->png_, &pimpl_->rows_[0]); + } + } + + png_write_end(pimpl_->png_, NULL); + } + + + void PngWriter::WriteToFile(const char* filename, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + Prepare(width, height, pitch, format, buffer); + + FILE* fp = fopen(filename, "wb"); + if (!fp) + { + throw OrthancException(ErrorCode_CannotWriteFile); + } + + png_init_io(pimpl_->png_, fp); + + if (setjmp(png_jmpbuf(pimpl_->png_))) + { + // Error during writing PNG + throw OrthancException(ErrorCode_CannotWriteFile); + } + + Compress(width, height, pitch, format); + + fclose(fp); + } + + + + + static void MemoryCallback(png_structp png_ptr, + png_bytep data, + png_size_t size) + { + ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr)); + buffer->AddChunk(reinterpret_cast<const char*>(data), size); + } + + + + void PngWriter::WriteToMemory(std::string& png, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer) + { + ChunkedBuffer chunks; + + Prepare(width, height, pitch, format, buffer); + + if (setjmp(png_jmpbuf(pimpl_->png_))) + { + // Error during writing PNG + throw OrthancException(ErrorCode_InternalError); + } + + png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL); + + Compress(width, height, pitch, format); + + chunks.Flatten(png); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/ImageFormats/PngWriter.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,92 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "ImageAccessor.h" + +#include <boost/shared_ptr.hpp> +#include <string> + +namespace Orthanc +{ + class PngWriter + { + private: + struct PImpl; + boost::shared_ptr<PImpl> pimpl_; + + void Compress(unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format); + + void Prepare(unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer); + + public: + PngWriter(); + + ~PngWriter(); + + void WriteToFile(const char* filename, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer); + + void WriteToMemory(std::string& png, + unsigned int width, + unsigned int height, + unsigned int pitch, + PixelFormat format, + const void* buffer); + + void WriteToFile(const char* filename, + const ImageAccessor& accessor) + { + WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); + } + + void WriteToMemory(std::string& png, + const ImageAccessor& accessor) + { + WriteToMemory(png, accessor.GetWidth(), accessor.GetHeight(), + accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,188 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "SharedMessageQueue.h" + + + +/** + * FIFO (queue): + * + * back front + * +--+--+--+--+--+--+--+--+--+--+--+ + * Enqueue -> | | | | | | | | | | | | + * | | | | | | | | | | | | -> Dequeue + * +--+--+--+--+--+--+--+--+--+--+--+ + * ^ + * | + * Make room here + * + * + * LIFO (stack): + * + * back front + * +--+--+--+--+--+--+--+--+--+--+--+ + * | | | | | | | | | | | | <- Enqueue + * | | | | | | | | | | | | -> Dequeue + * +--+--+--+--+--+--+--+--+--+--+--+ + * ^ + * | + * Make room here + **/ + + +namespace Orthanc +{ + SharedMessageQueue::SharedMessageQueue(unsigned int maxSize) : + isFifo_(true), + maxSize_(maxSize) + { + } + + + SharedMessageQueue::~SharedMessageQueue() + { + for (Queue::iterator it = queue_.begin(); it != queue_.end(); ++it) + { + delete *it; + } + } + + + void SharedMessageQueue::Enqueue(IDynamicObject* message) + { + boost::mutex::scoped_lock lock(mutex_); + + if (maxSize_ != 0 && queue_.size() > maxSize_) + { + if (isFifo_) + { + // Too many elements in the queue: Make room + delete queue_.front(); + queue_.pop_front(); + } + else + { + // Too many elements in the stack: Make room + delete queue_.back(); + queue_.pop_back(); + } + } + + if (isFifo_) + { + // Queue policy (FIFO) + queue_.push_back(message); + } + else + { + // Stack policy (LIFO) + queue_.push_front(message); + } + + elementAvailable_.notify_one(); + } + + + IDynamicObject* SharedMessageQueue::Dequeue(int32_t millisecondsTimeout) + { + boost::mutex::scoped_lock lock(mutex_); + + // Wait for a message to arrive in the FIFO queue + while (queue_.empty()) + { + if (millisecondsTimeout == 0) + { + elementAvailable_.wait(lock); + } + else + { + bool success = elementAvailable_.timed_wait + (lock, boost::posix_time::milliseconds(millisecondsTimeout)); + if (!success) + { + return NULL; + } + } + } + + std::auto_ptr<IDynamicObject> message(queue_.front()); + queue_.pop_front(); + + if (queue_.empty()) + { + emptied_.notify_all(); + } + + return message.release(); + } + + + + bool SharedMessageQueue::WaitEmpty(int32_t millisecondsTimeout) + { + boost::mutex::scoped_lock lock(mutex_); + + // Wait for the queue to become empty + while (!queue_.empty()) + { + if (millisecondsTimeout == 0) + { + emptied_.wait(lock); + } + else + { + if (!emptied_.timed_wait + (lock, boost::posix_time::milliseconds(millisecondsTimeout))) + { + return false; + } + } + } + + return true; + } + + + void SharedMessageQueue::SetFifoPolicy() + { + boost::mutex::scoped_lock lock(mutex_); + isFifo_ = true; + } + + void SharedMessageQueue::SetLifoPolicy() + { + boost::mutex::scoped_lock lock(mutex_); + isFifo_ = false; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/MultiThreading/SharedMessageQueue.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,82 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../IDynamicObject.h" + +#include <stdint.h> +#include <list> +#include <boost/thread.hpp> + +namespace Orthanc +{ + class SharedMessageQueue : public boost::noncopyable + { + private: + typedef std::list<IDynamicObject*> Queue; + + bool isFifo_; + unsigned int maxSize_; + Queue queue_; + boost::mutex mutex_; + boost::condition_variable elementAvailable_; + boost::condition_variable emptied_; + + public: + explicit SharedMessageQueue(unsigned int maxSize = 0); + + ~SharedMessageQueue(); + + // This transfers the ownership of the message + void Enqueue(IDynamicObject* message); + + // The caller is responsible to delete the dequeud message! + IDynamicObject* Dequeue(int32_t millisecondsTimeout); + + bool WaitEmpty(int32_t millisecondsTimeout); + + bool IsFifoPolicy() const + { + return isFifo_; + } + + bool IsLifoPolicy() const + { + return !isFifo_; + } + + void SetFifoPolicy(); + + void SetLifoPolicy(); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/OrthancException.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,141 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "OrthancException.h" + +namespace Orthanc +{ + const char* OrthancException::What() const + { + if (error_ == ErrorCode_Custom) + { + return custom_.c_str(); + } + else + { + return GetDescription(error_); + } + } + + + const char* OrthancException::GetDescription(ErrorCode error) + { + switch (error) + { + case ErrorCode_Success: + return "Success"; + + case ErrorCode_ParameterOutOfRange: + return "Parameter out of range"; + + case ErrorCode_NotImplemented: + return "Not implemented yet"; + + case ErrorCode_InternalError: + return "Internal error"; + + case ErrorCode_NotEnoughMemory: + return "Not enough memory"; + + case ErrorCode_UriSyntax: + return "Badly formatted URI"; + + case ErrorCode_BadParameterType: + return "Bad type for a parameter"; + + case ErrorCode_InexistentFile: + return "Inexistent file"; + + case ErrorCode_BadFileFormat: + return "Bad file format"; + + case ErrorCode_CannotWriteFile: + return "Cannot write to file"; + + case ErrorCode_Timeout: + return "Timeout"; + + case ErrorCode_UnknownResource: + return "Unknown resource"; + + case ErrorCode_BadSequenceOfCalls: + return "Bad sequence of calls"; + + case ErrorCode_IncompatibleDatabaseVersion: + return "Incompatible version of the database"; + + case ErrorCode_FullStorage: + return "The file storage is full"; + + case ErrorCode_InexistentItem: + return "Accessing an inexistent item"; + + case ErrorCode_BadRequest: + return "Bad request"; + + case ErrorCode_NetworkProtocol: + return "Error in the network protocol"; + + case ErrorCode_CorruptedFile: + return "Corrupted file (inconsistent MD5 hash)"; + + case ErrorCode_InexistentTag: + return "Inexistent tag"; + + case ErrorCode_ReadOnly: + return "Cannot modify a read-only data structure"; + + case ErrorCode_IncompatibleImageSize: + return "Incompatible size of the images"; + + case ErrorCode_IncompatibleImageFormat: + return "Incompatible format of the images"; + + case ErrorCode_SharedLibrary: + return "Error while using a shared library (plugin)"; + + case ErrorCode_SystemCommand: + return "Error while calling a system command"; + + case ErrorCode_Plugin: + return "Error encountered inside a plugin"; + + case ErrorCode_Database: + return "Error with the database engine"; + + case ErrorCode_Custom: + default: + return "???"; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/OrthancException.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,72 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <string> +#include "Enumerations.h" + +namespace Orthanc +{ + class OrthancException + { + protected: + ErrorCode error_; + std::string custom_; + + public: + static const char* GetDescription(ErrorCode error); + + OrthancException(const char* custom) : + error_(ErrorCode_Custom), + custom_(custom) + { + } + + OrthancException(const std::string& custom) : + error_(ErrorCode_Custom), + custom_(custom) + { + } + + OrthancException(ErrorCode error) : error_(error) + { + } + + ErrorCode GetErrorCode() const + { + return error_; + } + + const char* What() const; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/PrecompiledHeaders.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,33 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/PrecompiledHeaders.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,61 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#if defined(_WIN32) && !defined(NOMINMAX) +#define NOMINMAX +#endif + +#if ORTHANC_USE_PRECOMPILED_HEADERS == 1 + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/filesystem.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/locale.hpp> +#include <boost/regex.hpp> +#include <boost/thread.hpp> +#include <boost/thread/shared_mutex.hpp> + +#include <glog/logging.h> +#include <json/value.h> + +#if ORTHANC_PUGIXML_ENABLED == 1 +#include <pugixml.hpp> +#endif + +#include "Enumerations.h" +#include "OrthancException.h" +#include "Toolbox.h" +#include "Uuid.h" + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Connection.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,393 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "Connection.h" +#include "OrthancSQLiteException.h" + +#include <memory> +#include <cassert> +#include <sqlite3.h> +#include <string.h> + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include <glog/logging.h> +#endif + + +namespace Orthanc +{ + namespace SQLite + { + Connection::Connection() : + db_(NULL), + transactionNesting_(0), + needsRollback_(false) + { + } + + + Connection::~Connection() + { + Close(); + } + + + void Connection::CheckIsOpen() const + { + if (!db_) + { + throw OrthancSQLiteException("SQLite: The database is not opened"); + } + } + + void Connection::Open(const std::string& path) + { + if (db_) + { + throw OrthancSQLiteException("SQLite: Connection is already open"); + } + + int err = sqlite3_open(path.c_str(), &db_); + if (err != SQLITE_OK) + { + Close(); + db_ = NULL; + throw OrthancSQLiteException("SQLite: Unable to open the database"); + } + + // Execute PRAGMAs at this point + // http://www.sqlite.org/pragma.html + Execute("PRAGMA FOREIGN_KEYS=ON;"); + Execute("PRAGMA RECURSIVE_TRIGGERS=ON;"); + } + + void Connection::OpenInMemory() + { + Open(":memory:"); + } + + void Connection::Close() + { + ClearCache(); + + if (db_) + { + sqlite3_close(db_); + db_ = NULL; + } + } + + void Connection::ClearCache() + { + for (CachedStatements::iterator + it = cachedStatements_.begin(); + it != cachedStatements_.end(); ++it) + { + delete it->second; + } + + cachedStatements_.clear(); + } + + + StatementReference& Connection::GetCachedStatement(const StatementId& id, + const char* sql) + { + CachedStatements::iterator i = cachedStatements_.find(id); + if (i != cachedStatements_.end()) + { + if (i->second->GetReferenceCount() >= 1) + { + throw OrthancSQLiteException("SQLite: This cached statement is already being referred to"); + } + + return *i->second; + } + else + { + StatementReference* statement = new StatementReference(db_, sql); + cachedStatements_[id] = statement; + return *statement; + } + } + + + bool Connection::Execute(const char* sql) + { +#if ORTHANC_SQLITE_STANDALONE != 1 + VLOG(1) << "SQLite::Connection::Execute " << sql; +#endif + + CheckIsOpen(); + + int error = sqlite3_exec(db_, sql, NULL, NULL, NULL); + if (error == SQLITE_ERROR) + { + throw OrthancSQLiteException("SQLite Execute error: " + std::string(sqlite3_errmsg(db_))); + } + else + { + return error == SQLITE_OK; + } + } + + int Connection::ExecuteAndReturnErrorCode(const char* sql) + { + CheckIsOpen(); + return sqlite3_exec(db_, sql, NULL, NULL, NULL); + } + + // Info querying ------------------------------------------------------------- + + bool Connection::IsSQLValid(const char* sql) + { + sqlite3_stmt* stmt = NULL; + if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) + return false; + + sqlite3_finalize(stmt); + return true; + } + + bool Connection::DoesTableOrIndexExist(const char* name, + const char* type) const + { + // Our SQL is non-mutating, so this cast is OK. + Statement statement(const_cast<Connection&>(*this), + "SELECT name FROM sqlite_master WHERE type=? AND name=?"); + statement.BindString(0, type); + statement.BindString(1, name); + return statement.Step(); // Table exists if any row was returned. + } + + bool Connection::DoesTableExist(const char* table_name) const + { + return DoesTableOrIndexExist(table_name, "table"); + } + + bool Connection::DoesIndexExist(const char* index_name) const + { + return DoesTableOrIndexExist(index_name, "index"); + } + + bool Connection::DoesColumnExist(const char* table_name, const char* column_name) const + { + std::string sql("PRAGMA TABLE_INFO("); + sql.append(table_name); + sql.append(")"); + + // Our SQL is non-mutating, so this cast is OK. + Statement statement(const_cast<Connection&>(*this), sql.c_str()); + + while (statement.Step()) { + if (!statement.ColumnString(1).compare(column_name)) + return true; + } + return false; + } + + int64_t Connection::GetLastInsertRowId() const + { + return sqlite3_last_insert_rowid(db_); + } + + int Connection::GetLastChangeCount() const + { + return sqlite3_changes(db_); + } + + int Connection::GetErrorCode() const + { + return sqlite3_errcode(db_); + } + + int Connection::GetLastErrno() const + { + int err = 0; + if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err)) + return -2; + + return err; + } + + const char* Connection::GetErrorMessage() const + { + return sqlite3_errmsg(db_); + } + + + bool Connection::BeginTransaction() + { + if (needsRollback_) + { + assert(transactionNesting_ > 0); + + // When we're going to rollback, fail on this begin and don't actually + // mark us as entering the nested transaction. + return false; + } + + bool success = true; + if (!transactionNesting_) + { + needsRollback_ = false; + + Statement begin(*this, SQLITE_FROM_HERE, "BEGIN TRANSACTION"); + if (!begin.Run()) + return false; + } + transactionNesting_++; + return success; + } + + void Connection::RollbackTransaction() + { + if (!transactionNesting_) + { + throw OrthancSQLiteException("Rolling back a nonexistent transaction"); + } + + transactionNesting_--; + + if (transactionNesting_ > 0) + { + // Mark the outermost transaction as needing rollback. + needsRollback_ = true; + return; + } + + DoRollback(); + } + + bool Connection::CommitTransaction() + { + if (!transactionNesting_) + { + throw OrthancSQLiteException("Committing a nonexistent transaction"); + } + transactionNesting_--; + + if (transactionNesting_ > 0) + { + // Mark any nested transactions as failing after we've already got one. + return !needsRollback_; + } + + if (needsRollback_) + { + DoRollback(); + return false; + } + + Statement commit(*this, SQLITE_FROM_HERE, "COMMIT"); + return commit.Run(); + } + + void Connection::DoRollback() + { + Statement rollback(*this, SQLITE_FROM_HERE, "ROLLBACK"); + rollback.Run(); + needsRollback_ = false; + } + + + + + + + static void ScalarFunctionCaller(sqlite3_context* rawContext, + int argc, + sqlite3_value** argv) + { + FunctionContext context(rawContext, argc, argv); + + void* payload = sqlite3_user_data(rawContext); + assert(payload != NULL); + + IScalarFunction& func = *reinterpret_cast<IScalarFunction*>(payload); + func.Compute(context); + } + + + static void ScalarFunctionDestroyer(void* payload) + { + assert(payload != NULL); + delete reinterpret_cast<IScalarFunction*>(payload); + } + + + IScalarFunction* Connection::Register(IScalarFunction* func) + { + int err = sqlite3_create_function_v2(db_, + func->GetName(), + func->GetCardinality(), + SQLITE_UTF8, + func, + ScalarFunctionCaller, + NULL, + NULL, + ScalarFunctionDestroyer); + + if (err != SQLITE_OK) + { + delete func; + throw OrthancSQLiteException("SQLite: Unable to register a function"); + } + + return func; + } + + + void Connection::FlushToDisk() + { +#if ORTHANC_SQLITE_STANDALONE != 1 + VLOG(1) << "SQLite::Connection::FlushToDisk"; +#endif + + int err = sqlite3_wal_checkpoint(db_, NULL); + + if (err != SQLITE_OK) + { + throw OrthancSQLiteException("SQLite: Unable to flush the database"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Connection.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,177 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "Statement.h" +#include "IScalarFunction.h" + +#include <string> +#include <map> + +struct sqlite3; +struct sqlite3_stmt; + +#define SQLITE_FROM_HERE SQLite::StatementId(__FILE__, __LINE__) + +namespace Orthanc +{ + namespace SQLite + { + class Connection : NonCopyable + { + friend class Statement; + friend class Transaction; + + private: + // All cached statements. Keeping a reference to these statements means that + // they'll remain active. + typedef std::map<StatementId, StatementReference*> CachedStatements; + CachedStatements cachedStatements_; + + // The actual sqlite database. Will be NULL before Init has been called or if + // Init resulted in an error. + sqlite3* db_; + + // Number of currently-nested transactions. + int transactionNesting_; + + // True if any of the currently nested transactions have been rolled back. + // When we get to the outermost transaction, this will determine if we do + // a rollback instead of a commit. + bool needsRollback_; + + void ClearCache(); + + void CheckIsOpen() const; + + sqlite3* GetWrappedObject() + { + return db_; + } + + StatementReference& GetCachedStatement(const StatementId& id, + const char* sql); + + bool DoesTableOrIndexExist(const char* name, + const char* type) const; + + void DoRollback(); + + public: + // The database is opened by calling Open[InMemory](). Any uncommitted + // transactions will be rolled back when this object is deleted. + Connection(); + ~Connection(); + + void Open(const std::string& path); + + void OpenInMemory(); + + void Close(); + + bool Execute(const char* sql); + + bool Execute(const std::string& sql) + { + return Execute(sql.c_str()); + } + + void FlushToDisk(); + + IScalarFunction* Register(IScalarFunction* func); // Takes the ownership of the function + + // Info querying ------------------------------------------------------------- + + // Used to check a |sql| statement for syntactic validity. If the + // statement is valid SQL, returns true. + bool IsSQLValid(const char* sql); + + // Returns true if the given table exists. + bool DoesTableExist(const char* table_name) const; + + // Returns true if the given index exists. + bool DoesIndexExist(const char* index_name) const; + + // Returns true if a column with the given name exists in the given table. + bool DoesColumnExist(const char* table_name, const char* column_name) const; + + // Returns sqlite's internal ID for the last inserted row. Valid only + // immediately after an insert. + int64_t GetLastInsertRowId() const; + + // Returns sqlite's count of the number of rows modified by the last + // statement executed. Will be 0 if no statement has executed or the database + // is closed. + int GetLastChangeCount() const; + + // Errors -------------------------------------------------------------------- + + // Returns the error code associated with the last sqlite operation. + int GetErrorCode() const; + + // Returns the errno associated with GetErrorCode(). See + // SQLITE_LAST_ERRNO in SQLite documentation. + int GetLastErrno() const; + + // Returns a pointer to a statically allocated string associated with the + // last sqlite operation. + const char* GetErrorMessage() const; + + + // Diagnostics (for unit tests) ---------------------------------------------- + + int ExecuteAndReturnErrorCode(const char* sql); + + bool HasCachedStatement(const StatementId& id) const + { + return cachedStatements_.find(id) != cachedStatements_.end(); + } + + int GetTransactionNesting() const + { + return transactionNesting_; + } + + // Transactions -------------------------------------------------------------- + + bool BeginTransaction(); + void RollbackTransaction(); + bool CommitTransaction(); + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/FunctionContext.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,125 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the CHU of Liege, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "FunctionContext.h" +#include "OrthancSQLiteException.h" + +#include <sqlite3.h> + +namespace Orthanc +{ + namespace SQLite + { + FunctionContext::FunctionContext(struct sqlite3_context* context, + int argc, + struct ::Mem** argv) + { + assert(context != NULL); + assert(argc >= 0); + assert(argv != NULL); + + context_ = context; + argc_ = static_cast<unsigned int>(argc); + argv_ = argv; + } + + void FunctionContext::CheckIndex(unsigned int index) const + { + if (index >= argc_) + { + throw OrthancSQLiteException("Parameter out of range"); + } + } + + ColumnType FunctionContext::GetColumnType(unsigned int index) const + { + CheckIndex(index); + return static_cast<SQLite::ColumnType>(sqlite3_value_type(argv_[index])); + } + + int FunctionContext::GetIntValue(unsigned int index) const + { + CheckIndex(index); + return sqlite3_value_int(argv_[index]); + } + + int64_t FunctionContext::GetInt64Value(unsigned int index) const + { + CheckIndex(index); + return sqlite3_value_int64(argv_[index]); + } + + double FunctionContext::GetDoubleValue(unsigned int index) const + { + CheckIndex(index); + return sqlite3_value_double(argv_[index]); + } + + std::string FunctionContext::GetStringValue(unsigned int index) const + { + CheckIndex(index); + return std::string(reinterpret_cast<const char*>(sqlite3_value_text(argv_[index]))); + } + + bool FunctionContext::IsNullValue(unsigned int index) const + { + CheckIndex(index); + return sqlite3_value_type(argv_[index]) == SQLITE_NULL; + } + + void FunctionContext::SetNullResult() + { + sqlite3_result_null(context_); + } + + void FunctionContext::SetIntResult(int value) + { + sqlite3_result_int(context_, value); + } + + void FunctionContext::SetDoubleResult(double value) + { + sqlite3_result_double(context_, value); + } + + void FunctionContext::SetStringResult(const std::string& str) + { + sqlite3_result_text(context_, str.data(), str.size(), SQLITE_TRANSIENT); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/FunctionContext.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,88 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the CHU of Liege, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "Statement.h" + +struct sqlite3_context; +struct Mem; // This corresponds to the opaque type "sqlite3_value" + +namespace Orthanc +{ + namespace SQLite + { + class FunctionContext : public NonCopyable + { + friend class Connection; + + private: + struct sqlite3_context* context_; + unsigned int argc_; + struct ::Mem** argv_; + + void CheckIndex(unsigned int index) const; + + public: + FunctionContext(struct sqlite3_context* context, + int argc, + struct ::Mem** argv); + + ColumnType GetColumnType(unsigned int index) const; + + unsigned int GetParameterCount() const + { + return argc_; + } + + int GetIntValue(unsigned int index) const; + + int64_t GetInt64Value(unsigned int index) const; + + double GetDoubleValue(unsigned int index) const; + + std::string GetStringValue(unsigned int index) const; + + bool IsNullValue(unsigned int index) const; + + void SetNullResult(); + + void SetIntResult(int value); + + void SetDoubleResult(double value); + + void SetStringResult(const std::string& str); + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/IScalarFunction.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,58 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the CHU of Liege, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "NonCopyable.h" +#include "FunctionContext.h" + +namespace Orthanc +{ + namespace SQLite + { + class IScalarFunction : public NonCopyable + { + public: + virtual ~IScalarFunction() + { + } + + virtual const char* GetName() const = 0; + + virtual unsigned int GetCardinality() const = 0; + + virtual void Compute(FunctionContext& context) = 0; + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/ITransaction.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,66 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "NonCopyable.h" + +namespace Orthanc +{ + namespace SQLite + { + class ITransaction : public NonCopyable + { + public: + virtual ~ITransaction() + { + } + + // Begins the transaction. This uses the default sqlite "deferred" transaction + // type, which means that the DB lock is lazily acquired the next time the + // database is accessed, not in the begin transaction command. + virtual void Begin() = 0; + + // Rolls back the transaction. This will happen automatically if you do + // nothing when the transaction goes out of scope. + virtual void Rollback() = 0; + + // Commits the transaction, returning true on success. + virtual void Commit() = 0; + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/NonCopyable.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,60 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +namespace Orthanc +{ + namespace SQLite + { + // This class mimics "boost::noncopyable" + class NonCopyable + { + private: + NonCopyable(const NonCopyable&); + + NonCopyable& operator= (const NonCopyable&); + + protected: + NonCopyable() + { + } + + ~NonCopyable() + { + } + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/OrthancSQLiteException.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,67 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + + +#if ORTHANC_SQLITE_STANDALONE == 1 +#include <stdexcept> + +namespace Orthanc +{ + namespace SQLite + { + class OrthancSQLiteException : public ::std::runtime_error + { + public: + OrthancSQLiteException(const std::string& what) : + ::std::runtime_error(what) + { + } + + OrthancSQLiteException(const char* what) : + ::std::runtime_error(what) + { + } + }; + } +} + +#else +# include "../OrthancException.h" +# define OrthancSQLiteException ::Orthanc::OrthancException +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Statement.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,340 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "Statement.h" +#include "Connection.h" + +#include <sqlite3.h> +#include <string.h> +#include <stdio.h> +#include <algorithm> + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include <glog/logging.h> +#endif + +#if defined(_MSC_VER) +#define snprintf _snprintf +#endif + +namespace Orthanc +{ + namespace SQLite + { + int Statement::CheckError(int err) const + { + bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE); + if (!succeeded) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); + throw OrthancSQLiteException(buffer); + } + + return err; + } + + void Statement::CheckOk(int err) const + { + if (err == SQLITE_RANGE) + { + // Binding to a non-existent variable is evidence of a serious error. + throw OrthancSQLiteException("Bind value out of range"); + } + else if (err != SQLITE_OK) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); + throw OrthancSQLiteException(buffer); + } + } + + + Statement::Statement(Connection& database, + const StatementId& id, + const std::string& sql) : + reference_(database.GetCachedStatement(id, sql.c_str())) + { + Reset(true); + } + + + Statement::Statement(Connection& database, + const StatementId& id, + const char* sql) : + reference_(database.GetCachedStatement(id, sql)) + { + Reset(true); + } + + + Statement::Statement(Connection& database, + const std::string& sql) : + reference_(database.GetWrappedObject(), sql.c_str()) + { + } + + + Statement::Statement(Connection& database, + const char* sql) : + reference_(database.GetWrappedObject(), sql) + { + } + + + bool Statement::Run() + { +#if ORTHANC_SQLITE_STANDALONE != 1 + VLOG(1) << "SQLite::Statement::Run " << sqlite3_sql(GetStatement()); +#endif + + return CheckError(sqlite3_step(GetStatement())) == SQLITE_DONE; + } + + bool Statement::Step() + { +#if ORTHANC_SQLITE_STANDALONE != 1 + VLOG(1) << "SQLite::Statement::Step " << sqlite3_sql(GetStatement()); +#endif + + return CheckError(sqlite3_step(GetStatement())) == SQLITE_ROW; + } + + void Statement::Reset(bool clear_bound_vars) + { + // We don't call CheckError() here because sqlite3_reset() returns + // the last error that Step() caused thereby generating a second + // spurious error callback. + if (clear_bound_vars) + sqlite3_clear_bindings(GetStatement()); + //VLOG(1) << "SQLite::Statement::Reset"; + sqlite3_reset(GetStatement()); + } + + std::string Statement::GetOriginalSQLStatement() + { + return std::string(sqlite3_sql(GetStatement())); + } + + + void Statement::BindNull(int col) + { + CheckOk(sqlite3_bind_null(GetStatement(), col + 1)); + } + + void Statement::BindBool(int col, bool val) + { + BindInt(col, val ? 1 : 0); + } + + void Statement::BindInt(int col, int val) + { + CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val)); + } + + void Statement::BindInt64(int col, int64_t val) + { + CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val)); + } + + void Statement::BindDouble(int col, double val) + { + CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val)); + } + + void Statement::BindCString(int col, const char* val) + { + CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT)); + } + + void Statement::BindString(int col, const std::string& val) + { + CheckOk(sqlite3_bind_text(GetStatement(), + col + 1, + val.data(), + val.size(), + SQLITE_TRANSIENT)); + } + + /*void Statement::BindString16(int col, const string16& value) + { + BindString(col, UTF16ToUTF8(value)); + }*/ + + void Statement::BindBlob(int col, const void* val, int val_len) + { + CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT)); + } + + + int Statement::ColumnCount() const + { + return sqlite3_column_count(GetStatement()); + } + + + ColumnType Statement::GetColumnType(int col) const + { + // Verify that our enum matches sqlite's values. + assert(COLUMN_TYPE_INTEGER == SQLITE_INTEGER); + assert(COLUMN_TYPE_FLOAT == SQLITE_FLOAT); + assert(COLUMN_TYPE_TEXT == SQLITE_TEXT); + assert(COLUMN_TYPE_BLOB == SQLITE_BLOB); + assert(COLUMN_TYPE_NULL == SQLITE_NULL); + + return static_cast<ColumnType>(sqlite3_column_type(GetStatement(), col)); + } + + ColumnType Statement::GetDeclaredColumnType(int col) const + { + std::string column_type(sqlite3_column_decltype(GetStatement(), col)); + std::transform(column_type.begin(), column_type.end(), column_type.begin(), tolower); + + if (column_type == "integer") + return COLUMN_TYPE_INTEGER; + else if (column_type == "float") + return COLUMN_TYPE_FLOAT; + else if (column_type == "text") + return COLUMN_TYPE_TEXT; + else if (column_type == "blob") + return COLUMN_TYPE_BLOB; + + return COLUMN_TYPE_NULL; + } + + bool Statement::ColumnIsNull(int col) const + { + return sqlite3_column_type(GetStatement(), col) == SQLITE_NULL; + } + + bool Statement::ColumnBool(int col) const + { + return !!ColumnInt(col); + } + + int Statement::ColumnInt(int col) const + { + return sqlite3_column_int(GetStatement(), col); + } + + int64_t Statement::ColumnInt64(int col) const + { + return sqlite3_column_int64(GetStatement(), col); + } + + double Statement::ColumnDouble(int col) const + { + return sqlite3_column_double(GetStatement(), col); + } + + std::string Statement::ColumnString(int col) const + { + const char* str = reinterpret_cast<const char*>( + sqlite3_column_text(GetStatement(), col)); + int len = sqlite3_column_bytes(GetStatement(), col); + + std::string result; + if (str && len > 0) + result.assign(str, len); + return result; + } + + /*string16 Statement::ColumnString16(int col) const + { + std::string s = ColumnString(col); + return !s.empty() ? UTF8ToUTF16(s) : string16(); + }*/ + + int Statement::ColumnByteLength(int col) const + { + return sqlite3_column_bytes(GetStatement(), col); + } + + const void* Statement::ColumnBlob(int col) const + { + return sqlite3_column_blob(GetStatement(), col); + } + + bool Statement::ColumnBlobAsString(int col, std::string* blob) + { + const void* p = ColumnBlob(col); + size_t len = ColumnByteLength(col); + blob->resize(len); + if (blob->size() != len) { + return false; + } + blob->assign(reinterpret_cast<const char*>(p), len); + return true; + } + + /*bool Statement::ColumnBlobAsString16(int col, string16* val) const + { + const void* data = ColumnBlob(col); + size_t len = ColumnByteLength(col) / sizeof(char16); + val->resize(len); + if (val->size() != len) + return false; + val->assign(reinterpret_cast<const char16*>(data), len); + return true; + }*/ + + /*bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const + { + val->clear(); + + const void* data = sqlite3_column_blob(GetStatement(), col); + int len = sqlite3_column_bytes(GetStatement(), col); + if (data && len > 0) { + val->resize(len); + memcpy(&(*val)[0], data, len); + } + return true; + }*/ + + /*bool Statement::ColumnBlobAsVector( + int col, + std::vector<unsigned char>* val) const + { + return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val)); + }*/ + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Statement.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,174 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "NonCopyable.h" +#include "OrthancSQLiteException.h" +#include "StatementId.h" +#include "StatementReference.h" + +#include <vector> +#include <stdint.h> + +#if ORTHANC_BUILD_UNIT_TESTS == 1 +#include <gtest/gtest_prod.h> +#endif + +struct sqlite3_stmt; + + +namespace Orthanc +{ + namespace SQLite + { + class Connection; + + // Possible return values from ColumnType in a statement. These + // should match the values in sqlite3.h. + enum ColumnType + { + COLUMN_TYPE_INTEGER = 1, + COLUMN_TYPE_FLOAT = 2, + COLUMN_TYPE_TEXT = 3, + COLUMN_TYPE_BLOB = 4, + COLUMN_TYPE_NULL = 5 + }; + + class Statement : public NonCopyable + { + friend class Connection; + +#if ORTHANC_BUILD_UNIT_TESTS == 1 + FRIEND_TEST(SQLStatementTest, Run); + FRIEND_TEST(SQLStatementTest, Reset); +#endif + + private: + StatementReference reference_; + + int CheckError(int err) const; + + void CheckOk(int err) const; + + struct sqlite3_stmt* GetStatement() const + { + return reference_.GetWrappedObject(); + } + + public: + Statement(Connection& database, + const std::string& sql); + + Statement(Connection& database, + const StatementId& id, + const std::string& sql); + + Statement(Connection& database, + const char* sql); + + Statement(Connection& database, + const StatementId& id, + const char* sql); + + ~Statement() + { + Reset(); + } + + bool Run(); + + bool Step(); + + // Diagnostics -------------------------------------------------------------- + + std::string GetOriginalSQLStatement(); + + + // Binding ------------------------------------------------------------------- + + // These all take a 0-based argument index + void BindNull(int col); + void BindBool(int col, bool val); + void BindInt(int col, int val); + void BindInt64(int col, int64_t val); + void BindDouble(int col, double val); + void BindCString(int col, const char* val); + void BindString(int col, const std::string& val); + //void BindString16(int col, const string16& value); + void BindBlob(int col, const void* value, int value_len); + + + // Retrieving ---------------------------------------------------------------- + + // Returns the number of output columns in the result. + int ColumnCount() const; + + // Returns the type associated with the given column. + // + // Watch out: the type may be undefined if you've done something to cause a + // "type conversion." This means requesting the value of a column of a type + // where that type is not the native type. For safety, call ColumnType only + // on a column before getting the value out in any way. + ColumnType GetColumnType(int col) const; + ColumnType GetDeclaredColumnType(int col) const; + + // These all take a 0-based argument index. + bool ColumnIsNull(int col) const ; + bool ColumnBool(int col) const; + int ColumnInt(int col) const; + int64_t ColumnInt64(int col) const; + double ColumnDouble(int col) const; + std::string ColumnString(int col) const; + //string16 ColumnString16(int col) const; + + // When reading a blob, you can get a raw pointer to the underlying data, + // along with the length, or you can just ask us to copy the blob into a + // vector. Danger! ColumnBlob may return NULL if there is no data! + int ColumnByteLength(int col) const; + const void* ColumnBlob(int col) const; + bool ColumnBlobAsString(int col, std::string* blob); + //bool ColumnBlobAsString16(int col, string16* val) const; + //bool ColumnBlobAsVector(int col, std::vector<char>* val) const; + //bool ColumnBlobAsVector(int col, std::vector<unsigned char>* val) const; + + // Resets the statement to its initial condition. This includes any current + // result row, and also the bound variables if the |clear_bound_vars| is true. + void Reset(bool clear_bound_vars = true); + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/StatementId.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,58 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "StatementId.h" + +#include <string.h> + +namespace Orthanc +{ + namespace SQLite + { + bool StatementId::operator< (const StatementId& other) const + { + if (line_ != other.line_) + return line_ < other.line_; + + return strcmp(file_, other.file_) < 0; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/StatementId.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,60 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +namespace Orthanc +{ + namespace SQLite + { + class StatementId + { + private: + const char* file_; + int line_; + + StatementId(); // Forbidden + + public: + StatementId(const char* file, int line) : file_(file), line_(line) + { + } + + bool operator< (const StatementId& other) const; + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/StatementReference.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,152 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "StatementReference.h" +#include "OrthancSQLiteException.h" + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include <glog/logging.h> +#endif + +#include <string> +#include <cassert> +#include "sqlite3.h" + +namespace Orthanc +{ + namespace SQLite + { + bool StatementReference::IsRoot() const + { + return root_ == NULL; + } + + StatementReference::StatementReference() + { + root_ = NULL; + refCount_ = 0; + statement_ = NULL; + assert(IsRoot()); + } + + StatementReference::StatementReference(sqlite3* database, + const char* sql) + { + if (database == NULL || sql == NULL) + { + throw OrthancSQLiteException("Parameter out of range"); + } + + root_ = NULL; + refCount_ = 0; + + int error = sqlite3_prepare_v2(database, sql, -1, &statement_, NULL); + if (error != SQLITE_OK) + { + throw OrthancSQLiteException("SQLite: " + std::string(sqlite3_errmsg(database))); + } + + assert(IsRoot()); + } + + StatementReference::StatementReference(StatementReference& other) + { + refCount_ = 0; + + if (other.IsRoot()) + { + root_ = &other; + } + else + { + root_ = other.root_; + } + + root_->refCount_++; + statement_ = root_->statement_; + + assert(!IsRoot()); + } + + StatementReference::~StatementReference() + { + if (IsRoot()) + { + if (refCount_ != 0) + { + // There remain references to this object. We cannot throw + // an exception because: + // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html + +#if ORTHANC_SQLITE_STANDALONE != 1 + LOG(ERROR) << "Bad value of the reference counter"; +#endif + } + else if (statement_ != NULL) + { + sqlite3_finalize(statement_); + } + } + else + { + if (root_->refCount_ == 0) + { + // There remain references to this object. We cannot throw + // an exception because: + // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html + +#if ORTHANC_SQLITE_STANDALONE != 1 + LOG(ERROR) << "Bad value of the reference counter"; +#endif + } + else + { + root_->refCount_--; + } + } + } + + uint32_t StatementReference::GetReferenceCount() const + { + return refCount_; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/StatementReference.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,81 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "NonCopyable.h" + +#include <stdint.h> +#include <cassert> +#include <stdlib.h> + +struct sqlite3; +struct sqlite3_stmt; + +namespace Orthanc +{ + namespace SQLite + { + class StatementReference : NonCopyable + { + private: + StatementReference* root_; // Only used for non-root nodes + uint32_t refCount_; // Only used for root node + struct sqlite3_stmt* statement_; + + bool IsRoot() const; + + public: + StatementReference(); + + StatementReference(sqlite3* database, + const char* sql); + + StatementReference(StatementReference& other); + + ~StatementReference(); + + uint32_t GetReferenceCount() const; + + struct sqlite3_stmt* GetWrappedObject() const + { + assert(statement_ != NULL); + return statement_; + } + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Transaction.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,106 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#if ORTHANC_SQLITE_STANDALONE != 1 +#include "../PrecompiledHeaders.h" +#endif + +#include "Transaction.h" +#include "OrthancSQLiteException.h" + +namespace Orthanc +{ + namespace SQLite + { + Transaction::Transaction(Connection& connection) : + connection_(connection), + isOpen_(false) + { + } + + Transaction::~Transaction() + { + if (isOpen_) + { + connection_.RollbackTransaction(); + } + } + + void Transaction::Begin() + { + if (isOpen_) + { + throw OrthancSQLiteException("SQLite: Beginning a transaction twice!"); + } + + isOpen_ = connection_.BeginTransaction(); + if (!isOpen_) + { + throw OrthancSQLiteException("SQLite: Unable to create a transaction"); + } + } + + void Transaction::Rollback() + { + if (!isOpen_) + { + throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. " + "Did you remember to call Begin()?"); + } + + isOpen_ = false; + + connection_.RollbackTransaction(); + } + + void Transaction::Commit() + { + if (!isOpen_) + { + throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. " + "Did you remember to call Begin()?"); + } + + isOpen_ = false; + + if (!connection_.CommitTransaction()) + { + throw OrthancSQLiteException("SQLite: Failure when committing the transaction"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/SQLite/Transaction.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,71 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * + * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, + * Medical Physics Department, CHU of Liege, Belgium + * + * Copyright (c) 2012 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc., the name of the CHU of Liege, + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **/ + + +#pragma once + +#include "Connection.h" +#include "ITransaction.h" + +namespace Orthanc +{ + namespace SQLite + { + class Transaction : public ITransaction + { + private: + Connection& connection_; + + // True when the transaction is open, false when it's already been committed + // or rolled back. + bool isOpen_; + + public: + explicit Transaction(Connection& connection); + + virtual ~Transaction(); + + // Returns true when there is a transaction that has been successfully begun. + bool IsOpen() const { return isOpen_; } + + virtual void Begin(); + + virtual void Rollback(); + + virtual void Commit(); + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Toolbox.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,1141 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "Toolbox.h" + +#include "OrthancException.h" + +#include <string> +#include <stdint.h> +#include <string.h> +#include <boost/filesystem.hpp> +#include <boost/filesystem/fstream.hpp> +#include <boost/uuid/sha1.hpp> +#include <boost/lexical_cast.hpp> +#include <algorithm> +#include <ctype.h> + +#if BOOST_HAS_DATE_TIME == 1 +#include <boost/date_time/posix_time/posix_time.hpp> +#endif + +#if BOOST_HAS_REGEX == 1 +#include <boost/regex.hpp> +#endif + +#if HAVE_GOOGLE_LOG == 1 +#include <glog/logging.h> +#endif + +#if defined(_WIN32) +#include <windows.h> +#include <process.h> // For "_spawnvp()" +#else +#include <unistd.h> // For "execvp()" +#include <sys/wait.h> // For "waitpid()" +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include <mach-o/dyld.h> /* _NSGetExecutablePath */ +#include <limits.h> /* PATH_MAX */ +#endif + +#if defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) +#include <limits.h> /* PATH_MAX */ +#include <signal.h> +#include <unistd.h> +#endif + +#if BOOST_HAS_LOCALE != 1 +#error Since version 0.7.6, Orthanc entirely relies on boost::locale +#endif + +#include <boost/locale.hpp> + +#include "../Resources/ThirdParty/md5/md5.h" +#include "../Resources/ThirdParty/base64/base64.h" + + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +// Patch for the missing "_strtoll" symbol when compiling with Visual Studio < 2013 +extern "C" +{ + int64_t _strtoi64(const char *nptr, char **endptr, int base); + int64_t strtoll(const char *nptr, char **endptr, int base) + { + return _strtoi64(nptr, endptr, base); + } +} +#endif + + +#if ORTHANC_PUGIXML_ENABLED == 1 +#include "ChunkedBuffer.h" +#include <pugixml.hpp> +#endif + + +namespace Orthanc +{ + static bool finish; + +#if defined(_WIN32) + static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) + { + // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx + finish = true; + return true; + } +#else + static void SignalHandler(int) + { + finish = true; + } +#endif + + void Toolbox::USleep(uint64_t microSeconds) + { +#if defined(_WIN32) + ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000))); +#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) + usleep(microSeconds); +#else +#error Support your platform here +#endif + } + + + static void ServerBarrierInternal(const bool* stopFlag) + { +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, true); +#else + signal(SIGINT, SignalHandler); + signal(SIGQUIT, SignalHandler); + signal(SIGTERM, SignalHandler); +#endif + + // Active loop that awakens every 100ms + finish = false; + while (!(*stopFlag || finish)) + { + Toolbox::USleep(100 * 1000); + } + +#if defined(_WIN32) + SetConsoleCtrlHandler(ConsoleControlHandler, false); +#else + signal(SIGINT, NULL); + signal(SIGQUIT, NULL); + signal(SIGTERM, NULL); +#endif + } + + + void Toolbox::ServerBarrier(const bool& stopFlag) + { + ServerBarrierInternal(&stopFlag); + } + + void Toolbox::ServerBarrier() + { + const bool stopFlag = false; + ServerBarrierInternal(&stopFlag); + } + + + void Toolbox::ToUpperCase(std::string& s) + { + std::transform(s.begin(), s.end(), s.begin(), toupper); + } + + + void Toolbox::ToLowerCase(std::string& s) + { + std::transform(s.begin(), s.end(), s.begin(), tolower); + } + + + void Toolbox::ToUpperCase(std::string& result, + const std::string& source) + { + result = source; + ToUpperCase(result); + } + + void Toolbox::ToLowerCase(std::string& result, + const std::string& source) + { + result = source; + ToLowerCase(result); + } + + + void Toolbox::ReadFile(std::string& content, + const std::string& path) + { + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile); + } + + // http://www.cplusplus.com/reference/iostream/istream/tellg/ + f.seekg(0, std::ios::end); + std::streamsize size = f.tellg(); + f.seekg(0, std::ios::beg); + + content.resize(size); + if (size != 0) + { + f.read(reinterpret_cast<char*>(&content[0]), size); + } + + f.close(); + } + + + void Toolbox::WriteFile(const std::string& content, + const std::string& path) + { + boost::filesystem::ofstream f; + f.open(path, std::ofstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_CannotWriteFile); + } + + if (content.size() != 0) + { + f.write(content.c_str(), content.size()); + } + + f.close(); + } + + + + void Toolbox::RemoveFile(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (boost::filesystem::is_regular_file(path)) + boost::filesystem::remove(path); + else + throw OrthancException("The path is not a regular file: " + path); + } + } + + + + void Toolbox::SplitUriComponents(UriComponents& components, + const std::string& uri) + { + static const char URI_SEPARATOR = '/'; + + components.clear(); + + if (uri.size() == 0 || + uri[0] != URI_SEPARATOR) + { + throw OrthancException(ErrorCode_UriSyntax); + } + + // Count the number of slashes in the URI to make an assumption + // about the number of components in the URI + unsigned int estimatedSize = 0; + for (unsigned int i = 0; i < uri.size(); i++) + { + if (uri[i] == URI_SEPARATOR) + estimatedSize++; + } + + components.reserve(estimatedSize - 1); + + unsigned int start = 1; + unsigned int end = 1; + while (end < uri.size()) + { + // This is the loop invariant + assert(uri[start - 1] == '/' && (end >= start)); + + if (uri[end] == '/') + { + components.push_back(std::string(&uri[start], end - start)); + end++; + start = end; + } + else + { + end++; + } + } + + if (start < uri.size()) + { + components.push_back(std::string(&uri[start], end - start)); + } + + for (size_t i = 0; i < components.size(); i++) + { + if (components[i].size() == 0) + { + // Empty component, as in: "/coucou//e" + throw OrthancException(ErrorCode_UriSyntax); + } + } + } + + + void Toolbox::TruncateUri(UriComponents& target, + const UriComponents& source, + size_t fromLevel) + { + target.clear(); + + if (source.size() > fromLevel) + { + target.resize(source.size() - fromLevel); + + size_t j = 0; + for (size_t i = fromLevel; i < source.size(); i++, j++) + { + target[j] = source[i]; + } + + assert(j == target.size()); + } + } + + + + bool Toolbox::IsChildUri(const UriComponents& baseUri, + const UriComponents& testedUri) + { + if (testedUri.size() < baseUri.size()) + { + return false; + } + + for (size_t i = 0; i < baseUri.size(); i++) + { + if (baseUri[i] != testedUri[i]) + return false; + } + + return true; + } + + + std::string Toolbox::AutodetectMimeType(const std::string& path) + { + std::string contentType; + size_t lastDot = path.rfind('.'); + size_t lastSlash = path.rfind('/'); + + if (lastDot == std::string::npos || + (lastSlash != std::string::npos && lastDot < lastSlash)) + { + // No trailing dot, unable to detect the content type + } + else + { + const char* extension = &path[lastDot + 1]; + + // http://en.wikipedia.org/wiki/Mime_types + // Text types + if (!strcmp(extension, "txt")) + contentType = "text/plain"; + else if (!strcmp(extension, "html")) + contentType = "text/html"; + else if (!strcmp(extension, "xml")) + contentType = "text/xml"; + else if (!strcmp(extension, "css")) + contentType = "text/css"; + + // Application types + else if (!strcmp(extension, "js")) + contentType = "application/javascript"; + else if (!strcmp(extension, "json")) + contentType = "application/json"; + else if (!strcmp(extension, "pdf")) + contentType = "application/pdf"; + + // Images types + else if (!strcmp(extension, "jpg") || !strcmp(extension, "jpeg")) + contentType = "image/jpeg"; + else if (!strcmp(extension, "gif")) + contentType = "image/gif"; + else if (!strcmp(extension, "png")) + contentType = "image/png"; + } + + return contentType; + } + + + std::string Toolbox::FlattenUri(const UriComponents& components, + size_t fromLevel) + { + if (components.size() <= fromLevel) + { + return "/"; + } + else + { + std::string r; + + for (size_t i = fromLevel; i < components.size(); i++) + { + r += "/" + components[i]; + } + + return r; + } + } + + + + uint64_t Toolbox::GetFileSize(const std::string& path) + { + try + { + return static_cast<uint64_t>(boost::filesystem::file_size(path)); + } + catch (boost::filesystem::filesystem_error) + { + throw OrthancException(ErrorCode_InexistentFile); + } + } + + + static char GetHexadecimalCharacter(uint8_t value) + { + assert(value < 16); + + if (value < 10) + return value + '0'; + else + return (value - 10) + 'a'; + } + + + void Toolbox::ComputeMD5(std::string& result, + const std::string& data) + { + if (data.size() > 0) + { + ComputeMD5(result, &data[0], data.size()); + } + else + { + ComputeMD5(result, NULL, 0); + } + } + + + void Toolbox::ComputeMD5(std::string& result, + const void* data, + size_t length) + { + md5_state_s state; + md5_init(&state); + + if (length > 0) + { + md5_append(&state, + reinterpret_cast<const md5_byte_t*>(data), + static_cast<int>(length)); + } + + md5_byte_t actualHash[16]; + md5_finish(&state, actualHash); + + result.resize(32); + for (unsigned int i = 0; i < 16; i++) + { + result[2 * i] = GetHexadecimalCharacter(actualHash[i] / 16); + result[2 * i + 1] = GetHexadecimalCharacter(actualHash[i] % 16); + } + } + + + void Toolbox::EncodeBase64(std::string& result, + const std::string& data) + { + result = base64_encode(data); + } + + void Toolbox::DecodeBase64(std::string& result, + const std::string& data) + { + result = base64_decode(data); + } + + +#if defined(_WIN32) + static std::string GetPathToExecutableInternal() + { + // Yes, this is ugly, but there is no simple way to get the + // required buffer size, so we use a big constant + std::vector<char> buffer(32768); + /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1)); + return std::string(&buffer[0]); + } + +#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) + static std::string GetPathToExecutableInternal() + { + std::vector<char> buffer(PATH_MAX + 1); + ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); + if (bytes == 0) + { + throw OrthancException("Unable to get the path to the executable"); + } + + return std::string(&buffer[0]); + } + +#elif defined(__APPLE__) && defined(__MACH__) + static std::string GetPathToExecutableInternal() + { + char pathbuf[PATH_MAX + 1]; + unsigned int bufsize = static_cast<int>(sizeof(pathbuf)); + + _NSGetExecutablePath( pathbuf, &bufsize); + + return std::string(pathbuf); + } + +#else +#error Support your platform here +#endif + + + std::string Toolbox::GetPathToExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p).string(); + } + + + std::string Toolbox::GetDirectoryOfExecutable() + { + boost::filesystem::path p(GetPathToExecutableInternal()); + return boost::filesystem::absolute(p.parent_path()).string(); + } + + + std::string Toolbox::ConvertToUtf8(const std::string& source, + const Encoding sourceEncoding) + { + const char* encoding; + + + // http://bradleyross.users.sourceforge.net/docs/dicom/doc/src-html/org/dcm4che2/data/SpecificCharacterSet.html + switch (sourceEncoding) + { + case Encoding_Utf8: + // Already in UTF-8: No conversion is required + return source; + + case Encoding_Ascii: + return ConvertToAscii(source); + + case Encoding_Latin1: + encoding = "ISO-8859-1"; + break; + + case Encoding_Latin2: + encoding = "ISO-8859-2"; + break; + + case Encoding_Latin3: + encoding = "ISO-8859-3"; + break; + + case Encoding_Latin4: + encoding = "ISO-8859-4"; + break; + + case Encoding_Latin5: + encoding = "ISO-8859-9"; + break; + + case Encoding_Cyrillic: + encoding = "ISO-8859-5"; + break; + + case Encoding_Windows1251: + encoding = "WINDOWS-1251"; + break; + + case Encoding_Arabic: + encoding = "ISO-8859-6"; + break; + + case Encoding_Greek: + encoding = "ISO-8859-7"; + break; + + case Encoding_Hebrew: + encoding = "ISO-8859-8"; + break; + + case Encoding_Japanese: + encoding = "SHIFT-JIS"; + break; + + case Encoding_Chinese: + encoding = "GB18030"; + break; + + case Encoding_Thai: + encoding = "TIS620.2533-0"; + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + + try + { + return boost::locale::conv::to_utf<char>(source, encoding); + } + catch (std::runtime_error&) + { + // Bad input string or bad encoding + return ConvertToAscii(source); + } + } + + + std::string Toolbox::ConvertToAscii(const std::string& source) + { + std::string result; + + result.reserve(source.size() + 1); + for (size_t i = 0; i < source.size(); i++) + { + if (source[i] <= 127 && source[i] >= 0 && !iscntrl(source[i])) + { + result.push_back(source[i]); + } + } + + return result; + } + + void Toolbox::ComputeSHA1(std::string& result, + const std::string& data) + { + boost::uuids::detail::sha1 sha1; + + if (data.size() > 0) + { + sha1.process_bytes(&data[0], data.size()); + } + + unsigned int digest[5]; + + // Sanity check for the memory layout: A SHA-1 digest is 160 bits wide + assert(sizeof(unsigned int) == 4 && sizeof(digest) == (160 / 8)); + + sha1.get_digest(digest); + + result.resize(8 * 5 + 4); + sprintf(&result[0], "%08x-%08x-%08x-%08x-%08x", + digest[0], + digest[1], + digest[2], + digest[3], + digest[4]); + } + + bool Toolbox::IsSHA1(const std::string& str) + { + if (str.size() != 44) + { + return false; + } + + for (unsigned int i = 0; i < 44; i++) + { + if (i == 8 || + i == 17 || + i == 26 || + i == 35) + { + if (str[i] != '-') + return false; + } + else + { + if (!isalnum(str[i])) + return false; + } + } + + return true; + } + + +#if BOOST_HAS_DATE_TIME == 1 + std::string Toolbox::GetNowIsoString() + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + return boost::posix_time::to_iso_string(now); + } +#endif + + + std::string Toolbox::StripSpaces(const std::string& source) + { + size_t first = 0; + + while (first < source.length() && + isspace(source[first])) + { + first++; + } + + if (first == source.length()) + { + // String containing only spaces + return ""; + } + + size_t last = source.length(); + while (last > first && + isspace(source[last - 1])) + { + last--; + } + + assert(first <= last); + return source.substr(first, last - first); + } + + + static char Hex2Dec(char c) + { + return ((c >= '0' && c <= '9') ? c - '0' : + ((c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - 'A' + 10)); + } + + void Toolbox::UrlDecode(std::string& s) + { + // http://en.wikipedia.org/wiki/Percent-encoding + // http://www.w3schools.com/tags/ref_urlencode.asp + // http://stackoverflow.com/questions/154536/encode-decode-urls-in-c + + if (s.size() == 0) + { + return; + } + + size_t source = 0; + size_t target = 0; + + while (source < s.size()) + { + if (s[source] == '%' && + source + 2 < s.size() && + isalnum(s[source + 1]) && + isalnum(s[source + 2])) + { + s[target] = (Hex2Dec(s[source + 1]) << 4) | Hex2Dec(s[source + 2]); + source += 3; + target += 1; + } + else + { + if (s[source] == '+') + s[target] = ' '; + else + s[target] = s[source]; + + source++; + target++; + } + } + + s.resize(target); + } + + + Endianness Toolbox::DetectEndianness() + { + // http://sourceforge.net/p/predef/wiki/Endianness/ + + uint8_t buffer[4]; + + buffer[0] = 0x00; + buffer[1] = 0x01; + buffer[2] = 0x02; + buffer[3] = 0x03; + + switch (*((uint32_t *)buffer)) + { + case 0x00010203: + return Endianness_Big; + + case 0x03020100: + return Endianness_Little; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + +#if BOOST_HAS_REGEX == 1 + std::string Toolbox::WildcardToRegularExpression(const std::string& source) + { + // TODO - Speed up this with a regular expression + + std::string result = source; + + // Escape all special characters + boost::replace_all(result, "\\", "\\\\"); + boost::replace_all(result, "^", "\\^"); + boost::replace_all(result, ".", "\\."); + boost::replace_all(result, "$", "\\$"); + boost::replace_all(result, "|", "\\|"); + boost::replace_all(result, "(", "\\("); + boost::replace_all(result, ")", "\\)"); + boost::replace_all(result, "[", "\\["); + boost::replace_all(result, "]", "\\]"); + boost::replace_all(result, "+", "\\+"); + boost::replace_all(result, "/", "\\/"); + boost::replace_all(result, "{", "\\{"); + boost::replace_all(result, "}", "\\}"); + + // Convert wildcards '*' and '?' to their regex equivalents + boost::replace_all(result, "?", "."); + boost::replace_all(result, "*", ".*"); + + return result; + } +#endif + + + + void Toolbox::TokenizeString(std::vector<std::string>& result, + const std::string& value, + char separator) + { + result.clear(); + + std::string currentItem; + + for (size_t i = 0; i < value.size(); i++) + { + if (value[i] == separator) + { + result.push_back(currentItem); + currentItem.clear(); + } + else + { + currentItem.push_back(value[i]); + } + } + + result.push_back(currentItem); + } + + +#if BOOST_HAS_REGEX == 1 + void Toolbox::DecodeDataUriScheme(std::string& mime, + std::string& content, + const std::string& source) + { + boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)", + boost::regex::icase /* case insensitive search */); + + boost::cmatch what; + if (regex_match(source.c_str(), what, pattern)) + { + mime = what[1]; + content = what[2]; + } + else + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } +#endif + + + void Toolbox::MakeDirectory(const std::string& path) + { + if (boost::filesystem::exists(path)) + { + if (!boost::filesystem::is_directory(path)) + { + throw OrthancException("Cannot create the directory over an existing file: " + path); + } + } + else + { + if (!boost::filesystem::create_directories(path)) + { + throw OrthancException("Unable to create the directory: " + path); + } + } + } + + + bool Toolbox::IsExistingFile(const std::string& path) + { + return boost::filesystem::exists(path); + } + + +#if ORTHANC_PUGIXML_ENABLED == 1 + class ChunkedBufferWriter : public pugi::xml_writer + { + private: + ChunkedBuffer buffer_; + + public: + virtual void write(const void *data, size_t size) + { + if (size > 0) + { + buffer_.AddChunk(reinterpret_cast<const char*>(data), size); + } + } + + void Flatten(std::string& s) + { + buffer_.Flatten(s); + } + }; + + + static void JsonToXmlInternal(pugi::xml_node& target, + const Json::Value& source, + const std::string& arrayElement) + { + // http://jsoncpp.sourceforge.net/value_8h_source.html#l00030 + + switch (source.type()) + { + case Json::nullValue: + { + target.append_child(pugi::node_pcdata).set_value("null"); + break; + } + + case Json::intValue: + { + std::string s = boost::lexical_cast<std::string>(source.asInt()); + target.append_child(pugi::node_pcdata).set_value(s.c_str()); + break; + } + + case Json::uintValue: + { + std::string s = boost::lexical_cast<std::string>(source.asUInt()); + target.append_child(pugi::node_pcdata).set_value(s.c_str()); + break; + } + + case Json::realValue: + { + std::string s = boost::lexical_cast<std::string>(source.asFloat()); + target.append_child(pugi::node_pcdata).set_value(s.c_str()); + break; + } + + case Json::stringValue: + { + target.append_child(pugi::node_pcdata).set_value(source.asString().c_str()); + break; + } + + case Json::booleanValue: + { + target.append_child(pugi::node_pcdata).set_value(source.asBool() ? "true" : "false"); + break; + } + + case Json::arrayValue: + { + for (Json::Value::ArrayIndex i = 0; i < source.size(); i++) + { + pugi::xml_node node = target.append_child(); + node.set_name(arrayElement.c_str()); + JsonToXmlInternal(node, source[i], arrayElement); + } + break; + } + + case Json::objectValue: + { + Json::Value::Members members = source.getMemberNames(); + + for (size_t i = 0; i < members.size(); i++) + { + pugi::xml_node node = target.append_child(); + node.set_name(members[i].c_str()); + JsonToXmlInternal(node, source[members[i]], arrayElement); + } + + break; + } + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void Toolbox::JsonToXml(std::string& target, + const Json::Value& source, + const std::string& rootElement, + const std::string& arrayElement) + { + pugi::xml_document doc; + + pugi::xml_node n = doc.append_child(rootElement.c_str()); + JsonToXmlInternal(n, source, arrayElement); + + pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); + decl.append_attribute("version").set_value("1.0"); + decl.append_attribute("encoding").set_value("utf-8"); + + ChunkedBufferWriter writer; + doc.save(writer, " ", pugi::format_default, pugi::encoding_utf8); + writer.Flatten(target); + } + +#endif + + + void Toolbox::ExecuteSystemCommand(const std::string& command, + const std::vector<std::string>& arguments) + { + // Convert the arguments as a C array + std::vector<char*> args(arguments.size() + 2); + + args.front() = const_cast<char*>(command.c_str()); + + for (size_t i = 0; i < arguments.size(); i++) + { + args[i + 1] = const_cast<char*>(arguments[i].c_str()); + } + + args.back() = NULL; + + int status; + +#if defined(_WIN32) + // http://msdn.microsoft.com/en-us/library/275khfab.aspx + status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); + +#else + int pid = fork(); + + if (pid == -1) + { + // Error in fork() +#if HAVE_GOOGLE_LOG == 1 + LOG(ERROR) << "Cannot fork a child process"; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + else if (pid == 0) + { + // Execute the system command in the child process + execvp(command.c_str(), &args[0]); + + // We should never get here + _exit(1); + } + else + { + // Wait for the system command to exit + waitpid(pid, &status, 0); + } +#endif + + if (status != 0) + { +#if HAVE_GOOGLE_LOG == 1 + LOG(ERROR) << "System command failed with status code " << status; +#endif + + throw OrthancException(ErrorCode_SystemCommand); + } + } + + + bool Toolbox::IsInteger(const std::string& str) + { + std::string s = StripSpaces(str); + + if (s.size() == 0) + { + return false; + } + + size_t pos = 0; + if (s[0] == '-') + { + if (s.size() == 1) + { + return false; + } + + pos = 1; + } + + while (pos < s.size()) + { + if (!isdigit(s[pos])) + { + return false; + } + + pos++; + } + + return true; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Toolbox.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,164 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "Enumerations.h" + +#include <stdint.h> +#include <vector> +#include <string> + +#if ORTHANC_PUGIXML_ENABLED == 1 +#include <json/json.h> +#endif + +namespace Orthanc +{ + typedef std::vector<std::string> UriComponents; + + class NullType + { + }; + + namespace Toolbox + { + void ServerBarrier(const bool& stopFlag); + + void ServerBarrier(); + + void ToUpperCase(std::string& s); // Inplace version + + void ToLowerCase(std::string& s); // Inplace version + + void ToUpperCase(std::string& result, + const std::string& source); + + void ToLowerCase(std::string& result, + const std::string& source); + + void ReadFile(std::string& content, + const std::string& path); + + void WriteFile(const std::string& content, + const std::string& path); + + void USleep(uint64_t microSeconds); + + void RemoveFile(const std::string& path); + + void SplitUriComponents(UriComponents& components, + const std::string& uri); + + void TruncateUri(UriComponents& target, + const UriComponents& source, + size_t fromLevel); + + bool IsChildUri(const UriComponents& baseUri, + const UriComponents& testedUri); + + std::string AutodetectMimeType(const std::string& path); + + std::string FlattenUri(const UriComponents& components, + size_t fromLevel = 0); + + uint64_t GetFileSize(const std::string& path); + + void ComputeMD5(std::string& result, + const std::string& data); + + void ComputeMD5(std::string& result, + const void* data, + size_t length); + + void ComputeSHA1(std::string& result, + const std::string& data); + + bool IsSHA1(const std::string& str); + + void DecodeBase64(std::string& result, + const std::string& data); + + void EncodeBase64(std::string& result, + const std::string& data); + + std::string GetPathToExecutable(); + + std::string GetDirectoryOfExecutable(); + + std::string ConvertToUtf8(const std::string& source, + const Encoding sourceEncoding); + + std::string ConvertToAscii(const std::string& source); + + std::string StripSpaces(const std::string& source); + +#if BOOST_HAS_DATE_TIME == 1 + std::string GetNowIsoString(); +#endif + + // In-place percent-decoding for URL + void UrlDecode(std::string& s); + + Endianness DetectEndianness(); + +#if BOOST_HAS_REGEX == 1 + std::string WildcardToRegularExpression(const std::string& s); +#endif + + void TokenizeString(std::vector<std::string>& result, + const std::string& source, + char separator); + +#if BOOST_HAS_REGEX == 1 + void DecodeDataUriScheme(std::string& mime, + std::string& content, + const std::string& source); +#endif + + void MakeDirectory(const std::string& path); + + bool IsExistingFile(const std::string& path); + +#if ORTHANC_PUGIXML_ENABLED == 1 + void JsonToXml(std::string& target, + const Json::Value& source, + const std::string& rootElement = "root", + const std::string& arrayElement = "item"); +#endif + + void ExecuteSystemCommand(const std::string& command, + const std::vector<std::string>& arguments); + + bool IsInteger(const std::string& str); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Uuid.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,162 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeaders.h" +#include "Uuid.h" + +// http://stackoverflow.com/a/1626302 + +extern "C" +{ +#ifdef WIN32 +#include <rpc.h> +#else +#include <uuid/uuid.h> +#endif +} + +#include <boost/filesystem.hpp> + +namespace Orthanc +{ + namespace Toolbox + { + std::string GenerateUuid() + { +#ifdef WIN32 + UUID uuid; + UuidCreate ( &uuid ); + + unsigned char * str; + UuidToStringA ( &uuid, &str ); + + std::string s( ( char* ) str ); + + RpcStringFreeA ( &str ); +#else + uuid_t uuid; + uuid_generate_random ( uuid ); + char s[37]; + uuid_unparse ( uuid, s ); +#endif + return s; + } + + + bool IsUuid(const std::string& str) + { + if (str.size() != 36) + { + return false; + } + + for (size_t i = 0; i < str.length(); i++) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + if (str[i] != '-') + return false; + } + else + { + if (!isalnum(str[i])) + return false; + } + } + + return true; + } + + + bool StartsWithUuid(const std::string& str) + { + if (str.size() < 36) + { + return false; + } + + if (str.size() == 36) + { + return IsUuid(str); + } + + assert(str.size() > 36); + if (!isspace(str[36])) + { + return false; + } + + return IsUuid(str.substr(0, 36)); + } + + + static std::string CreateTemporaryPath(const char* extension) + { +#if BOOST_HAS_FILESYSTEM_V3 == 1 + boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path(); +#elif defined(__linux__) + boost::filesystem::path tmpDir("/tmp"); +#else +#error Support your platform here +#endif + + // We use UUID to create unique path to temporary files + std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid(); + + if (extension != NULL) + { + filename.append(extension); + } + + tmpDir /= filename; + return tmpDir.string(); + } + + + TemporaryFile::TemporaryFile() : + path_(CreateTemporaryPath(NULL)) + { + } + + + TemporaryFile::TemporaryFile(const char* extension) : + path_(CreateTemporaryPath(extension)) + { + } + + + TemporaryFile::~TemporaryFile() + { + boost::filesystem::remove(path_); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Core/Uuid.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,86 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <string> + +/** + * GUID vs. UUID + * The simple answer is: no difference, they are the same thing. Treat + * them as a 16 byte (128 bits) value that is used as a unique + * value. In Microsoft-speak they are called GUIDs, but call them + * UUIDs when not using Microsoft-speak. + * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid + **/ + +#include "Toolbox.h" + +namespace Orthanc +{ + namespace Toolbox + { + std::string GenerateUuid(); + + bool IsUuid(const std::string& str); + + bool StartsWithUuid(const std::string& str); + + class TemporaryFile + { + private: + std::string path_; + + public: + TemporaryFile(); + + TemporaryFile(const char* extension); + + ~TemporaryFile(); + + const std::string& GetPath() const + { + return path_; + } + + void Write(const std::string& content) + { + Toolbox::WriteFile(content, path_); + } + + void Read(std::string& content) const + { + Toolbox::ReadFile(content, path_); + } + }; + } +}
--- a/Orthanc/Enumerations.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,628 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h" -#include "Enumerations.h" - -#include "OrthancException.h" -#include "Toolbox.h" - -namespace Orthanc -{ - const char* EnumerationToString(HttpMethod method) - { - switch (method) - { - case HttpMethod_Get: - return "GET"; - - case HttpMethod_Post: - return "POST"; - - case HttpMethod_Delete: - return "DELETE"; - - case HttpMethod_Put: - return "PUT"; - - default: - return "?"; - } - } - - - const char* EnumerationToString(HttpStatus status) - { - switch (status) - { - case HttpStatus_100_Continue: - return "Continue"; - - case HttpStatus_101_SwitchingProtocols: - return "Switching Protocols"; - - case HttpStatus_102_Processing: - return "Processing"; - - case HttpStatus_200_Ok: - return "OK"; - - case HttpStatus_201_Created: - return "Created"; - - case HttpStatus_202_Accepted: - return "Accepted"; - - case HttpStatus_203_NonAuthoritativeInformation: - return "Non-Authoritative Information"; - - case HttpStatus_204_NoContent: - return "No Content"; - - case HttpStatus_205_ResetContent: - return "Reset Content"; - - case HttpStatus_206_PartialContent: - return "Partial Content"; - - case HttpStatus_207_MultiStatus: - return "Multi-Status"; - - case HttpStatus_208_AlreadyReported: - return "Already Reported"; - - case HttpStatus_226_IMUsed: - return "IM Used"; - - case HttpStatus_300_MultipleChoices: - return "Multiple Choices"; - - case HttpStatus_301_MovedPermanently: - return "Moved Permanently"; - - case HttpStatus_302_Found: - return "Found"; - - case HttpStatus_303_SeeOther: - return "See Other"; - - case HttpStatus_304_NotModified: - return "Not Modified"; - - case HttpStatus_305_UseProxy: - return "Use Proxy"; - - case HttpStatus_307_TemporaryRedirect: - return "Temporary Redirect"; - - case HttpStatus_400_BadRequest: - return "Bad Request"; - - case HttpStatus_401_Unauthorized: - return "Unauthorized"; - - case HttpStatus_402_PaymentRequired: - return "Payment Required"; - - case HttpStatus_403_Forbidden: - return "Forbidden"; - - case HttpStatus_404_NotFound: - return "Not Found"; - - case HttpStatus_405_MethodNotAllowed: - return "Method Not Allowed"; - - case HttpStatus_406_NotAcceptable: - return "Not Acceptable"; - - case HttpStatus_407_ProxyAuthenticationRequired: - return "Proxy Authentication Required"; - - case HttpStatus_408_RequestTimeout: - return "Request Timeout"; - - case HttpStatus_409_Conflict: - return "Conflict"; - - case HttpStatus_410_Gone: - return "Gone"; - - case HttpStatus_411_LengthRequired: - return "Length Required"; - - case HttpStatus_412_PreconditionFailed: - return "Precondition Failed"; - - case HttpStatus_413_RequestEntityTooLarge: - return "Request Entity Too Large"; - - case HttpStatus_414_RequestUriTooLong: - return "Request-URI Too Long"; - - case HttpStatus_415_UnsupportedMediaType: - return "Unsupported Media Type"; - - case HttpStatus_416_RequestedRangeNotSatisfiable: - return "Requested Range Not Satisfiable"; - - case HttpStatus_417_ExpectationFailed: - return "Expectation Failed"; - - case HttpStatus_422_UnprocessableEntity: - return "Unprocessable Entity"; - - case HttpStatus_423_Locked: - return "Locked"; - - case HttpStatus_424_FailedDependency: - return "Failed Dependency"; - - case HttpStatus_426_UpgradeRequired: - return "Upgrade Required"; - - case HttpStatus_500_InternalServerError: - return "Internal Server Error"; - - case HttpStatus_501_NotImplemented: - return "Not Implemented"; - - case HttpStatus_502_BadGateway: - return "Bad Gateway"; - - case HttpStatus_503_ServiceUnavailable: - return "Service Unavailable"; - - case HttpStatus_504_GatewayTimeout: - return "Gateway Timeout"; - - case HttpStatus_505_HttpVersionNotSupported: - return "HTTP Version Not Supported"; - - case HttpStatus_506_VariantAlsoNegotiates: - return "Variant Also Negotiates"; - - case HttpStatus_507_InsufficientStorage: - return "Insufficient Storage"; - - case HttpStatus_509_BandwidthLimitExceeded: - return "Bandwidth Limit Exceeded"; - - case HttpStatus_510_NotExtended: - return "Not Extended"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ResourceType type) - { - switch (type) - { - case ResourceType_Patient: - return "Patient"; - - case ResourceType_Study: - return "Study"; - - case ResourceType_Series: - return "Series"; - - case ResourceType_Instance: - return "Instance"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ImageFormat format) - { - switch (format) - { - case ImageFormat_Png: - return "Png"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(Encoding encoding) - { - switch (encoding) - { - case Encoding_Ascii: - return "Ascii"; - - case Encoding_Utf8: - return "Utf8"; - - case Encoding_Latin1: - return "Latin1"; - - case Encoding_Latin2: - return "Latin2"; - - case Encoding_Latin3: - return "Latin3"; - - case Encoding_Latin4: - return "Latin4"; - - case Encoding_Latin5: - return "Latin5"; - - case Encoding_Cyrillic: - return "Cyrillic"; - - case Encoding_Windows1251: - return "Windows1251"; - - case Encoding_Arabic: - return "Arabic"; - - case Encoding_Greek: - return "Greek"; - - case Encoding_Hebrew: - return "Hebrew"; - - case Encoding_Thai: - return "Thai"; - - case Encoding_Japanese: - return "Japanese"; - - case Encoding_Chinese: - return "Chinese"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(PhotometricInterpretation photometric) - { - switch (photometric) - { - case PhotometricInterpretation_RGB: - return "RGB"; - - case PhotometricInterpretation_Monochrome1: - return "Monochrome1"; - - case PhotometricInterpretation_Monochrome2: - return "Monochrome2"; - - case PhotometricInterpretation_ARGB: - return "ARGB"; - - case PhotometricInterpretation_CMYK: - return "CMYK"; - - case PhotometricInterpretation_HSV: - return "HSV"; - - case PhotometricInterpretation_Palette: - return "Palette color"; - - case PhotometricInterpretation_YBRFull: - return "YBR full"; - - case PhotometricInterpretation_YBRFull422: - return "YBR full 422"; - - case PhotometricInterpretation_YBRPartial420: - return "YBR partial 420"; - - case PhotometricInterpretation_YBRPartial422: - return "YBR partial 422"; - - case PhotometricInterpretation_YBR_ICT: - return "YBR ICT"; - - case PhotometricInterpretation_YBR_RCT: - return "YBR RCT"; - - case PhotometricInterpretation_Unknown: - return "Unknown"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - Encoding StringToEncoding(const char* encoding) - { - std::string s(encoding); - Toolbox::ToUpperCase(s); - - if (s == "UTF8") - { - return Encoding_Utf8; - } - - if (s == "ASCII") - { - return Encoding_Ascii; - } - - if (s == "LATIN1") - { - return Encoding_Latin1; - } - - if (s == "LATIN2") - { - return Encoding_Latin2; - } - - if (s == "LATIN3") - { - return Encoding_Latin3; - } - - if (s == "LATIN4") - { - return Encoding_Latin4; - } - - if (s == "LATIN5") - { - return Encoding_Latin5; - } - - if (s == "CYRILLIC") - { - return Encoding_Cyrillic; - } - - if (s == "WINDOWS1251") - { - return Encoding_Windows1251; - } - - if (s == "ARABIC") - { - return Encoding_Arabic; - } - - if (s == "GREEK") - { - return Encoding_Greek; - } - - if (s == "HEBREW") - { - return Encoding_Hebrew; - } - - if (s == "THAI") - { - return Encoding_Thai; - } - - if (s == "JAPANESE") - { - return Encoding_Japanese; - } - - if (s == "CHINESE") - { - return Encoding_Chinese; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - ResourceType StringToResourceType(const char* type) - { - std::string s(type); - Toolbox::ToUpperCase(s); - - if (s == "PATIENT" || s == "PATIENTS") - { - return ResourceType_Patient; - } - else if (s == "STUDY" || s == "STUDIES") - { - return ResourceType_Study; - } - else if (s == "SERIES") - { - return ResourceType_Series; - } - else if (s == "INSTANCE" || s == "IMAGE" || - s == "INSTANCES" || s == "IMAGES") - { - return ResourceType_Instance; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - ImageFormat StringToImageFormat(const char* format) - { - std::string s(format); - Toolbox::ToUpperCase(s); - - if (s == "PNG") - { - return ImageFormat_Png; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - unsigned int GetBytesPerPixel(PixelFormat format) - { - switch (format) - { - case PixelFormat_Grayscale8: - return 1; - - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - return 2; - - case PixelFormat_RGB24: - return 3; - - case PixelFormat_RGBA32: - return 4; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool GetDicomEncoding(Encoding& encoding, - const char* specificCharacterSet) - { - std::string s = specificCharacterSet; - Toolbox::ToUpperCase(s); - - // http://www.dabsoft.ch/dicom/3/C.12.1.1.2/ - // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java - if (s == "ISO_IR 6" || - s == "ISO_IR 192" || - s == "ISO 2022 IR 6") - { - encoding = Encoding_Utf8; - } - else if (s == "ISO_IR 100" || - s == "ISO 2022 IR 100") - { - encoding = Encoding_Latin1; - } - else if (s == "ISO_IR 101" || - s == "ISO 2022 IR 101") - { - encoding = Encoding_Latin2; - } - else if (s == "ISO_IR 109" || - s == "ISO 2022 IR 109") - { - encoding = Encoding_Latin3; - } - else if (s == "ISO_IR 110" || - s == "ISO 2022 IR 110") - { - encoding = Encoding_Latin4; - } - else if (s == "ISO_IR 148" || - s == "ISO 2022 IR 148") - { - encoding = Encoding_Latin5; - } - else if (s == "ISO_IR 144" || - s == "ISO 2022 IR 144") - { - encoding = Encoding_Cyrillic; - } - else if (s == "ISO_IR 127" || - s == "ISO 2022 IR 127") - { - encoding = Encoding_Arabic; - } - else if (s == "ISO_IR 126" || - s == "ISO 2022 IR 126") - { - encoding = Encoding_Greek; - } - else if (s == "ISO_IR 138" || - s == "ISO 2022 IR 138") - { - encoding = Encoding_Hebrew; - } - else if (s == "ISO_IR 166" || s == "ISO 2022 IR 166") - { - encoding = Encoding_Thai; - } - else if (s == "ISO_IR 13" || s == "ISO 2022 IR 13") - { - encoding = Encoding_Japanese; - } - else if (s == "GB18030") - { - encoding = Encoding_Chinese; - } - /* - else if (s == "ISO 2022 IR 149") - { - TODO - } - else if (s == "ISO 2022 IR 159") - { - TODO - } - else if (s == "ISO 2022 IR 87") - { - TODO - } - */ - else - { - return false; - } - - // The encoding was properly detected - return true; - } - - - const char* GetMimeType(FileContentType type) - { - switch (type) - { - case FileContentType_Dicom: - return "application/dicom"; - - case FileContentType_DicomAsJson: - return "application/json"; - - default: - return "application/octet-stream"; - } - } -}
--- a/Orthanc/Enumerations.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,345 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -namespace Orthanc -{ - enum Endianness - { - Endianness_Unknown, - Endianness_Big, - Endianness_Little - }; - - enum ErrorCode - { - // Generic error codes - ErrorCode_Success, - ErrorCode_Custom, - ErrorCode_InternalError, - ErrorCode_NotImplemented, - ErrorCode_ParameterOutOfRange, - ErrorCode_NotEnoughMemory, - ErrorCode_BadParameterType, - ErrorCode_BadSequenceOfCalls, - ErrorCode_InexistentItem, - ErrorCode_BadRequest, - ErrorCode_NetworkProtocol, - ErrorCode_SystemCommand, - ErrorCode_Database, - - // Specific error codes - ErrorCode_UriSyntax, - ErrorCode_InexistentFile, - ErrorCode_CannotWriteFile, - ErrorCode_BadFileFormat, - ErrorCode_Timeout, - ErrorCode_UnknownResource, - ErrorCode_IncompatibleDatabaseVersion, - ErrorCode_FullStorage, - ErrorCode_CorruptedFile, - ErrorCode_InexistentTag, - ErrorCode_ReadOnly, - ErrorCode_IncompatibleImageFormat, - ErrorCode_IncompatibleImageSize, - ErrorCode_SharedLibrary, - ErrorCode_Plugin - }; - - - /** - * {summary}{The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image.} - **/ - enum PixelFormat - { - /** - * {summary}{Color image in RGB24 format.} - * {description}{This format describes a color image. The pixels are stored in 3 - * consecutive bytes. The memory layout is RGB.} - **/ - PixelFormat_RGB24 = 1, - - /** - * {summary}{Color image in RGBA32 format.} - * {description}{This format describes a color image. The pixels are stored in 4 - * consecutive bytes. The memory layout is RGBA.} - **/ - PixelFormat_RGBA32 = 2, - - /** - * {summary}{Graylevel 8bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in one byte.} - **/ - PixelFormat_Grayscale8 = 3, - - /** - * {summary}{Graylevel, unsigned 16bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in two bytes.} - **/ - PixelFormat_Grayscale16 = 4, - - /** - * {summary}{Graylevel, signed 16bpp image.} - * {description}{The image is graylevel. Each pixel is signed and stored in two bytes.} - **/ - PixelFormat_SignedGrayscale16 = 5 - }; - - - /** - * {summary}{The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image.} - **/ - enum ImageExtractionMode - { - /** - * {summary}{Rescaled to 8bpp.} - * {description}{The minimum value of the image is set to 0, and its maximum value is set to 255.} - **/ - ImageExtractionMode_Preview = 1, - - /** - * {summary}{Truncation to the [0, 255] range.} - **/ - ImageExtractionMode_UInt8 = 2, - - /** - * {summary}{Truncation to the [0, 65535] range.} - **/ - ImageExtractionMode_UInt16 = 3, - - /** - * {summary}{Truncation to the [-32768, 32767] range.} - **/ - ImageExtractionMode_Int16 = 4 - }; - - - /** - * Most common, non-joke and non-experimental HTTP status codes - * http://en.wikipedia.org/wiki/List_of_HTTP_status_codes - **/ - enum HttpStatus - { - HttpStatus_None = -1, - - // 1xx Informational - HttpStatus_100_Continue = 100, - HttpStatus_101_SwitchingProtocols = 101, - HttpStatus_102_Processing = 102, - - // 2xx Success - HttpStatus_200_Ok = 200, - HttpStatus_201_Created = 201, - HttpStatus_202_Accepted = 202, - HttpStatus_203_NonAuthoritativeInformation = 203, - HttpStatus_204_NoContent = 204, - HttpStatus_205_ResetContent = 205, - HttpStatus_206_PartialContent = 206, - HttpStatus_207_MultiStatus = 207, - HttpStatus_208_AlreadyReported = 208, - HttpStatus_226_IMUsed = 226, - - // 3xx Redirection - HttpStatus_300_MultipleChoices = 300, - HttpStatus_301_MovedPermanently = 301, - HttpStatus_302_Found = 302, - HttpStatus_303_SeeOther = 303, - HttpStatus_304_NotModified = 304, - HttpStatus_305_UseProxy = 305, - HttpStatus_307_TemporaryRedirect = 307, - - // 4xx Client Error - HttpStatus_400_BadRequest = 400, - HttpStatus_401_Unauthorized = 401, - HttpStatus_402_PaymentRequired = 402, - HttpStatus_403_Forbidden = 403, - HttpStatus_404_NotFound = 404, - HttpStatus_405_MethodNotAllowed = 405, - HttpStatus_406_NotAcceptable = 406, - HttpStatus_407_ProxyAuthenticationRequired = 407, - HttpStatus_408_RequestTimeout = 408, - HttpStatus_409_Conflict = 409, - HttpStatus_410_Gone = 410, - HttpStatus_411_LengthRequired = 411, - HttpStatus_412_PreconditionFailed = 412, - HttpStatus_413_RequestEntityTooLarge = 413, - HttpStatus_414_RequestUriTooLong = 414, - HttpStatus_415_UnsupportedMediaType = 415, - HttpStatus_416_RequestedRangeNotSatisfiable = 416, - HttpStatus_417_ExpectationFailed = 417, - HttpStatus_422_UnprocessableEntity = 422, - HttpStatus_423_Locked = 423, - HttpStatus_424_FailedDependency = 424, - HttpStatus_426_UpgradeRequired = 426, - - // 5xx Server Error - HttpStatus_500_InternalServerError = 500, - HttpStatus_501_NotImplemented = 501, - HttpStatus_502_BadGateway = 502, - HttpStatus_503_ServiceUnavailable = 503, - HttpStatus_504_GatewayTimeout = 504, - HttpStatus_505_HttpVersionNotSupported = 505, - HttpStatus_506_VariantAlsoNegotiates = 506, - HttpStatus_507_InsufficientStorage = 507, - HttpStatus_509_BandwidthLimitExceeded = 509, - HttpStatus_510_NotExtended = 510 - }; - - - enum HttpMethod - { - HttpMethod_Get = 0, - HttpMethod_Post = 1, - HttpMethod_Delete = 2, - HttpMethod_Put = 3 - }; - - - enum ImageFormat - { - ImageFormat_Png = 1 - }; - - - // http://www.dabsoft.ch/dicom/3/C.12.1.1.2/ - enum Encoding - { - Encoding_Ascii, - Encoding_Utf8, - Encoding_Latin1, - Encoding_Latin2, - Encoding_Latin3, - Encoding_Latin4, - Encoding_Latin5, // Turkish - Encoding_Cyrillic, - Encoding_Windows1251, // Windows-1251 (commonly used for Cyrillic) - Encoding_Arabic, - Encoding_Greek, - Encoding_Hebrew, - Encoding_Thai, // TIS 620-2533 - Encoding_Japanese, // JIS X 0201 (Shift JIS): Katakana - Encoding_Chinese // GB18030 - Chinese simplified - //Encoding_JapaneseKanji, // Multibyte - JIS X 0208: Kanji - //Encoding_JapaneseSupplementaryKanji, // Multibyte - JIS X 0212: Supplementary Kanji set - //Encoding_Korean, // Multibyte - KS X 1001: Hangul and Hanja - }; - - - // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.2/ - enum PhotometricInterpretation - { - PhotometricInterpretation_ARGB, // Retired - PhotometricInterpretation_CMYK, // Retired - PhotometricInterpretation_HSV, // Retired - PhotometricInterpretation_Monochrome1, - PhotometricInterpretation_Monochrome2, - PhotometricInterpretation_Palette, - PhotometricInterpretation_RGB, - PhotometricInterpretation_YBRFull, - PhotometricInterpretation_YBRFull422, - PhotometricInterpretation_YBRPartial420, - PhotometricInterpretation_YBRPartial422, - PhotometricInterpretation_YBR_ICT, - PhotometricInterpretation_YBR_RCT, - PhotometricInterpretation_Unknown - }; - - enum DicomModule - { - DicomModule_Patient, - DicomModule_Study, - DicomModule_Series, - DicomModule_Instance, - DicomModule_Image - }; - - - /** - * WARNING: Do not change the explicit values in the enumerations - * below this point. This would result in incompatible databases - * between versions of Orthanc! - **/ - - enum CompressionType - { - CompressionType_None = 1, - CompressionType_Zlib = 2 - }; - - enum FileContentType - { - // If you add a value below, insert it in "PluginStorageArea" in - // the file "Plugins/Engine/OrthancPlugins.cpp" - FileContentType_Unknown = 0, - FileContentType_Dicom = 1, - FileContentType_DicomAsJson = 2, - - // Make sure that the value "65535" can be stored into this enumeration - FileContentType_StartUser = 1024, - FileContentType_EndUser = 65535 - }; - - enum ResourceType - { - ResourceType_Patient = 1, - ResourceType_Study = 2, - ResourceType_Series = 3, - ResourceType_Instance = 4 - }; - - - const char* EnumerationToString(HttpMethod method); - - const char* EnumerationToString(HttpStatus status); - - const char* EnumerationToString(ResourceType type); - - const char* EnumerationToString(ImageFormat format); - - const char* EnumerationToString(Encoding encoding); - - const char* EnumerationToString(PhotometricInterpretation photometric); - - Encoding StringToEncoding(const char* encoding); - - ResourceType StringToResourceType(const char* type); - - ImageFormat StringToImageFormat(const char* format); - - unsigned int GetBytesPerPixel(PixelFormat format); - - bool GetDicomEncoding(Encoding& encoding, - const char* specificCharacterSet); - - const char* GetMimeType(FileContentType type); -}
--- a/Orthanc/FileStorage/FilesystemStorage.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "FilesystemStorage.h" - -// http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system -// http://stackoverflow.com/questions/446358/storing-a-large-number-of-images - -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "../Uuid.h" - -#include <boost/filesystem/fstream.hpp> - -#if HAVE_GOOGLE_LOG == 1 -#include <glog/logging.h> -#endif - -static std::string ToString(const boost::filesystem::path& p) -{ -#if BOOST_HAS_FILESYSTEM_V3 == 1 - return p.filename().string(); -#else - return p.filename(); -#endif -} - - -namespace Orthanc -{ - boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const - { - namespace fs = boost::filesystem; - - if (!Toolbox::IsUuid(uuid)) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - fs::path path = root_; - - path /= std::string(&uuid[0], &uuid[2]); - path /= std::string(&uuid[2], &uuid[4]); - path /= uuid; - -#if BOOST_HAS_FILESYSTEM_V3 == 1 - path.make_preferred(); -#endif - - return path; - } - - FilesystemStorage::FilesystemStorage(std::string root) - { - //root_ = boost::filesystem::absolute(root).string(); - root_ = root; - - Toolbox::MakeDirectory(root); - } - - void FilesystemStorage::Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType /*type*/) - { - boost::filesystem::path path; - - path = GetPath(uuid); - - if (boost::filesystem::exists(path)) - { - // Extremely unlikely case: This Uuid has already been created - // in the past. - throw OrthancException(ErrorCode_InternalError); - } - - if (boost::filesystem::exists(path.parent_path())) - { - if (!boost::filesystem::is_directory(path.parent_path())) - { - throw OrthancException("The subdirectory to be created is already occupied by a regular file"); - } - } - else - { - if (!boost::filesystem::create_directories(path.parent_path())) - { - throw OrthancException("Unable to create a subdirectory in the file storage"); - } - } - - boost::filesystem::ofstream f; - f.open(path, std::ofstream::out | std::ios::binary); - if (!f.good()) - { - throw OrthancException("Unable to create a new file in the file storage"); - } - - if (size != 0) - { - f.write(static_cast<const char*>(content), size); - if (!f.good()) - { - f.close(); - throw OrthancException("Unable to write to the new file in the file storage"); - } - } - - f.close(); - } - - - void FilesystemStorage::Read(std::string& content, - const std::string& uuid, - FileContentType /*type*/) - { - content.clear(); - Toolbox::ReadFile(content, GetPath(uuid).string()); - } - - - uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const - { - boost::filesystem::path path = GetPath(uuid); - return boost::filesystem::file_size(path); - } - - - - void FilesystemStorage::ListAllFiles(std::set<std::string>& result) const - { - namespace fs = boost::filesystem; - - result.clear(); - - if (fs::exists(root_) && fs::is_directory(root_)) - { - for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) - { - if (fs::is_regular_file(current->status())) - { - try - { - fs::path d = current->path(); - std::string uuid = ToString(d); - if (Toolbox::IsUuid(uuid)) - { - fs::path p0 = d.parent_path().parent_path().parent_path(); - std::string p1 = ToString(d.parent_path().parent_path()); - std::string p2 = ToString(d.parent_path()); - if (p1.length() == 2 && - p2.length() == 2 && - p1 == uuid.substr(0, 2) && - p2 == uuid.substr(2, 2) && - p0 == root_) - { - result.insert(uuid); - } - } - } - catch (fs::filesystem_error) - { - } - } - } - } - } - - - void FilesystemStorage::Clear() - { - namespace fs = boost::filesystem; - typedef std::set<std::string> List; - - List result; - ListAllFiles(result); - - for (List::const_iterator it = result.begin(); it != result.end(); ++it) - { - Remove(*it, FileContentType_Unknown /*ignored in this class*/); - } - } - - - void FilesystemStorage::Remove(const std::string& uuid, - FileContentType /*type*/) - { -#if HAVE_GOOGLE_LOG == 1 - LOG(INFO) << "Deleting file " << uuid; -#endif - - namespace fs = boost::filesystem; - - fs::path p = GetPath(uuid); - - try - { - fs::remove(p); - } - catch (...) - { - // Ignore the error - } - - // Remove the two parent directories, ignoring the error code if - // these directories are not empty - - try - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - boost::system::error_code err; - fs::remove(p.parent_path(), err); - fs::remove(p.parent_path().parent_path(), err); -#else - fs::remove(p.parent_path()); - fs::remove(p.parent_path().parent_path()); -#endif - } - catch (...) - { - // Ignore the error - } - } - - - uintmax_t FilesystemStorage::GetCapacity() const - { - return boost::filesystem::space(root_).capacity; - } - - uintmax_t FilesystemStorage::GetAvailableSpace() const - { - return boost::filesystem::space(root_).available; - } -}
--- a/Orthanc/FileStorage/FilesystemStorage.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "IStorageArea.h" - -#include <stdint.h> -#include <boost/filesystem.hpp> -#include <set> - -namespace Orthanc -{ - class FilesystemStorage : public IStorageArea - { - // TODO REMOVE THIS - friend class FilesystemHttpSender; - friend class FileStorageAccessor; - - private: - boost::filesystem::path root_; - - boost::filesystem::path GetPath(const std::string& uuid) const; - - public: - FilesystemStorage(std::string root); - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type); - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type); - - virtual void Remove(const std::string& uuid, - FileContentType type); - - void ListAllFiles(std::set<std::string>& result) const; - - uintmax_t GetSize(const std::string& uuid) const; - - void Clear(); - - uintmax_t GetCapacity() const; - - uintmax_t GetAvailableSpace() const; - }; -}
--- a/Orthanc/FileStorage/IStorageArea.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include <string> -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - class IStorageArea : public boost::noncopyable - { - public: - virtual ~IStorageArea() - { - } - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type) = 0; - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type) = 0; - - virtual void Remove(const std::string& uuid, - FileContentType type) = 0; - }; -}
--- a/Orthanc/IDynamicObject.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - /** - * This class should be the ancestor to any class whose type is - * determined at the runtime, and that can be dynamically allocated. - * Being a child of IDynamicObject only implies the existence of a - * virtual destructor. - **/ - class IDynamicObject : public boost::noncopyable - { - public: - virtual ~IDynamicObject() - { - } - }; -}
--- a/Orthanc/ImageFormats/ImageAccessor.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageAccessor.h" - -#include "../OrthancException.h" -#include "../ChunkedBuffer.h" - -#include <stdint.h> -#include <cassert> -#include <boost/lexical_cast.hpp> - -#if HAVE_GOOGLE_LOG == 1 -#include <glog/logging.h> -#endif - - -namespace Orthanc -{ - template <typename PixelType> - static void ToMatlabStringInternal(ChunkedBuffer& target, - const ImageAccessor& source) - { - target.AddChunk("double([ "); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y)); - - std::string s; - if (y > 0) - { - s = "; "; - } - - s.reserve(source.GetWidth() * 8); - - for (unsigned int x = 0; x < source.GetWidth(); x++, p++) - { - s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " "; - } - - target.AddChunk(s); - } - - target.AddChunk("])"); - } - - - static void RGB24ToMatlabString(ChunkedBuffer& target, - const ImageAccessor& source) - { - assert(source.GetFormat() == PixelFormat_RGB24); - - target.AddChunk("double(permute(reshape([ "); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y)); - - std::string s; - s.reserve(source.GetWidth() * 3 * 8); - - for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++) - { - s += boost::lexical_cast<std::string>(static_cast<int>(*p)) + " "; - } - - target.AddChunk(s); - } - - target.AddChunk("], [ 3 " + boost::lexical_cast<std::string>(source.GetHeight()) + - " " + boost::lexical_cast<std::string>(source.GetWidth()) + " ]), [ 3 2 1 ]))"); - } - - - void* ImageAccessor::GetBuffer() const - { - if (readOnly_) - { -#if HAVE_GOOGLE_LOG == 1 - LOG(ERROR) << "Trying to write on a read-only image"; -#endif - - throw OrthancException(ErrorCode_ReadOnly); - } - - return buffer_; - } - - - const void* ImageAccessor::GetConstRow(unsigned int y) const - { - if (buffer_ != NULL) - { - return reinterpret_cast<const uint8_t*>(buffer_) + y * pitch_; - } - else - { - return NULL; - } - } - - - void* ImageAccessor::GetRow(unsigned int y) const - { - if (readOnly_) - { -#if HAVE_GOOGLE_LOG == 1 - LOG(ERROR) << "Trying to write on a read-only image"; -#endif - - throw OrthancException(ErrorCode_ReadOnly); - } - - if (buffer_ != NULL) - { - return reinterpret_cast<uint8_t*>(buffer_) + y * pitch_; - } - else - { - return NULL; - } - } - - - void ImageAccessor::AssignEmpty(PixelFormat format) - { - readOnly_ = false; - format_ = format; - width_ = 0; - height_ = 0; - pitch_ = 0; - buffer_ = NULL; - } - - - void ImageAccessor::AssignReadOnly(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - const void *buffer) - { - readOnly_ = true; - format_ = format; - width_ = width; - height_ = height; - pitch_ = pitch; - buffer_ = const_cast<void*>(buffer); - - assert(GetBytesPerPixel() * width_ <= pitch_); - } - - - void ImageAccessor::AssignWritable(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - void *buffer) - { - readOnly_ = false; - format_ = format; - width_ = width; - height_ = height; - pitch_ = pitch; - buffer_ = buffer; - - assert(GetBytesPerPixel() * width_ <= pitch_); - } - - - void ImageAccessor::ToMatlabString(std::string& target) const - { - ChunkedBuffer buffer; - - switch (GetFormat()) - { - case PixelFormat_Grayscale8: - ToMatlabStringInternal<uint8_t>(buffer, *this); - break; - - case PixelFormat_Grayscale16: - ToMatlabStringInternal<uint16_t>(buffer, *this); - break; - - case PixelFormat_SignedGrayscale16: - ToMatlabStringInternal<int16_t>(buffer, *this); - break; - - case PixelFormat_RGB24: - RGB24ToMatlabString(buffer, *this); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - buffer.Flatten(target); - } - -}
--- a/Orthanc/ImageFormats/ImageAccessor.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include <string> - -namespace Orthanc -{ - class ImageAccessor - { - private: - bool readOnly_; - PixelFormat format_; - unsigned int width_; - unsigned int height_; - unsigned int pitch_; - void *buffer_; - - public: - ImageAccessor() - { - AssignEmpty(PixelFormat_Grayscale8); - } - - bool IsReadOnly() const - { - return readOnly_; - } - - PixelFormat GetFormat() const - { - return format_; - } - - unsigned int GetBytesPerPixel() const - { - return ::Orthanc::GetBytesPerPixel(format_); - } - - unsigned int GetWidth() const - { - return width_; - } - - unsigned int GetHeight() const - { - return height_; - } - - unsigned int GetPitch() const - { - return pitch_; - } - - unsigned int GetSize() const - { - return GetHeight() * GetPitch(); - } - - const void* GetConstBuffer() const - { - return buffer_; - } - - void* GetBuffer() const; - - const void* GetConstRow(unsigned int y) const; - - void* GetRow(unsigned int y) const; - - void AssignEmpty(PixelFormat format); - - void AssignReadOnly(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - const void *buffer); - - void AssignWritable(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - void *buffer); - - void ToMatlabString(std::string& target) const; - }; -}
--- a/Orthanc/ImageFormats/ImageBuffer.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageBuffer.h" - -#include "../OrthancException.h" - -#include <stdio.h> -#include <stdlib.h> - -namespace Orthanc -{ - void ImageBuffer::Allocate() - { - if (changed_) - { - Deallocate(); - - /* - if (forceMinimalPitch_) - { - TODO: Align pitch and memory buffer to optimal size for SIMD. - } - */ - - pitch_ = GetBytesPerPixel() * width_; - size_t size = pitch_ * height_; - - if (size == 0) - { - buffer_ = NULL; - } - else - { - buffer_ = malloc(size); - if (buffer_ == NULL) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - - changed_ = false; - } - } - - - void ImageBuffer::Deallocate() - { - if (buffer_ != NULL) - { - free(buffer_); - buffer_ = NULL; - changed_ = true; - } - } - - - ImageBuffer::ImageBuffer(unsigned int width, - unsigned int height, - PixelFormat format) - { - Initialize(); - SetWidth(width); - SetHeight(height); - SetFormat(format); - } - - - void ImageBuffer::Initialize() - { - changed_ = false; - forceMinimalPitch_ = true; - format_ = PixelFormat_Grayscale8; - width_ = 0; - height_ = 0; - pitch_ = 0; - buffer_ = NULL; - } - - - void ImageBuffer::SetFormat(PixelFormat format) - { - if (format != format_) - { - changed_ = true; - format_ = format; - } - } - - - void ImageBuffer::SetWidth(unsigned int width) - { - if (width != width_) - { - changed_ = true; - width_ = width; - } - } - - - void ImageBuffer::SetHeight(unsigned int height) - { - if (height != height_) - { - changed_ = true; - height_ = height; - } - } - - - ImageAccessor ImageBuffer::GetAccessor() - { - Allocate(); - - ImageAccessor accessor; - accessor.AssignWritable(format_, width_, height_, pitch_, buffer_); - return accessor; - } - - - ImageAccessor ImageBuffer::GetConstAccessor() - { - Allocate(); - - ImageAccessor accessor; - accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_); - return accessor; - } - - - void ImageBuffer::SetMinimalPitchForced(bool force) - { - if (force != forceMinimalPitch_) - { - changed_ = true; - forceMinimalPitch_ = force; - } - } - - - void ImageBuffer::AcquireOwnership(ImageBuffer& other) - { - // Remove the content of the current image - Deallocate(); - - // Force the allocation of the other image (if not already - // allocated) - other.Allocate(); - - // Transfer the content of the other image - changed_ = false; - forceMinimalPitch_ = other.forceMinimalPitch_; - format_ = other.format_; - width_ = other.width_; - height_ = other.height_; - pitch_ = other.pitch_; - buffer_ = other.buffer_; - - // Force the reinitialization of the other image - other.Initialize(); - } -}
--- a/Orthanc/ImageFormats/ImageBuffer.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#include <vector> -#include <stdint.h> -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - class ImageBuffer : public boost::noncopyable - { - private: - bool changed_; - - bool forceMinimalPitch_; // Currently unused - PixelFormat format_; - unsigned int width_; - unsigned int height_; - unsigned int pitch_; - void *buffer_; - - void Initialize(); - - void Allocate(); - - void Deallocate(); - - public: - ImageBuffer(unsigned int width, - unsigned int height, - PixelFormat format); - - ImageBuffer() - { - Initialize(); - } - - ~ImageBuffer() - { - Deallocate(); - } - - PixelFormat GetFormat() const - { - return format_; - } - - void SetFormat(PixelFormat format); - - unsigned int GetWidth() const - { - return width_; - } - - void SetWidth(unsigned int width); - - unsigned int GetHeight() const - { - return height_; - } - - void SetHeight(unsigned int height); - - unsigned int GetBytesPerPixel() const - { - return ::Orthanc::GetBytesPerPixel(format_); - } - - ImageAccessor GetAccessor(); - - ImageAccessor GetConstAccessor(); - - bool IsMinimalPitchForced() const - { - return forceMinimalPitch_; - } - - void SetMinimalPitchForced(bool force); - - void AcquireOwnership(ImageBuffer& other); - }; -}
--- a/Orthanc/ImageFormats/ImageProcessing.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,532 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageProcessing.h" - -#include "../OrthancException.h" - -#include <boost/math/special_functions/round.hpp> - -#include <cassert> -#include <string.h> -#include <limits> -#include <stdint.h> - -namespace Orthanc -{ - template <typename TargetType, typename SourceType> - static void ConvertInternal(ImageAccessor& target, - const ImageAccessor& source) - { - const TargetType minValue = std::numeric_limits<TargetType>::min(); - const TargetType maxValue = std::numeric_limits<TargetType>::max(); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y)); - const SourceType* s = reinterpret_cast<const SourceType*>(source.GetConstRow(y)); - - for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s++) - { - if (static_cast<int32_t>(*s) < static_cast<int32_t>(minValue)) - { - *t = minValue; - } - else if (static_cast<int32_t>(*s) > static_cast<int32_t>(maxValue)) - { - *t = maxValue; - } - else - { - *t = static_cast<TargetType>(*s); - } - } - } - } - - - template <typename TargetType> - static void ConvertColorToGrayscale(ImageAccessor& target, - const ImageAccessor& source) - { - assert(source.GetFormat() == PixelFormat_RGB24); - - const TargetType minValue = std::numeric_limits<TargetType>::min(); - const TargetType maxValue = std::numeric_limits<TargetType>::max(); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - TargetType* t = reinterpret_cast<TargetType*>(target.GetRow(y)); - const uint8_t* s = reinterpret_cast<const uint8_t*>(source.GetConstRow(y)); - - for (unsigned int x = 0; x < source.GetWidth(); x++, t++, s += 3) - { - // Y = 0.2126 R + 0.7152 G + 0.0722 B - int32_t v = (2126 * static_cast<int32_t>(s[0]) + - 7152 * static_cast<int32_t>(s[1]) + - 0722 * static_cast<int32_t>(s[2])) / 1000; - - if (static_cast<int32_t>(v) < static_cast<int32_t>(minValue)) - { - *t = minValue; - } - else if (static_cast<int32_t>(v) > static_cast<int32_t>(maxValue)) - { - *t = maxValue; - } - else - { - *t = static_cast<TargetType>(v); - } - } - } - } - - - template <typename PixelType> - static void SetInternal(ImageAccessor& image, - int64_t constant) - { - for (unsigned int y = 0; y < image.GetHeight(); y++) - { - PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); - - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - *p = static_cast<PixelType>(constant); - } - } - } - - - template <typename PixelType> - static void GetMinMaxValueInternal(PixelType& minValue, - PixelType& maxValue, - const ImageAccessor& source) - { - // Deal with the special case of empty image - if (source.GetWidth() == 0 || - source.GetHeight() == 0) - { - minValue = 0; - maxValue = 0; - return; - } - - minValue = std::numeric_limits<PixelType>::max(); - maxValue = std::numeric_limits<PixelType>::min(); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - const PixelType* p = reinterpret_cast<const PixelType*>(source.GetConstRow(y)); - - for (unsigned int x = 0; x < source.GetWidth(); x++, p++) - { - if (*p < minValue) - { - minValue = *p; - } - - if (*p > maxValue) - { - maxValue = *p; - } - } - } - } - - - - template <typename PixelType> - static void AddConstantInternal(ImageAccessor& image, - int64_t constant) - { - if (constant == 0) - { - return; - } - - const int64_t minValue = std::numeric_limits<PixelType>::min(); - const int64_t maxValue = std::numeric_limits<PixelType>::max(); - - for (unsigned int y = 0; y < image.GetHeight(); y++) - { - PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); - - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - int64_t v = static_cast<int64_t>(*p) + constant; - - if (v > maxValue) - { - *p = std::numeric_limits<PixelType>::max(); - } - else if (v < minValue) - { - *p = std::numeric_limits<PixelType>::min(); - } - else - { - *p = static_cast<PixelType>(v); - } - } - } - } - - - - template <typename PixelType> - void MultiplyConstantInternal(ImageAccessor& image, - float factor) - { - if (std::abs(factor - 1.0f) <= std::numeric_limits<float>::epsilon()) - { - return; - } - - const int64_t minValue = std::numeric_limits<PixelType>::min(); - const int64_t maxValue = std::numeric_limits<PixelType>::max(); - - for (unsigned int y = 0; y < image.GetHeight(); y++) - { - PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); - - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - int64_t v = boost::math::llround(static_cast<float>(*p) * factor); - - if (v > maxValue) - { - *p = std::numeric_limits<PixelType>::max(); - } - else if (v < minValue) - { - *p = std::numeric_limits<PixelType>::min(); - } - else - { - *p = static_cast<PixelType>(v); - } - } - } - } - - - template <typename PixelType> - void ShiftScaleInternal(ImageAccessor& image, - float offset, - float scaling) - { - const float minValue = static_cast<float>(std::numeric_limits<PixelType>::min()); - const float maxValue = static_cast<float>(std::numeric_limits<PixelType>::max()); - - for (unsigned int y = 0; y < image.GetHeight(); y++) - { - PixelType* p = reinterpret_cast<PixelType*>(image.GetRow(y)); - - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - float v = (static_cast<float>(*p) + offset) * scaling; - - if (v > maxValue) - { - *p = std::numeric_limits<PixelType>::max(); - } - else if (v < minValue) - { - *p = std::numeric_limits<PixelType>::min(); - } - else - { - *p = static_cast<PixelType>(boost::math::iround(v)); - } - } - } - } - - - void ImageProcessing::Copy(ImageAccessor& target, - const ImageAccessor& source) - { - if (target.GetWidth() != source.GetWidth() || - target.GetHeight() != source.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - if (target.GetFormat() != source.GetFormat()) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat); - } - - unsigned int lineSize = GetBytesPerPixel(source.GetFormat()) * source.GetWidth(); - - assert(source.GetPitch() >= lineSize && target.GetPitch() >= lineSize); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - memcpy(target.GetRow(y), source.GetConstRow(y), lineSize); - } - } - - - void ImageProcessing::Convert(ImageAccessor& target, - const ImageAccessor& source) - { - if (target.GetWidth() != source.GetWidth() || - target.GetHeight() != source.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - if (source.GetFormat() == target.GetFormat()) - { - Copy(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_Grayscale8) - { - ConvertInternal<uint16_t, uint8_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_Grayscale8) - { - ConvertInternal<int16_t, uint8_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_Grayscale16) - { - ConvertInternal<uint8_t, uint16_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_Grayscale16) - { - ConvertInternal<int16_t, uint16_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - ConvertInternal<uint8_t, int16_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - ConvertInternal<uint16_t, int16_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale<uint8_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale<uint16_t>(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale<int16_t>(target, source); - return; - } - - throw OrthancException(ErrorCode_NotImplemented); - } - - - - void ImageProcessing::Set(ImageAccessor& image, - int64_t value) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - SetInternal<uint8_t>(image, value); - return; - - case PixelFormat_Grayscale16: - SetInternal<uint16_t>(image, value); - return; - - case PixelFormat_SignedGrayscale16: - SetInternal<int16_t>(image, value); - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::ShiftRight(ImageAccessor& image, - unsigned int shift) - { - if (image.GetWidth() == 0 || - image.GetHeight() == 0 || - shift == 0) - { - // Nothing to do - return; - } - - throw OrthancException(ErrorCode_NotImplemented); - } - - - void ImageProcessing::GetMinMaxValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - { - uint8_t a, b; - GetMinMaxValueInternal<uint8_t>(a, b, image); - minValue = a; - maxValue = b; - break; - } - - case PixelFormat_Grayscale16: - { - uint16_t a, b; - GetMinMaxValueInternal<uint16_t>(a, b, image); - minValue = a; - maxValue = b; - break; - } - - case PixelFormat_SignedGrayscale16: - { - int16_t a, b; - GetMinMaxValueInternal<int16_t>(a, b, image); - minValue = a; - maxValue = b; - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - - void ImageProcessing::AddConstant(ImageAccessor& image, - int64_t value) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - AddConstantInternal<uint8_t>(image, value); - return; - - case PixelFormat_Grayscale16: - AddConstantInternal<uint16_t>(image, value); - return; - - case PixelFormat_SignedGrayscale16: - AddConstantInternal<int16_t>(image, value); - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::MultiplyConstant(ImageAccessor& image, - float factor) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - MultiplyConstantInternal<uint8_t>(image, factor); - return; - - case PixelFormat_Grayscale16: - MultiplyConstantInternal<uint16_t>(image, factor); - return; - - case PixelFormat_SignedGrayscale16: - MultiplyConstantInternal<int16_t>(image, factor); - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::ShiftScale(ImageAccessor& image, - float offset, - float scaling) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - ShiftScaleInternal<uint8_t>(image, offset, scaling); - return; - - case PixelFormat_Grayscale16: - ShiftScaleInternal<uint16_t>(image, offset, scaling); - return; - - case PixelFormat_SignedGrayscale16: - ShiftScaleInternal<int16_t>(image, offset, scaling); - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } -}
--- a/Orthanc/ImageFormats/ImageProcessing.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#include <stdint.h> - -namespace Orthanc -{ - class ImageProcessing - { - public: - static void Copy(ImageAccessor& target, - const ImageAccessor& source); - - static void Convert(ImageAccessor& target, - const ImageAccessor& source); - - static void Set(ImageAccessor& image, - int64_t value); - - static void ShiftRight(ImageAccessor& target, - unsigned int shift); - - static void GetMinMaxValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image); - - static void AddConstant(ImageAccessor& image, - int64_t value); - - static void MultiplyConstant(ImageAccessor& image, - float factor); - - static void ShiftScale(ImageAccessor& image, - float offset, - float scaling); - }; -}
--- a/Orthanc/ImageFormats/PngWriter.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "PngWriter.h" - -#include <vector> -#include <stdint.h> -#include <png.h> -#include "../OrthancException.h" -#include "../ChunkedBuffer.h" -#include "../Toolbox.h" - - -// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4 -// http://zarb.org/~gc/html/libpng.html -/* - void write_row_callback(png_ptr, png_uint_32 row, int pass) - { - }*/ - - - - -/* bool isError_; - -// http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2 - -static void ErrorHandler(png_structp png, png_const_charp message) -{ -printf("** [%s]\n", message); - -PngWriter* that = (PngWriter*) png_get_error_ptr(png); -that->isError_ = true; -printf("** %d\n", (int)that); - -//((PngWriter*) payload)->isError_ = true; -} - -static void WarningHandler(png_structp png, png_const_charp message) -{ - printf("++ %d\n", (int)message); -}*/ - - -namespace Orthanc -{ - struct PngWriter::PImpl - { - png_structp png_; - png_infop info_; - - // Filled by Prepare() - std::vector<uint8_t*> rows_; - int bitDepth_; - int colorType_; - }; - - - - PngWriter::PngWriter() : pimpl_(new PImpl) - { - pimpl_->png_ = NULL; - pimpl_->info_ = NULL; - - pimpl_->png_ = png_create_write_struct - (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler); - if (!pimpl_->png_) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - pimpl_->info_ = png_create_info_struct(pimpl_->png_); - if (!pimpl_->info_) - { - png_destroy_write_struct(&pimpl_->png_, NULL); - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - - PngWriter::~PngWriter() - { - if (pimpl_->info_) - { - png_destroy_info_struct(pimpl_->png_, &pimpl_->info_); - } - - if (pimpl_->png_) - { - png_destroy_write_struct(&pimpl_->png_, NULL); - } - } - - - - void PngWriter::Prepare(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - pimpl_->rows_.resize(height); - for (unsigned int y = 0; y < height; y++) - { - pimpl_->rows_[y] = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffer)) + y * pitch; - } - - switch (format) - { - case PixelFormat_RGB24: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_RGB; - break; - - case PixelFormat_RGBA32: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA; - break; - - case PixelFormat_Grayscale8: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; - break; - - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - pimpl_->bitDepth_ = 16; - pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void PngWriter::Compress(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format) - { - png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height, - pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(pimpl_->png_, pimpl_->info_); - - if (height > 0) - { - switch (format) - { - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - { - int transforms = 0; - if (Toolbox::DetectEndianness() == Endianness_Little) - { - transforms = PNG_TRANSFORM_SWAP_ENDIAN; - } - - png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]); - png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL); - - break; - } - - default: - png_write_image(pimpl_->png_, &pimpl_->rows_[0]); - } - } - - png_write_end(pimpl_->png_, NULL); - } - - - void PngWriter::WriteToFile(const char* filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - Prepare(width, height, pitch, format, buffer); - - FILE* fp = fopen(filename, "wb"); - if (!fp) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - png_init_io(pimpl_->png_, fp); - - if (setjmp(png_jmpbuf(pimpl_->png_))) - { - // Error during writing PNG - throw OrthancException(ErrorCode_CannotWriteFile); - } - - Compress(width, height, pitch, format); - - fclose(fp); - } - - - - - static void MemoryCallback(png_structp png_ptr, - png_bytep data, - png_size_t size) - { - ChunkedBuffer* buffer = reinterpret_cast<ChunkedBuffer*>(png_get_io_ptr(png_ptr)); - buffer->AddChunk(reinterpret_cast<const char*>(data), size); - } - - - - void PngWriter::WriteToMemory(std::string& png, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - ChunkedBuffer chunks; - - Prepare(width, height, pitch, format, buffer); - - if (setjmp(png_jmpbuf(pimpl_->png_))) - { - // Error during writing PNG - throw OrthancException(ErrorCode_InternalError); - } - - png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL); - - Compress(width, height, pitch, format); - - chunks.Flatten(png); - } -}
--- a/Orthanc/ImageFormats/PngWriter.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#include <boost/shared_ptr.hpp> -#include <string> - -namespace Orthanc -{ - class PngWriter - { - private: - struct PImpl; - boost::shared_ptr<PImpl> pimpl_; - - void Compress(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format); - - void Prepare(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - public: - PngWriter(); - - ~PngWriter(); - - void WriteToFile(const char* filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - void WriteToMemory(std::string& png, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - void WriteToFile(const char* filename, - const ImageAccessor& accessor) - { - WriteToFile(filename, accessor.GetWidth(), accessor.GetHeight(), - accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); - } - - void WriteToMemory(std::string& png, - const ImageAccessor& accessor) - { - WriteToMemory(png, accessor.GetWidth(), accessor.GetHeight(), - accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); - } - }; -}
--- a/Orthanc/MultiThreading/SharedMessageQueue.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "SharedMessageQueue.h" - - - -/** - * FIFO (queue): - * - * back front - * +--+--+--+--+--+--+--+--+--+--+--+ - * Enqueue -> | | | | | | | | | | | | - * | | | | | | | | | | | | -> Dequeue - * +--+--+--+--+--+--+--+--+--+--+--+ - * ^ - * | - * Make room here - * - * - * LIFO (stack): - * - * back front - * +--+--+--+--+--+--+--+--+--+--+--+ - * | | | | | | | | | | | | <- Enqueue - * | | | | | | | | | | | | -> Dequeue - * +--+--+--+--+--+--+--+--+--+--+--+ - * ^ - * | - * Make room here - **/ - - -namespace Orthanc -{ - SharedMessageQueue::SharedMessageQueue(unsigned int maxSize) : - isFifo_(true), - maxSize_(maxSize) - { - } - - - SharedMessageQueue::~SharedMessageQueue() - { - for (Queue::iterator it = queue_.begin(); it != queue_.end(); ++it) - { - delete *it; - } - } - - - void SharedMessageQueue::Enqueue(IDynamicObject* message) - { - boost::mutex::scoped_lock lock(mutex_); - - if (maxSize_ != 0 && queue_.size() > maxSize_) - { - if (isFifo_) - { - // Too many elements in the queue: Make room - delete queue_.front(); - queue_.pop_front(); - } - else - { - // Too many elements in the stack: Make room - delete queue_.back(); - queue_.pop_back(); - } - } - - if (isFifo_) - { - // Queue policy (FIFO) - queue_.push_back(message); - } - else - { - // Stack policy (LIFO) - queue_.push_front(message); - } - - elementAvailable_.notify_one(); - } - - - IDynamicObject* SharedMessageQueue::Dequeue(int32_t millisecondsTimeout) - { - boost::mutex::scoped_lock lock(mutex_); - - // Wait for a message to arrive in the FIFO queue - while (queue_.empty()) - { - if (millisecondsTimeout == 0) - { - elementAvailable_.wait(lock); - } - else - { - bool success = elementAvailable_.timed_wait - (lock, boost::posix_time::milliseconds(millisecondsTimeout)); - if (!success) - { - return NULL; - } - } - } - - std::auto_ptr<IDynamicObject> message(queue_.front()); - queue_.pop_front(); - - if (queue_.empty()) - { - emptied_.notify_all(); - } - - return message.release(); - } - - - - bool SharedMessageQueue::WaitEmpty(int32_t millisecondsTimeout) - { - boost::mutex::scoped_lock lock(mutex_); - - // Wait for the queue to become empty - while (!queue_.empty()) - { - if (millisecondsTimeout == 0) - { - emptied_.wait(lock); - } - else - { - if (!emptied_.timed_wait - (lock, boost::posix_time::milliseconds(millisecondsTimeout))) - { - return false; - } - } - } - - return true; - } - - - void SharedMessageQueue::SetFifoPolicy() - { - boost::mutex::scoped_lock lock(mutex_); - isFifo_ = true; - } - - void SharedMessageQueue::SetLifoPolicy() - { - boost::mutex::scoped_lock lock(mutex_); - isFifo_ = false; - } -}
--- a/Orthanc/MultiThreading/SharedMessageQueue.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../IDynamicObject.h" - -#include <stdint.h> -#include <list> -#include <boost/thread.hpp> - -namespace Orthanc -{ - class SharedMessageQueue : public boost::noncopyable - { - private: - typedef std::list<IDynamicObject*> Queue; - - bool isFifo_; - unsigned int maxSize_; - Queue queue_; - boost::mutex mutex_; - boost::condition_variable elementAvailable_; - boost::condition_variable emptied_; - - public: - explicit SharedMessageQueue(unsigned int maxSize = 0); - - ~SharedMessageQueue(); - - // This transfers the ownership of the message - void Enqueue(IDynamicObject* message); - - // The caller is responsible to delete the dequeud message! - IDynamicObject* Dequeue(int32_t millisecondsTimeout); - - bool WaitEmpty(int32_t millisecondsTimeout); - - bool IsFifoPolicy() const - { - return isFifo_; - } - - bool IsLifoPolicy() const - { - return !isFifo_; - } - - void SetFifoPolicy(); - - void SetLifoPolicy(); - }; -}
--- a/Orthanc/OrthancException.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h" -#include "OrthancException.h" - -namespace Orthanc -{ - const char* OrthancException::What() const - { - if (error_ == ErrorCode_Custom) - { - return custom_.c_str(); - } - else - { - return GetDescription(error_); - } - } - - - const char* OrthancException::GetDescription(ErrorCode error) - { - switch (error) - { - case ErrorCode_Success: - return "Success"; - - case ErrorCode_ParameterOutOfRange: - return "Parameter out of range"; - - case ErrorCode_NotImplemented: - return "Not implemented yet"; - - case ErrorCode_InternalError: - return "Internal error"; - - case ErrorCode_NotEnoughMemory: - return "Not enough memory"; - - case ErrorCode_UriSyntax: - return "Badly formatted URI"; - - case ErrorCode_BadParameterType: - return "Bad type for a parameter"; - - case ErrorCode_InexistentFile: - return "Inexistent file"; - - case ErrorCode_BadFileFormat: - return "Bad file format"; - - case ErrorCode_CannotWriteFile: - return "Cannot write to file"; - - case ErrorCode_Timeout: - return "Timeout"; - - case ErrorCode_UnknownResource: - return "Unknown resource"; - - case ErrorCode_BadSequenceOfCalls: - return "Bad sequence of calls"; - - case ErrorCode_IncompatibleDatabaseVersion: - return "Incompatible version of the database"; - - case ErrorCode_FullStorage: - return "The file storage is full"; - - case ErrorCode_InexistentItem: - return "Accessing an inexistent item"; - - case ErrorCode_BadRequest: - return "Bad request"; - - case ErrorCode_NetworkProtocol: - return "Error in the network protocol"; - - case ErrorCode_CorruptedFile: - return "Corrupted file (inconsistent MD5 hash)"; - - case ErrorCode_InexistentTag: - return "Inexistent tag"; - - case ErrorCode_ReadOnly: - return "Cannot modify a read-only data structure"; - - case ErrorCode_IncompatibleImageSize: - return "Incompatible size of the images"; - - case ErrorCode_IncompatibleImageFormat: - return "Incompatible format of the images"; - - case ErrorCode_SharedLibrary: - return "Error while using a shared library (plugin)"; - - case ErrorCode_SystemCommand: - return "Error while calling a system command"; - - case ErrorCode_Plugin: - return "Error encountered inside a plugin"; - - case ErrorCode_Database: - return "Error with the database engine"; - - case ErrorCode_Custom: - default: - return "???"; - } - } -}
--- a/Orthanc/OrthancException.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include <string> -#include "Enumerations.h" - -namespace Orthanc -{ - class OrthancException - { - protected: - ErrorCode error_; - std::string custom_; - - public: - static const char* GetDescription(ErrorCode error); - - OrthancException(const char* custom) : - error_(ErrorCode_Custom), - custom_(custom) - { - } - - OrthancException(const std::string& custom) : - error_(ErrorCode_Custom), - custom_(custom) - { - } - - OrthancException(ErrorCode error) : error_(error) - { - } - - ErrorCode GetErrorCode() const - { - return error_; - } - - const char* What() const; - }; -}
--- a/Orthanc/PrecompiledHeaders.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h"
--- a/Orthanc/PrecompiledHeaders.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#if defined(_WIN32) && !defined(NOMINMAX) -#define NOMINMAX -#endif - -#if ORTHANC_USE_PRECOMPILED_HEADERS == 1 - -#include <boost/date_time/posix_time/posix_time.hpp> -#include <boost/filesystem.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/locale.hpp> -#include <boost/regex.hpp> -#include <boost/thread.hpp> -#include <boost/thread/shared_mutex.hpp> - -#include <glog/logging.h> -#include <json/value.h> - -#if ORTHANC_PUGIXML_ENABLED == 1 -#include <pugixml.hpp> -#endif - -#include "Enumerations.h" -#include "OrthancException.h" -#include "Toolbox.h" -#include "Uuid.h" - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/AutoGeneratedCode.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,41 @@ +set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED") +set(AUTOGENERATED_SOURCES) + +file(MAKE_DIRECTORY ${AUTOGENERATED_DIR}) +include_directories(${AUTOGENERATED_DIR}) + +macro(EmbedResources) + # Convert a semicolon separated list to a whitespace separated string + set(SCRIPT_ARGUMENTS) + set(DEPENDENCIES) + set(IS_PATH_NAME false) + foreach(arg ${ARGN}) + if (${IS_PATH_NAME}) + list(APPEND SCRIPT_ARGUMENTS "${arg}") + list(APPEND DEPENDENCIES "${arg}") + set(IS_PATH_NAME false) + else() + list(APPEND SCRIPT_ARGUMENTS "${arg}") + set(IS_PATH_NAME true) + endif() + endforeach() + + set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources") + add_custom_command( + OUTPUT + "${TARGET_BASE}.h" + "${TARGET_BASE}.cpp" + COMMAND + ${PYTHON_EXECUTABLE} + "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py" + "${AUTOGENERATED_DIR}/EmbeddedResources" + ${SCRIPT_ARGUMENTS} + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py" + ${DEPENDENCIES} + ) + + list(APPEND AUTOGENERATED_SOURCES + "${AUTOGENERATED_DIR}/EmbeddedResources.cpp" + ) +endmacro()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/BoostConfiguration.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,160 @@ +if (STATIC_BUILD OR NOT USE_SYSTEM_BOOST) + set(BOOST_STATIC 1) +else() + include(FindBoost) + + set(BOOST_STATIC 0) + #set(Boost_DEBUG 1) + #set(Boost_USE_STATIC_LIBS ON) + + find_package(Boost + COMPONENTS filesystem thread system date_time regex locale) + + if (NOT Boost_FOUND) + message(FATAL_ERROR "Unable to locate Boost on this system") + endif() + + # Boost releases 1.44 through 1.47 supply both V2 and V3 filesystem + # http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/index.htm + if (${Boost_VERSION} LESS 104400) + add_definitions( + -DBOOST_HAS_FILESYSTEM_V3=0 + ) + else() + add_definitions( + -DBOOST_HAS_FILESYSTEM_V3=1 + -DBOOST_FILESYSTEM_VERSION=3 + ) + endif() + + #if (${Boost_VERSION} LESS 104800) + # boost::locale is only available from 1.48.00 + #message("Too old version of Boost (${Boost_LIB_VERSION}): Building the static version") + # set(BOOST_STATIC 1) + #endif() + + include_directories(${Boost_INCLUDE_DIRS}) + link_libraries(${Boost_LIBRARIES}) +endif() + + +if (BOOST_STATIC) + # Parameters for Boost 1.55.0 + set(BOOST_NAME boost_1_55_0) + set(BOOST_BCP_SUFFIX bcpdigest-0.7.4) + set(BOOST_MD5 "409f7a0e4fb1f5659d07114f3133b67b") + set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src") + + set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) + DownloadPackage( + "${BOOST_MD5}" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz" + "${BOOST_SOURCES_DIR}" + ) + + set(BOOST_SOURCES) + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") + list(APPEND BOOST_SOURCES + ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp + ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp + ) + add_definitions( + -DBOOST_LOCALE_WITH_ICONV=1 + ) + + if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + add_definitions(-DBOOST_HAS_SCHED_YIELD=1) + endif() + + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(APPEND BOOST_SOURCES + ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp + ${BOOST_SOURCES_DIR}/libs/thread/src/win32/thread.cpp + ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_pe.cpp + ${BOOST_FILESYSTEM_SOURCES_DIR}/windows_file_codecvt.cpp + ) + + # Starting with release 0.8.2, Orthanc statically links against + # libiconv, even on Windows. Indeed, the "WCONV" library of + # Windows XP seems not to support properly several codepages + # (notably "Latin3", "Hebrew", and "Arabic"). + + if (USE_BOOST_ICONV) + include(${ORTHANC_ROOT}/Resources/CMake/LibIconvConfiguration.cmake) + else() + add_definitions(-DBOOST_LOCALE_WITH_WCONV=1) + endif() + + else() + message(FATAL_ERROR "Support your platform here") + endif() + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + list(APPEND BOOST_SOURCES + ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp + ) + endif() + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # This is a patch to compile Boost 1.55.0 with Clang 3.4 and later + # (including XCode 5.1). Fixes issue 14 of Orthanc. + # https://trac.macports.org/ticket/42282#comment:10 + execute_process( + COMMAND patch -p0 -N -i ${ORTHANC_ROOT}/Resources/Patches/boost-1.55.0-clang-atomic.patch + WORKING_DIRECTORY ${BOOST_SOURCES_DIR} + ) + endif() + + aux_source_directory(${BOOST_SOURCES_DIR}/libs/regex/src BOOST_REGEX_SOURCES) + + list(APPEND BOOST_SOURCES + ${BOOST_REGEX_SOURCES} + ${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp + ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp + ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp + ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp + ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp + ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp + ) + + list(APPEND THIRD_PARTY_SOURCES ${BOOST_SOURCES}) + + add_definitions( + # Static build of Boost + -DBOOST_ALL_NO_LIB + -DBOOST_ALL_NOLIB + -DBOOST_DATE_TIME_NO_LIB + -DBOOST_THREAD_BUILD_LIB + -DBOOST_PROGRAM_OPTIONS_NO_LIB + -DBOOST_REGEX_NO_LIB + -DBOOST_SYSTEM_NO_LIB + -DBOOST_LOCALE_NO_LIB + -DBOOST_HAS_LOCALE=1 + -DBOOST_HAS_FILESYSTEM_V3=1 + ) + + if (${CMAKE_COMPILER_IS_GNUCXX}) + add_definitions(-isystem ${BOOST_SOURCES_DIR}) + endif() + + include_directories( + ${BOOST_SOURCES_DIR} + ) + + source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*) +else() + add_definitions( + -DBOOST_HAS_LOCALE=1 + ) +endif() + + +add_definitions( + -DBOOST_HAS_DATE_TIME=1 + -DBOOST_HAS_REGEX=1 + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/Compiler.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,125 @@ +# This file sets all the compiler-related flags + +if (${CMAKE_COMPILER_IS_GNUCXX}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long -Wno-implicit-function-declaration") + # --std=c99 makes libcurl not to compile + # -pedantic gives a lot of warnings on OpenSSL + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wno-long-long -Wno-variadic-macros") + + if (CMAKE_CROSSCOMPILING) + # http://stackoverflow.com/a/3543845/881731 + set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff -I<CMAKE_CURRENT_SOURCE_DIR> <SOURCE> <OBJECT>") + endif() + +elseif (${MSVC}) + # Use static runtime under Visual Studio + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace + # http://stackoverflow.com/a/6510446 + foreach(flag_var + CMAKE_C_FLAGS_DEBUG + CMAKE_CXX_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + + # Add /Zm256 compiler option to Visual Studio to fix PCH errors + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm256") + + add_definitions( + -D_CRT_SECURE_NO_WARNINGS=1 + -D_CRT_SECURE_NO_DEPRECATE=1 + ) + include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio) + link_libraries(netapi32) +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + + # Remove the "-rdynamic" option + # http://www.mail-archive.com/cmake@cmake.org/msg08837.html + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + link_libraries(uuid pthread rt) + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") + add_definitions( + -D_LARGEFILE64_SOURCE=1 + -D_FILE_OFFSET_BITS=64 + ) + link_libraries(dl) + endif() + +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + add_definitions( + -DWINVER=0x0501 + -D_CRT_SECURE_NO_WARNINGS=1 + ) + link_libraries(rpcrt4 ws2_32) + + if (${CMAKE_COMPILER_IS_GNUCXX}) + # This is a patch for MinGW64 + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") + + CHECK_LIBRARY_EXISTS(winpthread pthread_create "" HAVE_WIN_PTHREAD) + if (HAVE_WIN_PTHREAD) + # This line is necessary to compile with recent versions of MinGW, + # otherwise "libwinpthread-1.dll" is not statically linked. + SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic") + add_definitions(-DHAVE_WIN_PTHREAD=1) + else() + add_definitions(-DHAVE_WIN_PTHREAD=0) + endif() + endif() + +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + add_definitions( + -D_XOPEN_SOURCE=1 + ) + link_libraries(iconv) + +endif() + + +if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -I${LSB_PATH}/include") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -nostdinc++ -I${LSB_PATH}/include -I${LSB_PATH}/include/c++ -I${LSB_PATH}/include/c++/backward -fpermissive") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH}") +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + # In FreeBSD, the "/usr/local/" folder contains the ports and need to be imported + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") + SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib") +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + CHECK_INCLUDE_FILES(rpc.h HAVE_UUID_H) +else() + CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) +endif() + +if (NOT HAVE_UUID_H) + message(FATAL_ERROR "Please install the uuid-dev package") +endif() + + +if (${STATIC_BUILD}) + add_definitions(-DORTHANC_STATIC=1) +else() + add_definitions(-DORTHANC_STATIC=0) +endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/DownloadPackage.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,138 @@ +macro(GetUrlFilename TargetVariable Url) + string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}") +endmacro() + + +macro(GetUrlExtension TargetVariable Url) + #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}") + string(REGEX REPLACE "^.*\\." "" TMP "${Url}") + string(TOLOWER "${TMP}" "${TargetVariable}") +endmacro() + + +## +## Check the existence of the required decompression tools +## + +if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + find_program(ZIP_EXECUTABLE 7z + PATHS + "$ENV{ProgramFiles}/7-Zip" + "$ENV{ProgramW6432}/7-Zip" + ) + + if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") + endif() + +else() + find_program(UNZIP_EXECUTABLE unzip) + if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'unzip' package") + endif() + + find_program(TAR_EXECUTABLE tar) + if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'tar' package") + endif() +endif() + + +macro(DownloadPackage MD5 Url TargetDirectory) + if (NOT IS_DIRECTORY "${TargetDirectory}") + GetUrlFilename(TMP_FILENAME "${Url}") + + set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}") + if (NOT EXISTS "${TMP_PATH}") + message("Downloading ${Url}") + + # This fixes issue 6: "I think cmake shouldn't download the + # packages which are not in the system, it should stop and let + # user know." + # https://code.google.com/p/orthanc/issues/detail?id=6 + if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) + message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") + endif() + + file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}") + else() + message("Using local copy of ${Url}") + endif() + + GetUrlExtension(TMP_EXTENSION "${Url}") + #message(${TMP_EXTENSION}) + message("Uncompressing ${TMP_FILENAME}") + + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + # How to silently extract files using 7-zip + # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly + + if (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) + execute_process( + COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if ("${TMP_EXTENSION}" STREQUAL "tgz") + string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}") + else() + string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") + endif() + + execute_process( + COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + elseif ("${TMP_EXTENSION}" STREQUAL "zip") + execute_process( + COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + else() + message(FATAL_ERROR "Support your platform here") + endif() + + else() + if ("${TMP_EXTENSION}" STREQUAL "zip") + execute_process( + COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) + #message("tar xvfz ${TMP_PATH}") + execute_process( + COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + elseif ("${TMP_EXTENSION}" STREQUAL "bz2") + execute_process( + COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + else() + message(FATAL_ERROR "Unknown package format.") + endif() + endif() + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if (NOT IS_DIRECTORY "${TargetDirectory}") + message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.") + endif() + endif() +endmacro()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/GoogleTestConfiguration.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,39 @@ +if (USE_GTEST_DEBIAN_SOURCE_PACKAGE) + set(GTEST_SOURCES /usr/src/gtest/src/gtest-all.cc) + include_directories(/usr/src/gtest) + + if (NOT EXISTS /usr/include/gtest/gtest.h OR + NOT EXISTS ${GTEST_SOURCES}) + message(FATAL_ERROR "Please install the libgtest-dev package") + endif() + +elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST) + set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0) + DownloadPackage( + "2d6ec8ccdf5c46b05ba54a9fd1d130d7" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/gtest-1.7.0.zip" + "${GTEST_SOURCES_DIR}") + + include_directories( + ${GTEST_SOURCES_DIR}/include + ${GTEST_SOURCES_DIR} + ) + + set(GTEST_SOURCES + ${GTEST_SOURCES_DIR}/src/gtest-all.cc + ) + + # https://code.google.com/p/googletest/issues/detail?id=412 + if (MSVC) # VS2012 does not support tuples correctly yet + add_definitions(/D _VARIADIC_MAX=10) + endif() + +else() + include(FindGTest) + if (NOT GTEST_FOUND) + message(FATAL_ERROR "Unable to find GoogleTest") + endif() + + include_directories(${GTEST_INCLUDE_DIRS}) + link_libraries(${GTEST_LIBRARIES}) +endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/LibPngConfiguration.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,60 @@ +if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG) + SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.5.12) + DownloadPackage( + "8ea7f60347a306c5faf70b977fa80e28" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libpng-1.5.12.tar.gz" + "${LIBPNG_SOURCES_DIR}") + + include_directories( + ${LIBPNG_SOURCES_DIR} + ) + + configure_file( + ${LIBPNG_SOURCES_DIR}/scripts/pnglibconf.h.prebuilt + ${LIBPNG_SOURCES_DIR}/pnglibconf.h + COPY_ONLY) + + set(LIBPNG_SOURCES + #${LIBPNG_SOURCES_DIR}/example.c + ${LIBPNG_SOURCES_DIR}/png.c + ${LIBPNG_SOURCES_DIR}/pngerror.c + ${LIBPNG_SOURCES_DIR}/pngget.c + ${LIBPNG_SOURCES_DIR}/pngmem.c + ${LIBPNG_SOURCES_DIR}/pngpread.c + ${LIBPNG_SOURCES_DIR}/pngread.c + ${LIBPNG_SOURCES_DIR}/pngrio.c + ${LIBPNG_SOURCES_DIR}/pngrtran.c + ${LIBPNG_SOURCES_DIR}/pngrutil.c + ${LIBPNG_SOURCES_DIR}/pngset.c + #${LIBPNG_SOURCES_DIR}/pngtest.c + ${LIBPNG_SOURCES_DIR}/pngtrans.c + ${LIBPNG_SOURCES_DIR}/pngwio.c + ${LIBPNG_SOURCES_DIR}/pngwrite.c + ${LIBPNG_SOURCES_DIR}/pngwtran.c + ${LIBPNG_SOURCES_DIR}/pngwutil.c + ) + + #set_property( + # SOURCE ${LIBPNG_SOURCES} + # PROPERTY COMPILE_FLAGS -UHAVE_CONFIG_H) + + list(APPEND THIRD_PARTY_SOURCES ${LIBPNG_SOURCES}) + + add_definitions( + -DPNG_NO_CONSOLE_IO=1 + -DPNG_NO_STDIO=1 + ) + + source_group(ThirdParty\\Libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*) + +else() + include(FindPNG) + + if (NOT ${PNG_FOUND}) + message(FATAL_ERROR "Unable to find LibPNG") + endif() + + include_directories(${PNG_INCLUDE_DIRS}) + link_libraries(${PNG_LIBRARIES}) + add_definitions(${PNG_DEFINITIONS}) +endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/SQLiteConfiguration.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,49 @@ +if (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) + SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3071300) + DownloadPackage( + "5fbeff9645ab035a1f580e90b279a16d" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/sqlite-amalgamation-3071300.zip" + "${SQLITE_SOURCES_DIR}") + + list(APPEND THIRD_PARTY_SOURCES + ${SQLITE_SOURCES_DIR}/sqlite3.c + ) + + add_definitions( + # For SQLite to run in the "Serialized" thread-safe mode + # http://www.sqlite.org/threadsafe.html + -DSQLITE_THREADSAFE=1 + -DSQLITE_OMIT_LOAD_EXTENSION # Disable SQLite plugins + ) + + include_directories( + ${SQLITE_SOURCES_DIR} + ) + + source_group(ThirdParty\\SQLite REGULAR_EXPRESSION ${SQLITE_SOURCES_DIR}/.*) + +else() + CHECK_INCLUDE_FILE_CXX(sqlite3.h HAVE_SQLITE_H) + if (NOT HAVE_SQLITE_H) + message(FATAL_ERROR "Please install the libsqlite3-dev package") + endif() + + find_path(SQLITE_INCLUDE_DIR sqlite3.h + /usr/include + /usr/local/include + ) + message("SQLite include dir: ${SQLITE_INCLUDE_DIR}") + + # Autodetection of the version of SQLite + file(STRINGS "${SQLITE_INCLUDE_DIR}/sqlite3.h" SQLITE_VERSION_NUMBER1 REGEX "#define SQLITE_VERSION_NUMBER.*$") + string(REGEX REPLACE "#define SQLITE_VERSION_NUMBER(.*)$" "\\1" SQLITE_VERSION_NUMBER ${SQLITE_VERSION_NUMBER1}) + + message("Detected version of SQLite: ${SQLITE_VERSION_NUMBER}") + + IF (${SQLITE_VERSION_NUMBER} LESS 3007000) + # "sqlite3_create_function_v2" is not defined in SQLite < 3.7.0 + message(FATAL_ERROR "SQLite version must be above 3.7.0. Please set the CMake variable USE_SYSTEM_SQLITE to OFF.") + ENDIF() + + link_libraries(sqlite3) +endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/CMake/ZlibConfiguration.cmake Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,42 @@ +# This is the minizip distribution to create ZIP files +list(APPEND THIRD_PARTY_SOURCES + ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/ioapi.c + ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/zip.c + ) + +if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB) + SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.7) + DownloadPackage( + "60df6a37c56e7c1366cca812414f7b85" + "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/zlib-1.2.7.tar.gz" + "${ZLIB_SOURCES_DIR}") + + include_directories( + ${ZLIB_SOURCES_DIR} + ) + + list(APPEND THIRD_PARTY_SOURCES + ${ZLIB_SOURCES_DIR}/adler32.c + ${ZLIB_SOURCES_DIR}/compress.c + ${ZLIB_SOURCES_DIR}/crc32.c + ${ZLIB_SOURCES_DIR}/deflate.c + ${ZLIB_SOURCES_DIR}/gzclose.c + ${ZLIB_SOURCES_DIR}/gzlib.c + ${ZLIB_SOURCES_DIR}/gzread.c + ${ZLIB_SOURCES_DIR}/gzwrite.c + ${ZLIB_SOURCES_DIR}/infback.c + ${ZLIB_SOURCES_DIR}/inffast.c + ${ZLIB_SOURCES_DIR}/inflate.c + ${ZLIB_SOURCES_DIR}/inftrees.c + ${ZLIB_SOURCES_DIR}/trees.c + ${ZLIB_SOURCES_DIR}/uncompr.c + ${ZLIB_SOURCES_DIR}/zutil.c + ) + +else() + include(FindZLIB) + include_directories(${ZLIB_INCLUDE_DIRS}) + link_libraries(${ZLIB_LIBRARIES}) +endif() + +source_group(ThirdParty\\ZLib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/ThirdParty/base64/base64.cpp Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,128 @@ +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#include "base64.h" +#include <string.h> + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(const std::string& stringToEncode) +{ + const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*> + (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL); + unsigned int in_len = stringToEncode.size(); + + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; +} + + +std::string base64_decode(const std::string& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/ThirdParty/base64/base64.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,4 @@ +#include <string> + +std::string base64_encode(const std::string& stringToEncode); +std::string base64_decode(const std::string& s);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/ThirdParty/md5/md5.c Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,381 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include <string.h> + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orthanc/Resources/ThirdParty/md5/md5.h Tue Jun 02 11:16:30 2015 +0200 @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */
--- a/Orthanc/SQLite/Connection.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Connection.h" -#include "OrthancSQLiteException.h" - -#include <memory> -#include <cassert> -#include <sqlite3.h> -#include <string.h> - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include <glog/logging.h> -#endif - - -namespace Orthanc -{ - namespace SQLite - { - Connection::Connection() : - db_(NULL), - transactionNesting_(0), - needsRollback_(false) - { - } - - - Connection::~Connection() - { - Close(); - } - - - void Connection::CheckIsOpen() const - { - if (!db_) - { - throw OrthancSQLiteException("SQLite: The database is not opened"); - } - } - - void Connection::Open(const std::string& path) - { - if (db_) - { - throw OrthancSQLiteException("SQLite: Connection is already open"); - } - - int err = sqlite3_open(path.c_str(), &db_); - if (err != SQLITE_OK) - { - Close(); - db_ = NULL; - throw OrthancSQLiteException("SQLite: Unable to open the database"); - } - - // Execute PRAGMAs at this point - // http://www.sqlite.org/pragma.html - Execute("PRAGMA FOREIGN_KEYS=ON;"); - Execute("PRAGMA RECURSIVE_TRIGGERS=ON;"); - } - - void Connection::OpenInMemory() - { - Open(":memory:"); - } - - void Connection::Close() - { - ClearCache(); - - if (db_) - { - sqlite3_close(db_); - db_ = NULL; - } - } - - void Connection::ClearCache() - { - for (CachedStatements::iterator - it = cachedStatements_.begin(); - it != cachedStatements_.end(); ++it) - { - delete it->second; - } - - cachedStatements_.clear(); - } - - - StatementReference& Connection::GetCachedStatement(const StatementId& id, - const char* sql) - { - CachedStatements::iterator i = cachedStatements_.find(id); - if (i != cachedStatements_.end()) - { - if (i->second->GetReferenceCount() >= 1) - { - throw OrthancSQLiteException("SQLite: This cached statement is already being referred to"); - } - - return *i->second; - } - else - { - StatementReference* statement = new StatementReference(db_, sql); - cachedStatements_[id] = statement; - return *statement; - } - } - - - bool Connection::Execute(const char* sql) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Connection::Execute " << sql; -#endif - - CheckIsOpen(); - - int error = sqlite3_exec(db_, sql, NULL, NULL, NULL); - if (error == SQLITE_ERROR) - { - throw OrthancSQLiteException("SQLite Execute error: " + std::string(sqlite3_errmsg(db_))); - } - else - { - return error == SQLITE_OK; - } - } - - int Connection::ExecuteAndReturnErrorCode(const char* sql) - { - CheckIsOpen(); - return sqlite3_exec(db_, sql, NULL, NULL, NULL); - } - - // Info querying ------------------------------------------------------------- - - bool Connection::IsSQLValid(const char* sql) - { - sqlite3_stmt* stmt = NULL; - if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) - return false; - - sqlite3_finalize(stmt); - return true; - } - - bool Connection::DoesTableOrIndexExist(const char* name, - const char* type) const - { - // Our SQL is non-mutating, so this cast is OK. - Statement statement(const_cast<Connection&>(*this), - "SELECT name FROM sqlite_master WHERE type=? AND name=?"); - statement.BindString(0, type); - statement.BindString(1, name); - return statement.Step(); // Table exists if any row was returned. - } - - bool Connection::DoesTableExist(const char* table_name) const - { - return DoesTableOrIndexExist(table_name, "table"); - } - - bool Connection::DoesIndexExist(const char* index_name) const - { - return DoesTableOrIndexExist(index_name, "index"); - } - - bool Connection::DoesColumnExist(const char* table_name, const char* column_name) const - { - std::string sql("PRAGMA TABLE_INFO("); - sql.append(table_name); - sql.append(")"); - - // Our SQL is non-mutating, so this cast is OK. - Statement statement(const_cast<Connection&>(*this), sql.c_str()); - - while (statement.Step()) { - if (!statement.ColumnString(1).compare(column_name)) - return true; - } - return false; - } - - int64_t Connection::GetLastInsertRowId() const - { - return sqlite3_last_insert_rowid(db_); - } - - int Connection::GetLastChangeCount() const - { - return sqlite3_changes(db_); - } - - int Connection::GetErrorCode() const - { - return sqlite3_errcode(db_); - } - - int Connection::GetLastErrno() const - { - int err = 0; - if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err)) - return -2; - - return err; - } - - const char* Connection::GetErrorMessage() const - { - return sqlite3_errmsg(db_); - } - - - bool Connection::BeginTransaction() - { - if (needsRollback_) - { - assert(transactionNesting_ > 0); - - // When we're going to rollback, fail on this begin and don't actually - // mark us as entering the nested transaction. - return false; - } - - bool success = true; - if (!transactionNesting_) - { - needsRollback_ = false; - - Statement begin(*this, SQLITE_FROM_HERE, "BEGIN TRANSACTION"); - if (!begin.Run()) - return false; - } - transactionNesting_++; - return success; - } - - void Connection::RollbackTransaction() - { - if (!transactionNesting_) - { - throw OrthancSQLiteException("Rolling back a nonexistent transaction"); - } - - transactionNesting_--; - - if (transactionNesting_ > 0) - { - // Mark the outermost transaction as needing rollback. - needsRollback_ = true; - return; - } - - DoRollback(); - } - - bool Connection::CommitTransaction() - { - if (!transactionNesting_) - { - throw OrthancSQLiteException("Committing a nonexistent transaction"); - } - transactionNesting_--; - - if (transactionNesting_ > 0) - { - // Mark any nested transactions as failing after we've already got one. - return !needsRollback_; - } - - if (needsRollback_) - { - DoRollback(); - return false; - } - - Statement commit(*this, SQLITE_FROM_HERE, "COMMIT"); - return commit.Run(); - } - - void Connection::DoRollback() - { - Statement rollback(*this, SQLITE_FROM_HERE, "ROLLBACK"); - rollback.Run(); - needsRollback_ = false; - } - - - - - - - static void ScalarFunctionCaller(sqlite3_context* rawContext, - int argc, - sqlite3_value** argv) - { - FunctionContext context(rawContext, argc, argv); - - void* payload = sqlite3_user_data(rawContext); - assert(payload != NULL); - - IScalarFunction& func = *reinterpret_cast<IScalarFunction*>(payload); - func.Compute(context); - } - - - static void ScalarFunctionDestroyer(void* payload) - { - assert(payload != NULL); - delete reinterpret_cast<IScalarFunction*>(payload); - } - - - IScalarFunction* Connection::Register(IScalarFunction* func) - { - int err = sqlite3_create_function_v2(db_, - func->GetName(), - func->GetCardinality(), - SQLITE_UTF8, - func, - ScalarFunctionCaller, - NULL, - NULL, - ScalarFunctionDestroyer); - - if (err != SQLITE_OK) - { - delete func; - throw OrthancSQLiteException("SQLite: Unable to register a function"); - } - - return func; - } - - - void Connection::FlushToDisk() - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Connection::FlushToDisk"; -#endif - - int err = sqlite3_wal_checkpoint(db_, NULL); - - if (err != SQLITE_OK) - { - throw OrthancSQLiteException("SQLite: Unable to flush the database"); - } - } - } -}
--- a/Orthanc/SQLite/Connection.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "Statement.h" -#include "IScalarFunction.h" - -#include <string> -#include <map> - -struct sqlite3; -struct sqlite3_stmt; - -#define SQLITE_FROM_HERE SQLite::StatementId(__FILE__, __LINE__) - -namespace Orthanc -{ - namespace SQLite - { - class Connection : NonCopyable - { - friend class Statement; - friend class Transaction; - - private: - // All cached statements. Keeping a reference to these statements means that - // they'll remain active. - typedef std::map<StatementId, StatementReference*> CachedStatements; - CachedStatements cachedStatements_; - - // The actual sqlite database. Will be NULL before Init has been called or if - // Init resulted in an error. - sqlite3* db_; - - // Number of currently-nested transactions. - int transactionNesting_; - - // True if any of the currently nested transactions have been rolled back. - // When we get to the outermost transaction, this will determine if we do - // a rollback instead of a commit. - bool needsRollback_; - - void ClearCache(); - - void CheckIsOpen() const; - - sqlite3* GetWrappedObject() - { - return db_; - } - - StatementReference& GetCachedStatement(const StatementId& id, - const char* sql); - - bool DoesTableOrIndexExist(const char* name, - const char* type) const; - - void DoRollback(); - - public: - // The database is opened by calling Open[InMemory](). Any uncommitted - // transactions will be rolled back when this object is deleted. - Connection(); - ~Connection(); - - void Open(const std::string& path); - - void OpenInMemory(); - - void Close(); - - bool Execute(const char* sql); - - bool Execute(const std::string& sql) - { - return Execute(sql.c_str()); - } - - void FlushToDisk(); - - IScalarFunction* Register(IScalarFunction* func); // Takes the ownership of the function - - // Info querying ------------------------------------------------------------- - - // Used to check a |sql| statement for syntactic validity. If the - // statement is valid SQL, returns true. - bool IsSQLValid(const char* sql); - - // Returns true if the given table exists. - bool DoesTableExist(const char* table_name) const; - - // Returns true if the given index exists. - bool DoesIndexExist(const char* index_name) const; - - // Returns true if a column with the given name exists in the given table. - bool DoesColumnExist(const char* table_name, const char* column_name) const; - - // Returns sqlite's internal ID for the last inserted row. Valid only - // immediately after an insert. - int64_t GetLastInsertRowId() const; - - // Returns sqlite's count of the number of rows modified by the last - // statement executed. Will be 0 if no statement has executed or the database - // is closed. - int GetLastChangeCount() const; - - // Errors -------------------------------------------------------------------- - - // Returns the error code associated with the last sqlite operation. - int GetErrorCode() const; - - // Returns the errno associated with GetErrorCode(). See - // SQLITE_LAST_ERRNO in SQLite documentation. - int GetLastErrno() const; - - // Returns a pointer to a statically allocated string associated with the - // last sqlite operation. - const char* GetErrorMessage() const; - - - // Diagnostics (for unit tests) ---------------------------------------------- - - int ExecuteAndReturnErrorCode(const char* sql); - - bool HasCachedStatement(const StatementId& id) const - { - return cachedStatements_.find(id) != cachedStatements_.end(); - } - - int GetTransactionNesting() const - { - return transactionNesting_; - } - - // Transactions -------------------------------------------------------------- - - bool BeginTransaction(); - void RollbackTransaction(); - bool CommitTransaction(); - }; - } -}
--- a/Orthanc/SQLite/FunctionContext.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "FunctionContext.h" -#include "OrthancSQLiteException.h" - -#include <sqlite3.h> - -namespace Orthanc -{ - namespace SQLite - { - FunctionContext::FunctionContext(struct sqlite3_context* context, - int argc, - struct ::Mem** argv) - { - assert(context != NULL); - assert(argc >= 0); - assert(argv != NULL); - - context_ = context; - argc_ = static_cast<unsigned int>(argc); - argv_ = argv; - } - - void FunctionContext::CheckIndex(unsigned int index) const - { - if (index >= argc_) - { - throw OrthancSQLiteException("Parameter out of range"); - } - } - - ColumnType FunctionContext::GetColumnType(unsigned int index) const - { - CheckIndex(index); - return static_cast<SQLite::ColumnType>(sqlite3_value_type(argv_[index])); - } - - int FunctionContext::GetIntValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_int(argv_[index]); - } - - int64_t FunctionContext::GetInt64Value(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_int64(argv_[index]); - } - - double FunctionContext::GetDoubleValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_double(argv_[index]); - } - - std::string FunctionContext::GetStringValue(unsigned int index) const - { - CheckIndex(index); - return std::string(reinterpret_cast<const char*>(sqlite3_value_text(argv_[index]))); - } - - bool FunctionContext::IsNullValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_type(argv_[index]) == SQLITE_NULL; - } - - void FunctionContext::SetNullResult() - { - sqlite3_result_null(context_); - } - - void FunctionContext::SetIntResult(int value) - { - sqlite3_result_int(context_, value); - } - - void FunctionContext::SetDoubleResult(double value) - { - sqlite3_result_double(context_, value); - } - - void FunctionContext::SetStringResult(const std::string& str) - { - sqlite3_result_text(context_, str.data(), str.size(), SQLITE_TRANSIENT); - } - } -}
--- a/Orthanc/SQLite/FunctionContext.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "Statement.h" - -struct sqlite3_context; -struct Mem; // This corresponds to the opaque type "sqlite3_value" - -namespace Orthanc -{ - namespace SQLite - { - class FunctionContext : public NonCopyable - { - friend class Connection; - - private: - struct sqlite3_context* context_; - unsigned int argc_; - struct ::Mem** argv_; - - void CheckIndex(unsigned int index) const; - - public: - FunctionContext(struct sqlite3_context* context, - int argc, - struct ::Mem** argv); - - ColumnType GetColumnType(unsigned int index) const; - - unsigned int GetParameterCount() const - { - return argc_; - } - - int GetIntValue(unsigned int index) const; - - int64_t GetInt64Value(unsigned int index) const; - - double GetDoubleValue(unsigned int index) const; - - std::string GetStringValue(unsigned int index) const; - - bool IsNullValue(unsigned int index) const; - - void SetNullResult(); - - void SetIntResult(int value); - - void SetDoubleResult(double value); - - void SetStringResult(const std::string& str); - }; - } -}
--- a/Orthanc/SQLite/IScalarFunction.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "NonCopyable.h" -#include "FunctionContext.h" - -namespace Orthanc -{ - namespace SQLite - { - class IScalarFunction : public NonCopyable - { - public: - virtual ~IScalarFunction() - { - } - - virtual const char* GetName() const = 0; - - virtual unsigned int GetCardinality() const = 0; - - virtual void Compute(FunctionContext& context) = 0; - }; - } -}
--- a/Orthanc/SQLite/ITransaction.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "NonCopyable.h" - -namespace Orthanc -{ - namespace SQLite - { - class ITransaction : public NonCopyable - { - public: - virtual ~ITransaction() - { - } - - // Begins the transaction. This uses the default sqlite "deferred" transaction - // type, which means that the DB lock is lazily acquired the next time the - // database is accessed, not in the begin transaction command. - virtual void Begin() = 0; - - // Rolls back the transaction. This will happen automatically if you do - // nothing when the transaction goes out of scope. - virtual void Rollback() = 0; - - // Commits the transaction, returning true on success. - virtual void Commit() = 0; - }; - } -}
--- a/Orthanc/SQLite/NonCopyable.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -namespace Orthanc -{ - namespace SQLite - { - // This class mimics "boost::noncopyable" - class NonCopyable - { - private: - NonCopyable(const NonCopyable&); - - NonCopyable& operator= (const NonCopyable&); - - protected: - NonCopyable() - { - } - - ~NonCopyable() - { - } - }; - } -}
--- a/Orthanc/SQLite/OrthancSQLiteException.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - - -#if ORTHANC_SQLITE_STANDALONE == 1 -#include <stdexcept> - -namespace Orthanc -{ - namespace SQLite - { - class OrthancSQLiteException : public ::std::runtime_error - { - public: - OrthancSQLiteException(const std::string& what) : - ::std::runtime_error(what) - { - } - - OrthancSQLiteException(const char* what) : - ::std::runtime_error(what) - { - } - }; - } -} - -#else -# include "../OrthancException.h" -# define OrthancSQLiteException ::Orthanc::OrthancException -#endif
--- a/Orthanc/SQLite/README.txt Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -Introduction -============ - -The code in this folder is a standalone object-oriented wrapper around -SQLite3. It is derived from the code of Chromium: - -http://src.chromium.org/viewvc/chrome/trunk/src/sql/ -http://maxradi.us/documents/sqlite/ - - -Main differences with Chromium -============================== - -* The reference counting mechanism has been reimplemented to make it - simpler. -* The OrthancException class is used for the exception mechanisms. -* A statement is always valid (is_valid() always return true). -* The classes and the methods have been renamed to meet Orthanc's - coding conventions. - - -Reuse in another software -========================= - -To use the Orthanc SQLite wrapper in another project than Orthanc, you -just have to define the "ORTHANC_SQLITE_STANDALONE" macro. - -All the C++ exceptions generated by the wrapper will be objects of the -class "::Orthanc::SQLite::OrthancSQLiteException", that derives from -the standard exception class "::std::runtime_error". - - -Licensing -========= - -The code in this folder is licensed under the 3-clause BSD license, in -order to respect the original license of the code. - -It is pretty straightforward to extract the code from this folder and -to include it in another project.
--- a/Orthanc/SQLite/Statement.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Statement.h" -#include "Connection.h" - -#include <sqlite3.h> -#include <string.h> -#include <stdio.h> -#include <algorithm> - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include <glog/logging.h> -#endif - -#if defined(_MSC_VER) -#define snprintf _snprintf -#endif - -namespace Orthanc -{ - namespace SQLite - { - int Statement::CheckError(int err) const - { - bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE); - if (!succeeded) - { - char buffer[128]; - snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); - throw OrthancSQLiteException(buffer); - } - - return err; - } - - void Statement::CheckOk(int err) const - { - if (err == SQLITE_RANGE) - { - // Binding to a non-existent variable is evidence of a serious error. - throw OrthancSQLiteException("Bind value out of range"); - } - else if (err != SQLITE_OK) - { - char buffer[128]; - snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); - throw OrthancSQLiteException(buffer); - } - } - - - Statement::Statement(Connection& database, - const StatementId& id, - const std::string& sql) : - reference_(database.GetCachedStatement(id, sql.c_str())) - { - Reset(true); - } - - - Statement::Statement(Connection& database, - const StatementId& id, - const char* sql) : - reference_(database.GetCachedStatement(id, sql)) - { - Reset(true); - } - - - Statement::Statement(Connection& database, - const std::string& sql) : - reference_(database.GetWrappedObject(), sql.c_str()) - { - } - - - Statement::Statement(Connection& database, - const char* sql) : - reference_(database.GetWrappedObject(), sql) - { - } - - - bool Statement::Run() - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Statement::Run " << sqlite3_sql(GetStatement()); -#endif - - return CheckError(sqlite3_step(GetStatement())) == SQLITE_DONE; - } - - bool Statement::Step() - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Statement::Step " << sqlite3_sql(GetStatement()); -#endif - - return CheckError(sqlite3_step(GetStatement())) == SQLITE_ROW; - } - - void Statement::Reset(bool clear_bound_vars) - { - // We don't call CheckError() here because sqlite3_reset() returns - // the last error that Step() caused thereby generating a second - // spurious error callback. - if (clear_bound_vars) - sqlite3_clear_bindings(GetStatement()); - //VLOG(1) << "SQLite::Statement::Reset"; - sqlite3_reset(GetStatement()); - } - - std::string Statement::GetOriginalSQLStatement() - { - return std::string(sqlite3_sql(GetStatement())); - } - - - void Statement::BindNull(int col) - { - CheckOk(sqlite3_bind_null(GetStatement(), col + 1)); - } - - void Statement::BindBool(int col, bool val) - { - BindInt(col, val ? 1 : 0); - } - - void Statement::BindInt(int col, int val) - { - CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val)); - } - - void Statement::BindInt64(int col, int64_t val) - { - CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val)); - } - - void Statement::BindDouble(int col, double val) - { - CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val)); - } - - void Statement::BindCString(int col, const char* val) - { - CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT)); - } - - void Statement::BindString(int col, const std::string& val) - { - CheckOk(sqlite3_bind_text(GetStatement(), - col + 1, - val.data(), - val.size(), - SQLITE_TRANSIENT)); - } - - /*void Statement::BindString16(int col, const string16& value) - { - BindString(col, UTF16ToUTF8(value)); - }*/ - - void Statement::BindBlob(int col, const void* val, int val_len) - { - CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT)); - } - - - int Statement::ColumnCount() const - { - return sqlite3_column_count(GetStatement()); - } - - - ColumnType Statement::GetColumnType(int col) const - { - // Verify that our enum matches sqlite's values. - assert(COLUMN_TYPE_INTEGER == SQLITE_INTEGER); - assert(COLUMN_TYPE_FLOAT == SQLITE_FLOAT); - assert(COLUMN_TYPE_TEXT == SQLITE_TEXT); - assert(COLUMN_TYPE_BLOB == SQLITE_BLOB); - assert(COLUMN_TYPE_NULL == SQLITE_NULL); - - return static_cast<ColumnType>(sqlite3_column_type(GetStatement(), col)); - } - - ColumnType Statement::GetDeclaredColumnType(int col) const - { - std::string column_type(sqlite3_column_decltype(GetStatement(), col)); - std::transform(column_type.begin(), column_type.end(), column_type.begin(), tolower); - - if (column_type == "integer") - return COLUMN_TYPE_INTEGER; - else if (column_type == "float") - return COLUMN_TYPE_FLOAT; - else if (column_type == "text") - return COLUMN_TYPE_TEXT; - else if (column_type == "blob") - return COLUMN_TYPE_BLOB; - - return COLUMN_TYPE_NULL; - } - - bool Statement::ColumnIsNull(int col) const - { - return sqlite3_column_type(GetStatement(), col) == SQLITE_NULL; - } - - bool Statement::ColumnBool(int col) const - { - return !!ColumnInt(col); - } - - int Statement::ColumnInt(int col) const - { - return sqlite3_column_int(GetStatement(), col); - } - - int64_t Statement::ColumnInt64(int col) const - { - return sqlite3_column_int64(GetStatement(), col); - } - - double Statement::ColumnDouble(int col) const - { - return sqlite3_column_double(GetStatement(), col); - } - - std::string Statement::ColumnString(int col) const - { - const char* str = reinterpret_cast<const char*>( - sqlite3_column_text(GetStatement(), col)); - int len = sqlite3_column_bytes(GetStatement(), col); - - std::string result; - if (str && len > 0) - result.assign(str, len); - return result; - } - - /*string16 Statement::ColumnString16(int col) const - { - std::string s = ColumnString(col); - return !s.empty() ? UTF8ToUTF16(s) : string16(); - }*/ - - int Statement::ColumnByteLength(int col) const - { - return sqlite3_column_bytes(GetStatement(), col); - } - - const void* Statement::ColumnBlob(int col) const - { - return sqlite3_column_blob(GetStatement(), col); - } - - bool Statement::ColumnBlobAsString(int col, std::string* blob) - { - const void* p = ColumnBlob(col); - size_t len = ColumnByteLength(col); - blob->resize(len); - if (blob->size() != len) { - return false; - } - blob->assign(reinterpret_cast<const char*>(p), len); - return true; - } - - /*bool Statement::ColumnBlobAsString16(int col, string16* val) const - { - const void* data = ColumnBlob(col); - size_t len = ColumnByteLength(col) / sizeof(char16); - val->resize(len); - if (val->size() != len) - return false; - val->assign(reinterpret_cast<const char16*>(data), len); - return true; - }*/ - - /*bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const - { - val->clear(); - - const void* data = sqlite3_column_blob(GetStatement(), col); - int len = sqlite3_column_bytes(GetStatement(), col); - if (data && len > 0) { - val->resize(len); - memcpy(&(*val)[0], data, len); - } - return true; - }*/ - - /*bool Statement::ColumnBlobAsVector( - int col, - std::vector<unsigned char>* val) const - { - return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val)); - }*/ - - } -}
--- a/Orthanc/SQLite/Statement.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "NonCopyable.h" -#include "OrthancSQLiteException.h" -#include "StatementId.h" -#include "StatementReference.h" - -#include <vector> -#include <stdint.h> - -#if ORTHANC_BUILD_UNIT_TESTS == 1 -#include <gtest/gtest_prod.h> -#endif - -struct sqlite3_stmt; - - -namespace Orthanc -{ - namespace SQLite - { - class Connection; - - // Possible return values from ColumnType in a statement. These - // should match the values in sqlite3.h. - enum ColumnType - { - COLUMN_TYPE_INTEGER = 1, - COLUMN_TYPE_FLOAT = 2, - COLUMN_TYPE_TEXT = 3, - COLUMN_TYPE_BLOB = 4, - COLUMN_TYPE_NULL = 5 - }; - - class Statement : public NonCopyable - { - friend class Connection; - -#if ORTHANC_BUILD_UNIT_TESTS == 1 - FRIEND_TEST(SQLStatementTest, Run); - FRIEND_TEST(SQLStatementTest, Reset); -#endif - - private: - StatementReference reference_; - - int CheckError(int err) const; - - void CheckOk(int err) const; - - struct sqlite3_stmt* GetStatement() const - { - return reference_.GetWrappedObject(); - } - - public: - Statement(Connection& database, - const std::string& sql); - - Statement(Connection& database, - const StatementId& id, - const std::string& sql); - - Statement(Connection& database, - const char* sql); - - Statement(Connection& database, - const StatementId& id, - const char* sql); - - ~Statement() - { - Reset(); - } - - bool Run(); - - bool Step(); - - // Diagnostics -------------------------------------------------------------- - - std::string GetOriginalSQLStatement(); - - - // Binding ------------------------------------------------------------------- - - // These all take a 0-based argument index - void BindNull(int col); - void BindBool(int col, bool val); - void BindInt(int col, int val); - void BindInt64(int col, int64_t val); - void BindDouble(int col, double val); - void BindCString(int col, const char* val); - void BindString(int col, const std::string& val); - //void BindString16(int col, const string16& value); - void BindBlob(int col, const void* value, int value_len); - - - // Retrieving ---------------------------------------------------------------- - - // Returns the number of output columns in the result. - int ColumnCount() const; - - // Returns the type associated with the given column. - // - // Watch out: the type may be undefined if you've done something to cause a - // "type conversion." This means requesting the value of a column of a type - // where that type is not the native type. For safety, call ColumnType only - // on a column before getting the value out in any way. - ColumnType GetColumnType(int col) const; - ColumnType GetDeclaredColumnType(int col) const; - - // These all take a 0-based argument index. - bool ColumnIsNull(int col) const ; - bool ColumnBool(int col) const; - int ColumnInt(int col) const; - int64_t ColumnInt64(int col) const; - double ColumnDouble(int col) const; - std::string ColumnString(int col) const; - //string16 ColumnString16(int col) const; - - // When reading a blob, you can get a raw pointer to the underlying data, - // along with the length, or you can just ask us to copy the blob into a - // vector. Danger! ColumnBlob may return NULL if there is no data! - int ColumnByteLength(int col) const; - const void* ColumnBlob(int col) const; - bool ColumnBlobAsString(int col, std::string* blob); - //bool ColumnBlobAsString16(int col, string16* val) const; - //bool ColumnBlobAsVector(int col, std::vector<char>* val) const; - //bool ColumnBlobAsVector(int col, std::vector<unsigned char>* val) const; - - // Resets the statement to its initial condition. This includes any current - // result row, and also the bound variables if the |clear_bound_vars| is true. - void Reset(bool clear_bound_vars = true); - }; - } -}
--- a/Orthanc/SQLite/StatementId.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "StatementId.h" - -#include <string.h> - -namespace Orthanc -{ - namespace SQLite - { - bool StatementId::operator< (const StatementId& other) const - { - if (line_ != other.line_) - return line_ < other.line_; - - return strcmp(file_, other.file_) < 0; - } - } -}
--- a/Orthanc/SQLite/StatementId.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -namespace Orthanc -{ - namespace SQLite - { - class StatementId - { - private: - const char* file_; - int line_; - - StatementId(); // Forbidden - - public: - StatementId(const char* file, int line) : file_(file), line_(line) - { - } - - bool operator< (const StatementId& other) const; - }; - } -}
--- a/Orthanc/SQLite/StatementReference.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "StatementReference.h" -#include "OrthancSQLiteException.h" - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include <glog/logging.h> -#endif - -#include <string> -#include <cassert> -#include "sqlite3.h" - -namespace Orthanc -{ - namespace SQLite - { - bool StatementReference::IsRoot() const - { - return root_ == NULL; - } - - StatementReference::StatementReference() - { - root_ = NULL; - refCount_ = 0; - statement_ = NULL; - assert(IsRoot()); - } - - StatementReference::StatementReference(sqlite3* database, - const char* sql) - { - if (database == NULL || sql == NULL) - { - throw OrthancSQLiteException("Parameter out of range"); - } - - root_ = NULL; - refCount_ = 0; - - int error = sqlite3_prepare_v2(database, sql, -1, &statement_, NULL); - if (error != SQLITE_OK) - { - throw OrthancSQLiteException("SQLite: " + std::string(sqlite3_errmsg(database))); - } - - assert(IsRoot()); - } - - StatementReference::StatementReference(StatementReference& other) - { - refCount_ = 0; - - if (other.IsRoot()) - { - root_ = &other; - } - else - { - root_ = other.root_; - } - - root_->refCount_++; - statement_ = root_->statement_; - - assert(!IsRoot()); - } - - StatementReference::~StatementReference() - { - if (IsRoot()) - { - if (refCount_ != 0) - { - // There remain references to this object. We cannot throw - // an exception because: - // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html - -#if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "Bad value of the reference counter"; -#endif - } - else if (statement_ != NULL) - { - sqlite3_finalize(statement_); - } - } - else - { - if (root_->refCount_ == 0) - { - // There remain references to this object. We cannot throw - // an exception because: - // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html - -#if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "Bad value of the reference counter"; -#endif - } - else - { - root_->refCount_--; - } - } - } - - uint32_t StatementReference::GetReferenceCount() const - { - return refCount_; - } - } -}
--- a/Orthanc/SQLite/StatementReference.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "NonCopyable.h" - -#include <stdint.h> -#include <cassert> -#include <stdlib.h> - -struct sqlite3; -struct sqlite3_stmt; - -namespace Orthanc -{ - namespace SQLite - { - class StatementReference : NonCopyable - { - private: - StatementReference* root_; // Only used for non-root nodes - uint32_t refCount_; // Only used for root node - struct sqlite3_stmt* statement_; - - bool IsRoot() const; - - public: - StatementReference(); - - StatementReference(sqlite3* database, - const char* sql); - - StatementReference(StatementReference& other); - - ~StatementReference(); - - uint32_t GetReferenceCount() const; - - struct sqlite3_stmt* GetWrappedObject() const - { - assert(statement_ != NULL); - return statement_; - } - }; - } -}
--- a/Orthanc/SQLite/Transaction.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Transaction.h" -#include "OrthancSQLiteException.h" - -namespace Orthanc -{ - namespace SQLite - { - Transaction::Transaction(Connection& connection) : - connection_(connection), - isOpen_(false) - { - } - - Transaction::~Transaction() - { - if (isOpen_) - { - connection_.RollbackTransaction(); - } - } - - void Transaction::Begin() - { - if (isOpen_) - { - throw OrthancSQLiteException("SQLite: Beginning a transaction twice!"); - } - - isOpen_ = connection_.BeginTransaction(); - if (!isOpen_) - { - throw OrthancSQLiteException("SQLite: Unable to create a transaction"); - } - } - - void Transaction::Rollback() - { - if (!isOpen_) - { - throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. " - "Did you remember to call Begin()?"); - } - - isOpen_ = false; - - connection_.RollbackTransaction(); - } - - void Transaction::Commit() - { - if (!isOpen_) - { - throw OrthancSQLiteException("SQLite: Attempting to roll back a nonexistent transaction. " - "Did you remember to call Begin()?"); - } - - isOpen_ = false; - - if (!connection_.CommitTransaction()) - { - throw OrthancSQLiteException("SQLite: Failure when committing the transaction"); - } - } - } -}
--- a/Orthanc/SQLite/Transaction.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2015 Sebastien Jodogne <s.jodogne@gmail.com>, - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **/ - - -#pragma once - -#include "Connection.h" -#include "ITransaction.h" - -namespace Orthanc -{ - namespace SQLite - { - class Transaction : public ITransaction - { - private: - Connection& connection_; - - // True when the transaction is open, false when it's already been committed - // or rolled back. - bool isOpen_; - - public: - explicit Transaction(Connection& connection); - - virtual ~Transaction(); - - // Returns true when there is a transaction that has been successfully begun. - bool IsOpen() const { return isOpen_; } - - virtual void Begin(); - - virtual void Rollback(); - - virtual void Commit(); - }; - } -}
--- a/Orthanc/Toolbox.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1141 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h" -#include "Toolbox.h" - -#include "OrthancException.h" - -#include <string> -#include <stdint.h> -#include <string.h> -#include <boost/filesystem.hpp> -#include <boost/filesystem/fstream.hpp> -#include <boost/uuid/sha1.hpp> -#include <boost/lexical_cast.hpp> -#include <algorithm> -#include <ctype.h> - -#if BOOST_HAS_DATE_TIME == 1 -#include <boost/date_time/posix_time/posix_time.hpp> -#endif - -#if BOOST_HAS_REGEX == 1 -#include <boost/regex.hpp> -#endif - -#if HAVE_GOOGLE_LOG == 1 -#include <glog/logging.h> -#endif - -#if defined(_WIN32) -#include <windows.h> -#include <process.h> // For "_spawnvp()" -#else -#include <unistd.h> // For "execvp()" -#include <sys/wait.h> // For "waitpid()" -#endif - -#if defined(__APPLE__) && defined(__MACH__) -#include <mach-o/dyld.h> /* _NSGetExecutablePath */ -#include <limits.h> /* PATH_MAX */ -#endif - -#if defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) -#include <limits.h> /* PATH_MAX */ -#include <signal.h> -#include <unistd.h> -#endif - -#if BOOST_HAS_LOCALE != 1 -#error Since version 0.7.6, Orthanc entirely relies on boost::locale -#endif - -#include <boost/locale.hpp> - -#include "../Resources/ThirdParty/md5/md5.h" -#include "../Resources/ThirdParty/base64/base64.h" - - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -// Patch for the missing "_strtoll" symbol when compiling with Visual Studio < 2013 -extern "C" -{ - int64_t _strtoi64(const char *nptr, char **endptr, int base); - int64_t strtoll(const char *nptr, char **endptr, int base) - { - return _strtoi64(nptr, endptr, base); - } -} -#endif - - -#if ORTHANC_PUGIXML_ENABLED == 1 -#include "ChunkedBuffer.h" -#include <pugixml.hpp> -#endif - - -namespace Orthanc -{ - static bool finish; - -#if defined(_WIN32) - static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) - { - // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx - finish = true; - return true; - } -#else - static void SignalHandler(int) - { - finish = true; - } -#endif - - void Toolbox::USleep(uint64_t microSeconds) - { -#if defined(_WIN32) - ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000))); -#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) - usleep(microSeconds); -#else -#error Support your platform here -#endif - } - - - static void ServerBarrierInternal(const bool* stopFlag) - { -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, true); -#else - signal(SIGINT, SignalHandler); - signal(SIGQUIT, SignalHandler); - signal(SIGTERM, SignalHandler); -#endif - - // Active loop that awakens every 100ms - finish = false; - while (!(*stopFlag || finish)) - { - Toolbox::USleep(100 * 1000); - } - -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, false); -#else - signal(SIGINT, NULL); - signal(SIGQUIT, NULL); - signal(SIGTERM, NULL); -#endif - } - - - void Toolbox::ServerBarrier(const bool& stopFlag) - { - ServerBarrierInternal(&stopFlag); - } - - void Toolbox::ServerBarrier() - { - const bool stopFlag = false; - ServerBarrierInternal(&stopFlag); - } - - - void Toolbox::ToUpperCase(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), toupper); - } - - - void Toolbox::ToLowerCase(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), tolower); - } - - - void Toolbox::ToUpperCase(std::string& result, - const std::string& source) - { - result = source; - ToUpperCase(result); - } - - void Toolbox::ToLowerCase(std::string& result, - const std::string& source) - { - result = source; - ToLowerCase(result); - } - - - void Toolbox::ReadFile(std::string& content, - const std::string& path) - { - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - // http://www.cplusplus.com/reference/iostream/istream/tellg/ - f.seekg(0, std::ios::end); - std::streamsize size = f.tellg(); - f.seekg(0, std::ios::beg); - - content.resize(size); - if (size != 0) - { - f.read(reinterpret_cast<char*>(&content[0]), size); - } - - f.close(); - } - - - void Toolbox::WriteFile(const std::string& content, - const std::string& path) - { - boost::filesystem::ofstream f; - f.open(path, std::ofstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - if (content.size() != 0) - { - f.write(content.c_str(), content.size()); - } - - f.close(); - } - - - - void Toolbox::RemoveFile(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (boost::filesystem::is_regular_file(path)) - boost::filesystem::remove(path); - else - throw OrthancException("The path is not a regular file: " + path); - } - } - - - - void Toolbox::SplitUriComponents(UriComponents& components, - const std::string& uri) - { - static const char URI_SEPARATOR = '/'; - - components.clear(); - - if (uri.size() == 0 || - uri[0] != URI_SEPARATOR) - { - throw OrthancException(ErrorCode_UriSyntax); - } - - // Count the number of slashes in the URI to make an assumption - // about the number of components in the URI - unsigned int estimatedSize = 0; - for (unsigned int i = 0; i < uri.size(); i++) - { - if (uri[i] == URI_SEPARATOR) - estimatedSize++; - } - - components.reserve(estimatedSize - 1); - - unsigned int start = 1; - unsigned int end = 1; - while (end < uri.size()) - { - // This is the loop invariant - assert(uri[start - 1] == '/' && (end >= start)); - - if (uri[end] == '/') - { - components.push_back(std::string(&uri[start], end - start)); - end++; - start = end; - } - else - { - end++; - } - } - - if (start < uri.size()) - { - components.push_back(std::string(&uri[start], end - start)); - } - - for (size_t i = 0; i < components.size(); i++) - { - if (components[i].size() == 0) - { - // Empty component, as in: "/coucou//e" - throw OrthancException(ErrorCode_UriSyntax); - } - } - } - - - void Toolbox::TruncateUri(UriComponents& target, - const UriComponents& source, - size_t fromLevel) - { - target.clear(); - - if (source.size() > fromLevel) - { - target.resize(source.size() - fromLevel); - - size_t j = 0; - for (size_t i = fromLevel; i < source.size(); i++, j++) - { - target[j] = source[i]; - } - - assert(j == target.size()); - } - } - - - - bool Toolbox::IsChildUri(const UriComponents& baseUri, - const UriComponents& testedUri) - { - if (testedUri.size() < baseUri.size()) - { - return false; - } - - for (size_t i = 0; i < baseUri.size(); i++) - { - if (baseUri[i] != testedUri[i]) - return false; - } - - return true; - } - - - std::string Toolbox::AutodetectMimeType(const std::string& path) - { - std::string contentType; - size_t lastDot = path.rfind('.'); - size_t lastSlash = path.rfind('/'); - - if (lastDot == std::string::npos || - (lastSlash != std::string::npos && lastDot < lastSlash)) - { - // No trailing dot, unable to detect the content type - } - else - { - const char* extension = &path[lastDot + 1]; - - // http://en.wikipedia.org/wiki/Mime_types - // Text types - if (!strcmp(extension, "txt")) - contentType = "text/plain"; - else if (!strcmp(extension, "html")) - contentType = "text/html"; - else if (!strcmp(extension, "xml")) - contentType = "text/xml"; - else if (!strcmp(extension, "css")) - contentType = "text/css"; - - // Application types - else if (!strcmp(extension, "js")) - contentType = "application/javascript"; - else if (!strcmp(extension, "json")) - contentType = "application/json"; - else if (!strcmp(extension, "pdf")) - contentType = "application/pdf"; - - // Images types - else if (!strcmp(extension, "jpg") || !strcmp(extension, "jpeg")) - contentType = "image/jpeg"; - else if (!strcmp(extension, "gif")) - contentType = "image/gif"; - else if (!strcmp(extension, "png")) - contentType = "image/png"; - } - - return contentType; - } - - - std::string Toolbox::FlattenUri(const UriComponents& components, - size_t fromLevel) - { - if (components.size() <= fromLevel) - { - return "/"; - } - else - { - std::string r; - - for (size_t i = fromLevel; i < components.size(); i++) - { - r += "/" + components[i]; - } - - return r; - } - } - - - - uint64_t Toolbox::GetFileSize(const std::string& path) - { - try - { - return static_cast<uint64_t>(boost::filesystem::file_size(path)); - } - catch (boost::filesystem::filesystem_error) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } - - - static char GetHexadecimalCharacter(uint8_t value) - { - assert(value < 16); - - if (value < 10) - return value + '0'; - else - return (value - 10) + 'a'; - } - - - void Toolbox::ComputeMD5(std::string& result, - const std::string& data) - { - if (data.size() > 0) - { - ComputeMD5(result, &data[0], data.size()); - } - else - { - ComputeMD5(result, NULL, 0); - } - } - - - void Toolbox::ComputeMD5(std::string& result, - const void* data, - size_t length) - { - md5_state_s state; - md5_init(&state); - - if (length > 0) - { - md5_append(&state, - reinterpret_cast<const md5_byte_t*>(data), - static_cast<int>(length)); - } - - md5_byte_t actualHash[16]; - md5_finish(&state, actualHash); - - result.resize(32); - for (unsigned int i = 0; i < 16; i++) - { - result[2 * i] = GetHexadecimalCharacter(actualHash[i] / 16); - result[2 * i + 1] = GetHexadecimalCharacter(actualHash[i] % 16); - } - } - - - void Toolbox::EncodeBase64(std::string& result, - const std::string& data) - { - result = base64_encode(data); - } - - void Toolbox::DecodeBase64(std::string& result, - const std::string& data) - { - result = base64_decode(data); - } - - -#if defined(_WIN32) - static std::string GetPathToExecutableInternal() - { - // Yes, this is ugly, but there is no simple way to get the - // required buffer size, so we use a big constant - std::vector<char> buffer(32768); - /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1)); - return std::string(&buffer[0]); - } - -#elif defined(__linux) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) - static std::string GetPathToExecutableInternal() - { - std::vector<char> buffer(PATH_MAX + 1); - ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); - if (bytes == 0) - { - throw OrthancException("Unable to get the path to the executable"); - } - - return std::string(&buffer[0]); - } - -#elif defined(__APPLE__) && defined(__MACH__) - static std::string GetPathToExecutableInternal() - { - char pathbuf[PATH_MAX + 1]; - unsigned int bufsize = static_cast<int>(sizeof(pathbuf)); - - _NSGetExecutablePath( pathbuf, &bufsize); - - return std::string(pathbuf); - } - -#else -#error Support your platform here -#endif - - - std::string Toolbox::GetPathToExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p).string(); - } - - - std::string Toolbox::GetDirectoryOfExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p.parent_path()).string(); - } - - - std::string Toolbox::ConvertToUtf8(const std::string& source, - const Encoding sourceEncoding) - { - const char* encoding; - - - // http://bradleyross.users.sourceforge.net/docs/dicom/doc/src-html/org/dcm4che2/data/SpecificCharacterSet.html - switch (sourceEncoding) - { - case Encoding_Utf8: - // Already in UTF-8: No conversion is required - return source; - - case Encoding_Ascii: - return ConvertToAscii(source); - - case Encoding_Latin1: - encoding = "ISO-8859-1"; - break; - - case Encoding_Latin2: - encoding = "ISO-8859-2"; - break; - - case Encoding_Latin3: - encoding = "ISO-8859-3"; - break; - - case Encoding_Latin4: - encoding = "ISO-8859-4"; - break; - - case Encoding_Latin5: - encoding = "ISO-8859-9"; - break; - - case Encoding_Cyrillic: - encoding = "ISO-8859-5"; - break; - - case Encoding_Windows1251: - encoding = "WINDOWS-1251"; - break; - - case Encoding_Arabic: - encoding = "ISO-8859-6"; - break; - - case Encoding_Greek: - encoding = "ISO-8859-7"; - break; - - case Encoding_Hebrew: - encoding = "ISO-8859-8"; - break; - - case Encoding_Japanese: - encoding = "SHIFT-JIS"; - break; - - case Encoding_Chinese: - encoding = "GB18030"; - break; - - case Encoding_Thai: - encoding = "TIS620.2533-0"; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - try - { - return boost::locale::conv::to_utf<char>(source, encoding); - } - catch (std::runtime_error&) - { - // Bad input string or bad encoding - return ConvertToAscii(source); - } - } - - - std::string Toolbox::ConvertToAscii(const std::string& source) - { - std::string result; - - result.reserve(source.size() + 1); - for (size_t i = 0; i < source.size(); i++) - { - if (source[i] <= 127 && source[i] >= 0 && !iscntrl(source[i])) - { - result.push_back(source[i]); - } - } - - return result; - } - - void Toolbox::ComputeSHA1(std::string& result, - const std::string& data) - { - boost::uuids::detail::sha1 sha1; - - if (data.size() > 0) - { - sha1.process_bytes(&data[0], data.size()); - } - - unsigned int digest[5]; - - // Sanity check for the memory layout: A SHA-1 digest is 160 bits wide - assert(sizeof(unsigned int) == 4 && sizeof(digest) == (160 / 8)); - - sha1.get_digest(digest); - - result.resize(8 * 5 + 4); - sprintf(&result[0], "%08x-%08x-%08x-%08x-%08x", - digest[0], - digest[1], - digest[2], - digest[3], - digest[4]); - } - - bool Toolbox::IsSHA1(const std::string& str) - { - if (str.size() != 44) - { - return false; - } - - for (unsigned int i = 0; i < 44; i++) - { - if (i == 8 || - i == 17 || - i == 26 || - i == 35) - { - if (str[i] != '-') - return false; - } - else - { - if (!isalnum(str[i])) - return false; - } - } - - return true; - } - - -#if BOOST_HAS_DATE_TIME == 1 - std::string Toolbox::GetNowIsoString() - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - return boost::posix_time::to_iso_string(now); - } -#endif - - - std::string Toolbox::StripSpaces(const std::string& source) - { - size_t first = 0; - - while (first < source.length() && - isspace(source[first])) - { - first++; - } - - if (first == source.length()) - { - // String containing only spaces - return ""; - } - - size_t last = source.length(); - while (last > first && - isspace(source[last - 1])) - { - last--; - } - - assert(first <= last); - return source.substr(first, last - first); - } - - - static char Hex2Dec(char c) - { - return ((c >= '0' && c <= '9') ? c - '0' : - ((c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - 'A' + 10)); - } - - void Toolbox::UrlDecode(std::string& s) - { - // http://en.wikipedia.org/wiki/Percent-encoding - // http://www.w3schools.com/tags/ref_urlencode.asp - // http://stackoverflow.com/questions/154536/encode-decode-urls-in-c - - if (s.size() == 0) - { - return; - } - - size_t source = 0; - size_t target = 0; - - while (source < s.size()) - { - if (s[source] == '%' && - source + 2 < s.size() && - isalnum(s[source + 1]) && - isalnum(s[source + 2])) - { - s[target] = (Hex2Dec(s[source + 1]) << 4) | Hex2Dec(s[source + 2]); - source += 3; - target += 1; - } - else - { - if (s[source] == '+') - s[target] = ' '; - else - s[target] = s[source]; - - source++; - target++; - } - } - - s.resize(target); - } - - - Endianness Toolbox::DetectEndianness() - { - // http://sourceforge.net/p/predef/wiki/Endianness/ - - uint8_t buffer[4]; - - buffer[0] = 0x00; - buffer[1] = 0x01; - buffer[2] = 0x02; - buffer[3] = 0x03; - - switch (*((uint32_t *)buffer)) - { - case 0x00010203: - return Endianness_Big; - - case 0x03020100: - return Endianness_Little; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - -#if BOOST_HAS_REGEX == 1 - std::string Toolbox::WildcardToRegularExpression(const std::string& source) - { - // TODO - Speed up this with a regular expression - - std::string result = source; - - // Escape all special characters - boost::replace_all(result, "\\", "\\\\"); - boost::replace_all(result, "^", "\\^"); - boost::replace_all(result, ".", "\\."); - boost::replace_all(result, "$", "\\$"); - boost::replace_all(result, "|", "\\|"); - boost::replace_all(result, "(", "\\("); - boost::replace_all(result, ")", "\\)"); - boost::replace_all(result, "[", "\\["); - boost::replace_all(result, "]", "\\]"); - boost::replace_all(result, "+", "\\+"); - boost::replace_all(result, "/", "\\/"); - boost::replace_all(result, "{", "\\{"); - boost::replace_all(result, "}", "\\}"); - - // Convert wildcards '*' and '?' to their regex equivalents - boost::replace_all(result, "?", "."); - boost::replace_all(result, "*", ".*"); - - return result; - } -#endif - - - - void Toolbox::TokenizeString(std::vector<std::string>& result, - const std::string& value, - char separator) - { - result.clear(); - - std::string currentItem; - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == separator) - { - result.push_back(currentItem); - currentItem.clear(); - } - else - { - currentItem.push_back(value[i]); - } - } - - result.push_back(currentItem); - } - - -#if BOOST_HAS_REGEX == 1 - void Toolbox::DecodeDataUriScheme(std::string& mime, - std::string& content, - const std::string& source) - { - boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)", - boost::regex::icase /* case insensitive search */); - - boost::cmatch what; - if (regex_match(source.c_str(), what, pattern)) - { - mime = what[1]; - content = what[2]; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } -#endif - - - void Toolbox::MakeDirectory(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (!boost::filesystem::is_directory(path)) - { - throw OrthancException("Cannot create the directory over an existing file: " + path); - } - } - else - { - if (!boost::filesystem::create_directories(path)) - { - throw OrthancException("Unable to create the directory: " + path); - } - } - } - - - bool Toolbox::IsExistingFile(const std::string& path) - { - return boost::filesystem::exists(path); - } - - -#if ORTHANC_PUGIXML_ENABLED == 1 - class ChunkedBufferWriter : public pugi::xml_writer - { - private: - ChunkedBuffer buffer_; - - public: - virtual void write(const void *data, size_t size) - { - if (size > 0) - { - buffer_.AddChunk(reinterpret_cast<const char*>(data), size); - } - } - - void Flatten(std::string& s) - { - buffer_.Flatten(s); - } - }; - - - static void JsonToXmlInternal(pugi::xml_node& target, - const Json::Value& source, - const std::string& arrayElement) - { - // http://jsoncpp.sourceforge.net/value_8h_source.html#l00030 - - switch (source.type()) - { - case Json::nullValue: - { - target.append_child(pugi::node_pcdata).set_value("null"); - break; - } - - case Json::intValue: - { - std::string s = boost::lexical_cast<std::string>(source.asInt()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::uintValue: - { - std::string s = boost::lexical_cast<std::string>(source.asUInt()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::realValue: - { - std::string s = boost::lexical_cast<std::string>(source.asFloat()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::stringValue: - { - target.append_child(pugi::node_pcdata).set_value(source.asString().c_str()); - break; - } - - case Json::booleanValue: - { - target.append_child(pugi::node_pcdata).set_value(source.asBool() ? "true" : "false"); - break; - } - - case Json::arrayValue: - { - for (Json::Value::ArrayIndex i = 0; i < source.size(); i++) - { - pugi::xml_node node = target.append_child(); - node.set_name(arrayElement.c_str()); - JsonToXmlInternal(node, source[i], arrayElement); - } - break; - } - - case Json::objectValue: - { - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - pugi::xml_node node = target.append_child(); - node.set_name(members[i].c_str()); - JsonToXmlInternal(node, source[members[i]], arrayElement); - } - - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void Toolbox::JsonToXml(std::string& target, - const Json::Value& source, - const std::string& rootElement, - const std::string& arrayElement) - { - pugi::xml_document doc; - - pugi::xml_node n = doc.append_child(rootElement.c_str()); - JsonToXmlInternal(n, source, arrayElement); - - pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); - decl.append_attribute("version").set_value("1.0"); - decl.append_attribute("encoding").set_value("utf-8"); - - ChunkedBufferWriter writer; - doc.save(writer, " ", pugi::format_default, pugi::encoding_utf8); - writer.Flatten(target); - } - -#endif - - - void Toolbox::ExecuteSystemCommand(const std::string& command, - const std::vector<std::string>& arguments) - { - // Convert the arguments as a C array - std::vector<char*> args(arguments.size() + 2); - - args.front() = const_cast<char*>(command.c_str()); - - for (size_t i = 0; i < arguments.size(); i++) - { - args[i + 1] = const_cast<char*>(arguments[i].c_str()); - } - - args.back() = NULL; - - int status; - -#if defined(_WIN32) - // http://msdn.microsoft.com/en-us/library/275khfab.aspx - status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); - -#else - int pid = fork(); - - if (pid == -1) - { - // Error in fork() -#if HAVE_GOOGLE_LOG == 1 - LOG(ERROR) << "Cannot fork a child process"; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - else if (pid == 0) - { - // Execute the system command in the child process - execvp(command.c_str(), &args[0]); - - // We should never get here - _exit(1); - } - else - { - // Wait for the system command to exit - waitpid(pid, &status, 0); - } -#endif - - if (status != 0) - { -#if HAVE_GOOGLE_LOG == 1 - LOG(ERROR) << "System command failed with status code " << status; -#endif - - throw OrthancException(ErrorCode_SystemCommand); - } - } - - - bool Toolbox::IsInteger(const std::string& str) - { - std::string s = StripSpaces(str); - - if (s.size() == 0) - { - return false; - } - - size_t pos = 0; - if (s[0] == '-') - { - if (s.size() == 1) - { - return false; - } - - pos = 1; - } - - while (pos < s.size()) - { - if (!isdigit(s[pos])) - { - return false; - } - - pos++; - } - - return true; - } -} -
--- a/Orthanc/Toolbox.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "Enumerations.h" - -#include <stdint.h> -#include <vector> -#include <string> - -#if ORTHANC_PUGIXML_ENABLED == 1 -#include <json/json.h> -#endif - -namespace Orthanc -{ - typedef std::vector<std::string> UriComponents; - - class NullType - { - }; - - namespace Toolbox - { - void ServerBarrier(const bool& stopFlag); - - void ServerBarrier(); - - void ToUpperCase(std::string& s); // Inplace version - - void ToLowerCase(std::string& s); // Inplace version - - void ToUpperCase(std::string& result, - const std::string& source); - - void ToLowerCase(std::string& result, - const std::string& source); - - void ReadFile(std::string& content, - const std::string& path); - - void WriteFile(const std::string& content, - const std::string& path); - - void USleep(uint64_t microSeconds); - - void RemoveFile(const std::string& path); - - void SplitUriComponents(UriComponents& components, - const std::string& uri); - - void TruncateUri(UriComponents& target, - const UriComponents& source, - size_t fromLevel); - - bool IsChildUri(const UriComponents& baseUri, - const UriComponents& testedUri); - - std::string AutodetectMimeType(const std::string& path); - - std::string FlattenUri(const UriComponents& components, - size_t fromLevel = 0); - - uint64_t GetFileSize(const std::string& path); - - void ComputeMD5(std::string& result, - const std::string& data); - - void ComputeMD5(std::string& result, - const void* data, - size_t length); - - void ComputeSHA1(std::string& result, - const std::string& data); - - bool IsSHA1(const std::string& str); - - void DecodeBase64(std::string& result, - const std::string& data); - - void EncodeBase64(std::string& result, - const std::string& data); - - std::string GetPathToExecutable(); - - std::string GetDirectoryOfExecutable(); - - std::string ConvertToUtf8(const std::string& source, - const Encoding sourceEncoding); - - std::string ConvertToAscii(const std::string& source); - - std::string StripSpaces(const std::string& source); - -#if BOOST_HAS_DATE_TIME == 1 - std::string GetNowIsoString(); -#endif - - // In-place percent-decoding for URL - void UrlDecode(std::string& s); - - Endianness DetectEndianness(); - -#if BOOST_HAS_REGEX == 1 - std::string WildcardToRegularExpression(const std::string& s); -#endif - - void TokenizeString(std::vector<std::string>& result, - const std::string& source, - char separator); - -#if BOOST_HAS_REGEX == 1 - void DecodeDataUriScheme(std::string& mime, - std::string& content, - const std::string& source); -#endif - - void MakeDirectory(const std::string& path); - - bool IsExistingFile(const std::string& path); - -#if ORTHANC_PUGIXML_ENABLED == 1 - void JsonToXml(std::string& target, - const Json::Value& source, - const std::string& rootElement = "root", - const std::string& arrayElement = "item"); -#endif - - void ExecuteSystemCommand(const std::string& command, - const std::vector<std::string>& arguments); - - bool IsInteger(const std::string& str); - } -}
--- a/Orthanc/Uuid.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "PrecompiledHeaders.h" -#include "Uuid.h" - -// http://stackoverflow.com/a/1626302 - -extern "C" -{ -#ifdef WIN32 -#include <rpc.h> -#else -#include <uuid/uuid.h> -#endif -} - -#include <boost/filesystem.hpp> - -namespace Orthanc -{ - namespace Toolbox - { - std::string GenerateUuid() - { -#ifdef WIN32 - UUID uuid; - UuidCreate ( &uuid ); - - unsigned char * str; - UuidToStringA ( &uuid, &str ); - - std::string s( ( char* ) str ); - - RpcStringFreeA ( &str ); -#else - uuid_t uuid; - uuid_generate_random ( uuid ); - char s[37]; - uuid_unparse ( uuid, s ); -#endif - return s; - } - - - bool IsUuid(const std::string& str) - { - if (str.size() != 36) - { - return false; - } - - for (size_t i = 0; i < str.length(); i++) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - if (str[i] != '-') - return false; - } - else - { - if (!isalnum(str[i])) - return false; - } - } - - return true; - } - - - bool StartsWithUuid(const std::string& str) - { - if (str.size() < 36) - { - return false; - } - - if (str.size() == 36) - { - return IsUuid(str); - } - - assert(str.size() > 36); - if (!isspace(str[36])) - { - return false; - } - - return IsUuid(str.substr(0, 36)); - } - - - static std::string CreateTemporaryPath(const char* extension) - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path(); -#elif defined(__linux__) - boost::filesystem::path tmpDir("/tmp"); -#else -#error Support your platform here -#endif - - // We use UUID to create unique path to temporary files - std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid(); - - if (extension != NULL) - { - filename.append(extension); - } - - tmpDir /= filename; - return tmpDir.string(); - } - - - TemporaryFile::TemporaryFile() : - path_(CreateTemporaryPath(NULL)) - { - } - - - TemporaryFile::TemporaryFile(const char* extension) : - path_(CreateTemporaryPath(extension)) - { - } - - - TemporaryFile::~TemporaryFile() - { - boost::filesystem::remove(path_); - } - } -}
--- a/Orthanc/Uuid.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include <string> - -/** - * GUID vs. UUID - * The simple answer is: no difference, they are the same thing. Treat - * them as a 16 byte (128 bits) value that is used as a unique - * value. In Microsoft-speak they are called GUIDs, but call them - * UUIDs when not using Microsoft-speak. - * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid - **/ - -#include "Toolbox.h" - -namespace Orthanc -{ - namespace Toolbox - { - std::string GenerateUuid(); - - bool IsUuid(const std::string& str); - - bool StartsWithUuid(const std::string& str); - - class TemporaryFile - { - private: - std::string path_; - - public: - TemporaryFile(); - - TemporaryFile(const char* extension); - - ~TemporaryFile(); - - const std::string& GetPath() const - { - return path_; - } - - void Write(const std::string& content) - { - Toolbox::WriteFile(content, path_); - } - - void Read(std::string& content) const - { - Toolbox::ReadFile(content, path_); - } - }; - } -}
--- a/Resources/CMake/AutoGeneratedCode.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED") -set(AUTOGENERATED_SOURCES) - -file(MAKE_DIRECTORY ${AUTOGENERATED_DIR}) -include_directories(${AUTOGENERATED_DIR}) - -macro(EmbedResources) - # Convert a semicolon separated list to a whitespace separated string - set(SCRIPT_ARGUMENTS) - set(DEPENDENCIES) - set(IS_PATH_NAME false) - foreach(arg ${ARGN}) - if (${IS_PATH_NAME}) - list(APPEND SCRIPT_ARGUMENTS "${arg}") - list(APPEND DEPENDENCIES "${arg}") - set(IS_PATH_NAME false) - else() - list(APPEND SCRIPT_ARGUMENTS "${arg}") - set(IS_PATH_NAME true) - endif() - endforeach() - - set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources") - add_custom_command( - OUTPUT - "${TARGET_BASE}.h" - "${TARGET_BASE}.cpp" - COMMAND - ${PYTHON_EXECUTABLE} - "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py" - "${AUTOGENERATED_DIR}/EmbeddedResources" - ${SCRIPT_ARGUMENTS} - DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/Resources/EmbedResources.py" - ${DEPENDENCIES} - ) - - list(APPEND AUTOGENERATED_SOURCES - "${AUTOGENERATED_DIR}/EmbeddedResources.cpp" - ) -endmacro()
--- a/Resources/CMake/BoostConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -if (STATIC_BUILD OR NOT USE_SYSTEM_BOOST) - set(BOOST_STATIC 1) -else() - include(FindBoost) - set(BOOST_STATIC 0) - find_package(Boost COMPONENTS system thread filesystem locale) - - if (NOT Boost_FOUND) - message(FATAL_ERROR "Unable to locate Boost on this system") - endif() - - include_directories(${Boost_INCLUDE_DIRS}) - link_libraries(${Boost_LIBRARIES}) -endif() - - -if (BOOST_STATIC) - # Parameters for Boost 1.55.0 - set(BOOST_NAME boost_1_55_0) - set(BOOST_BCP_SUFFIX bcpdigest-0.7.4) - set(BOOST_MD5 "409f7a0e4fb1f5659d07114f3133b67b") - set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src") - - set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) - DownloadPackage( - "${BOOST_MD5}" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz" - "${BOOST_SOURCES_DIR}" - ) - - add_definitions( - # Static build of Boost - -DBOOST_ALL_NO_LIB - -DBOOST_ALL_NOLIB - -DBOOST_DATE_TIME_NO_LIB - -DBOOST_THREAD_BUILD_LIB - -DBOOST_PROGRAM_OPTIONS_NO_LIB - -DBOOST_REGEX_NO_LIB - -DBOOST_SYSTEM_NO_LIB - -DBOOST_LOCALE_NO_LIB - ) - - if (${CMAKE_COMPILER_IS_GNUCXX}) - add_definitions(-isystem ${BOOST_SOURCES_DIR}) - endif() - - include_directories( - ${BOOST_SOURCES_DIR} - ) - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp - ) - - - ## Boost::thread - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp - ) - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - add_definitions(-DBOOST_HAS_SCHED_YIELD=1) - endif() - - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/thread.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_pe.cpp - ) - endif() - - - ## Boost::filesystem - - list(APPEND BOOST_SOURCES - ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp - ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp - ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp - ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp - ) - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp - ) - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(APPEND BOOST_SOURCES - ${BOOST_FILESYSTEM_SOURCES_DIR}/windows_file_codecvt.cpp - ) - endif() - - - source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*) -endif() - - -add_definitions( - -DBOOST_HAS_FILESYSTEM_V3=1 - -DBOOST_HAS_LOCALE=1 - -DBOOST_HAS_DATE_TIME=0 - -DBOOST_HAS_REGEX=0 - )
--- a/Resources/CMake/Compiler.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -# Force static build when cross-compiling -if (CMAKE_CROSSCOMPILING) - SET(STATIC_BUILD ON) - SET(STANDALONE_BUILD ON) -endif() - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - SET(OS_LIBRARIES uuid rt dl) - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread") -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - SET(OS_LIBRARIES rpcrt4 ws2_32 secur32) - if (CMAKE_COMPILER_IS_GNUCXX) - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++") - - # This line is necessary to compile with recent versions of MinGW, - # otherwise "libwinpthread-1.dll" is not statically linked. - SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic") - endif() -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - SET(OS_LIBRARIES uuid) - link_directories("/usr/local/lib") - # This line helps CHECK_INCLUDE_FILE_CXX macro to find files - SET(CMAKE_REQUIRED_INCLUDES "/usr/local/include") -endif () - -if (CMAKE_COMPILER_IS_GNUCXX) - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/Resources/VersionScript.map -Wl,--no-undefined") -endif() - -if (MSVC) - # Use static runtime under Visual Studio - # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace - # http://stackoverflow.com/a/6510446 - foreach(flag_var - CMAKE_C_FLAGS_DEBUG - CMAKE_CXX_FLAGS_DEBUG - CMAKE_C_FLAGS_RELEASE - CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL - CMAKE_CXX_FLAGS_MINSIZEREL - CMAKE_C_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_RELWITHDEBINFO) - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") - endforeach(flag_var) - - add_definitions( - -D_CRT_SECURE_NO_WARNINGS=1 - -D_CRT_NONSTDC_NO_DEPRECATE=1 - ) -endif()
--- a/Resources/CMake/DownloadPackage.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -macro(GetUrlFilename TargetVariable Url) - string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}") -endmacro() - - -macro(GetUrlExtension TargetVariable Url) - #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}") - string(REGEX REPLACE "^.*\\." "" TMP "${Url}") - string(TOLOWER "${TMP}" "${TargetVariable}") -endmacro() - - -## -## Check the existence of the required decompression tools -## - -if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - find_program(ZIP_EXECUTABLE 7z - PATHS - "$ENV{ProgramFiles}/7-Zip" - "$ENV{ProgramW6432}/7-Zip" - ) - - if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") - endif() - -else() - find_program(UNZIP_EXECUTABLE unzip) - if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'unzip' package") - endif() - - find_program(TAR_EXECUTABLE tar) - if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'tar' package") - endif() -endif() - - -macro(DownloadPackage MD5 Url TargetDirectory) - if (NOT IS_DIRECTORY "${TargetDirectory}") - GetUrlFilename(TMP_FILENAME "${Url}") - - set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}") - if (NOT EXISTS "${TMP_PATH}") - message("Downloading ${Url}") - - # This fixes issue 6: "I think cmake shouldn't download the - # packages which are not in the system, it should stop and let - # user know." - # https://code.google.com/p/orthanc/issues/detail?id=6 - if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) - message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") - endif() - - file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}") - else() - message("Using local copy of ${Url}") - endif() - - GetUrlExtension(TMP_EXTENSION "${Url}") - #message(${TMP_EXTENSION}) - message("Uncompressing ${TMP_FILENAME}") - - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - # How to silently extract files using 7-zip - # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly - - if (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) - execute_process( - COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if ("${TMP_EXTENSION}" STREQUAL "tgz") - string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}") - else() - string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") - endif() - - execute_process( - COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - elseif ("${TMP_EXTENSION}" STREQUAL "zip") - execute_process( - COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - else() - message(FATAL_ERROR "Support your platform here") - endif() - - else() - if ("${TMP_EXTENSION}" STREQUAL "zip") - execute_process( - COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) - #message("tar xvfz ${TMP_PATH}") - execute_process( - COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - elseif ("${TMP_EXTENSION}" STREQUAL "bz2") - execute_process( - COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - else() - message(FATAL_ERROR "Unknown package format.") - endif() - endif() - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if (NOT IS_DIRECTORY "${TargetDirectory}") - message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.") - endif() - endif() -endmacro()
--- a/Resources/CMake/GoogleTestConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -if (USE_GTEST_DEBIAN_SOURCE_PACKAGE) - set(GTEST_SOURCES /usr/src/gtest/src/gtest-all.cc) - include_directories(/usr/src/gtest) - - if (NOT EXISTS /usr/include/gtest/gtest.h OR - NOT EXISTS ${GTEST_SOURCES}) - message(FATAL_ERROR "Please install the libgtest-dev package") - endif() - -elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST) - set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0) - DownloadPackage( - "2d6ec8ccdf5c46b05ba54a9fd1d130d7" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/gtest-1.7.0.zip" - "${GTEST_SOURCES_DIR}") - - include_directories( - ${GTEST_SOURCES_DIR}/include - ${GTEST_SOURCES_DIR} - ) - - set(GTEST_SOURCES - ${GTEST_SOURCES_DIR}/src/gtest-all.cc - ) - - # https://code.google.com/p/googletest/issues/detail?id=412 - if (MSVC) # VS2012 does not support tuples correctly yet - add_definitions(/D _VARIADIC_MAX=10) - endif() - -else() - include(FindGTest) - if (NOT GTEST_FOUND) - message(FATAL_ERROR "Unable to find GoogleTest") - endif() - - include_directories(${GTEST_INCLUDE_DIRS}) - link_libraries(${GTEST_LIBRARIES}) -endif()
--- a/Resources/CMake/JsonCppConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP) - set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-src-0.6.0-rc2) - DownloadPackage( - "363e2f4cbd3aeb63bf4e571f377400fb" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jsoncpp-src-0.6.0-rc2.tar.gz" - "${JSONCPP_SOURCES_DIR}") - - list(APPEND JSONCPP_SOURCES - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_reader.cpp - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_value.cpp - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_writer.cpp - ) - - include_directories( - ${JSONCPP_SOURCES_DIR}/include - ) - - source_group(ThirdParty\\JsonCpp REGULAR_EXPRESSION ${JSONCPP_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE_CXX(jsoncpp/json/reader.h HAVE_JSONCPP_H) - if (NOT HAVE_JSONCPP_H) - message(FATAL_ERROR "Please install the libjsoncpp-dev package") - endif() - - find_path(JSONCPP_INCLUDE_DIR json/reader.h - /usr/include/jsoncpp - /usr/local/include/jsoncpp - ) - - message("JsonCpp include dir: ${JSONCPP_INCLUDE_DIR}") - include_directories(${JSONCPP_INCLUDE_DIR}) - link_libraries(jsoncpp) - -endif()
--- a/Resources/CMake/LibPngConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG) - SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.5.12) - DownloadPackage( - "8ea7f60347a306c5faf70b977fa80e28" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libpng-1.5.12.tar.gz" - "${LIBPNG_SOURCES_DIR}") - - include_directories( - ${LIBPNG_SOURCES_DIR} - ) - - configure_file( - ${LIBPNG_SOURCES_DIR}/scripts/pnglibconf.h.prebuilt - ${LIBPNG_SOURCES_DIR}/pnglibconf.h - COPY_ONLY) - - set(LIBPNG_SOURCES - #${LIBPNG_SOURCES_DIR}/example.c - ${LIBPNG_SOURCES_DIR}/png.c - ${LIBPNG_SOURCES_DIR}/pngerror.c - ${LIBPNG_SOURCES_DIR}/pngget.c - ${LIBPNG_SOURCES_DIR}/pngmem.c - ${LIBPNG_SOURCES_DIR}/pngpread.c - ${LIBPNG_SOURCES_DIR}/pngread.c - ${LIBPNG_SOURCES_DIR}/pngrio.c - ${LIBPNG_SOURCES_DIR}/pngrtran.c - ${LIBPNG_SOURCES_DIR}/pngrutil.c - ${LIBPNG_SOURCES_DIR}/pngset.c - #${LIBPNG_SOURCES_DIR}/pngtest.c - ${LIBPNG_SOURCES_DIR}/pngtrans.c - ${LIBPNG_SOURCES_DIR}/pngwio.c - ${LIBPNG_SOURCES_DIR}/pngwrite.c - ${LIBPNG_SOURCES_DIR}/pngwtran.c - ${LIBPNG_SOURCES_DIR}/pngwutil.c - ) - - #set_property( - # SOURCE ${LIBPNG_SOURCES} - # PROPERTY COMPILE_FLAGS -UHAVE_CONFIG_H) - - list(APPEND THIRD_PARTY_SOURCES ${LIBPNG_SOURCES}) - - add_definitions( - -DPNG_NO_CONSOLE_IO=1 - -DPNG_NO_STDIO=1 - ) - - source_group(ThirdParty\\Libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*) - -else() - include(FindPNG) - - if (NOT ${PNG_FOUND}) - message(FATAL_ERROR "Unable to find LibPNG") - endif() - - include_directories(${PNG_INCLUDE_DIRS}) - link_libraries(${PNG_LIBRARIES}) - add_definitions(${PNG_DEFINITIONS}) -endif()
--- a/Resources/CMake/SQLiteConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -if (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) - SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3071300) - DownloadPackage( - "5fbeff9645ab035a1f580e90b279a16d" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/sqlite-amalgamation-3071300.zip" - "${SQLITE_SOURCES_DIR}") - - list(APPEND SQLITE_SOURCES - ${SQLITE_SOURCES_DIR}/sqlite3.c - ) - - add_definitions( - # For SQLite to run in the "Serialized" thread-safe mode - # http://www.sqlite.org/threadsafe.html - -DSQLITE_THREADSAFE=1 - -DSQLITE_OMIT_LOAD_EXTENSION # Disable SQLite plugins - ) - - include_directories( - ${SQLITE_SOURCES_DIR} - ) - - source_group(ThirdParty\\SQLite REGULAR_EXPRESSION ${SQLITE_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE_CXX(sqlite3.h HAVE_SQLITE_H) - if (NOT HAVE_SQLITE_H) - message(FATAL_ERROR "Please install the libsqlite3-dev package") - endif() - - find_path(SQLITE_INCLUDE_DIR sqlite3.h - /usr/include - /usr/local/include - ) - message("SQLite include dir: ${SQLITE_INCLUDE_DIR}") - - # Autodetection of the version of SQLite - file(STRINGS "${SQLITE_INCLUDE_DIR}/sqlite3.h" SQLITE_VERSION_NUMBER1 REGEX "#define SQLITE_VERSION_NUMBER.*$") - string(REGEX REPLACE "#define SQLITE_VERSION_NUMBER(.*)$" "\\1" SQLITE_VERSION_NUMBER ${SQLITE_VERSION_NUMBER1}) - - message("Detected version of SQLite: ${SQLITE_VERSION_NUMBER}") - - IF (${SQLITE_VERSION_NUMBER} LESS 3007000) - # "sqlite3_create_function_v2" is not defined in SQLite < 3.7.0 - message(FATAL_ERROR "SQLite version must be above 3.7.0. Please set the CMake variable USE_SYSTEM_SQLITE to OFF.") - ENDIF() - - link_libraries(sqlite3) -endif()
--- a/Resources/CMake/ZlibConfiguration.cmake Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -# This is the minizip distribution to create ZIP files -list(APPEND THIRD_PARTY_SOURCES - ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/ioapi.c - ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/zip.c - ) - -if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB) - SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.7) - DownloadPackage( - "60df6a37c56e7c1366cca812414f7b85" - "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/zlib-1.2.7.tar.gz" - "${ZLIB_SOURCES_DIR}") - - include_directories( - ${ZLIB_SOURCES_DIR} - ) - - list(APPEND ZLIB_SOURCES - ${ZLIB_SOURCES_DIR}/adler32.c - ${ZLIB_SOURCES_DIR}/compress.c - ${ZLIB_SOURCES_DIR}/crc32.c - ${ZLIB_SOURCES_DIR}/deflate.c - ${ZLIB_SOURCES_DIR}/gzclose.c - ${ZLIB_SOURCES_DIR}/gzlib.c - ${ZLIB_SOURCES_DIR}/gzread.c - ${ZLIB_SOURCES_DIR}/gzwrite.c - ${ZLIB_SOURCES_DIR}/infback.c - ${ZLIB_SOURCES_DIR}/inffast.c - ${ZLIB_SOURCES_DIR}/inflate.c - ${ZLIB_SOURCES_DIR}/inftrees.c - ${ZLIB_SOURCES_DIR}/trees.c - ${ZLIB_SOURCES_DIR}/uncompr.c - ${ZLIB_SOURCES_DIR}/zutil.c - ) - -else() - include(FindZLIB) - include_directories(${ZLIB_INCLUDE_DIRS}) - link_libraries(${ZLIB_LIBRARIES}) -endif() - -source_group(ThirdParty\\ZLib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
--- a/Resources/SyncOrthancFolder.py Mon Jun 01 12:48:18 2015 +0200 +++ b/Resources/SyncOrthancFolder.py Tue Jun 02 11:16:30 2015 +0200 @@ -8,52 +8,64 @@ import os import shutil -SOURCE = '/home/jodogne/Subversion/Orthanc/Core' +SOURCE = '/home/jodogne/Subversion/Orthanc' TARGET = os.path.join(os.path.dirname(__file__), '..', 'Orthanc') FILES = [ - 'ChunkedBuffer.cpp', - 'ChunkedBuffer.h', - 'Enumerations.cpp', - 'Enumerations.h', - 'FileStorage/FilesystemStorage.cpp', - 'FileStorage/FilesystemStorage.h', - 'FileStorage/IStorageArea.h', - 'IDynamicObject.h', - 'ImageFormats/ImageAccessor.cpp', - 'ImageFormats/ImageAccessor.h', - 'ImageFormats/ImageBuffer.cpp', - 'ImageFormats/ImageBuffer.h', - 'ImageFormats/ImageProcessing.cpp', - 'ImageFormats/ImageProcessing.h', - 'ImageFormats/PngWriter.cpp', - 'ImageFormats/PngWriter.h', - 'MultiThreading/SharedMessageQueue.cpp', - 'MultiThreading/SharedMessageQueue.h', - 'OrthancException.cpp', - 'OrthancException.h', - 'PrecompiledHeaders.cpp', - 'PrecompiledHeaders.h', - 'SQLite/Connection.cpp', - 'SQLite/Connection.h', - 'SQLite/FunctionContext.cpp', - 'SQLite/FunctionContext.h', - 'SQLite/IScalarFunction.h', - 'SQLite/ITransaction.h', - 'SQLite/NonCopyable.h', - 'SQLite/OrthancSQLiteException.h', - 'SQLite/Statement.cpp', - 'SQLite/Statement.h', - 'SQLite/StatementId.cpp', - 'SQLite/StatementId.h', - 'SQLite/StatementReference.cpp', - 'SQLite/StatementReference.h', - 'SQLite/Transaction.cpp', - 'SQLite/Transaction.h', - 'Toolbox.cpp', - 'Toolbox.h', - 'Uuid.cpp', - 'Uuid.h', + 'Core/ChunkedBuffer.cpp', + 'Core/ChunkedBuffer.h', + 'Core/Enumerations.cpp', + 'Core/Enumerations.h', + 'Core/FileStorage/FilesystemStorage.cpp', + 'Core/FileStorage/FilesystemStorage.h', + 'Core/FileStorage/IStorageArea.h', + 'Core/IDynamicObject.h', + 'Core/ImageFormats/ImageAccessor.cpp', + 'Core/ImageFormats/ImageAccessor.h', + 'Core/ImageFormats/ImageBuffer.cpp', + 'Core/ImageFormats/ImageBuffer.h', + 'Core/ImageFormats/ImageProcessing.cpp', + 'Core/ImageFormats/ImageProcessing.h', + 'Core/ImageFormats/PngWriter.cpp', + 'Core/ImageFormats/PngWriter.h', + 'Core/MultiThreading/SharedMessageQueue.cpp', + 'Core/MultiThreading/SharedMessageQueue.h', + 'Core/OrthancException.cpp', + 'Core/OrthancException.h', + 'Core/PrecompiledHeaders.cpp', + 'Core/PrecompiledHeaders.h', + 'Core/SQLite/Connection.cpp', + 'Core/SQLite/Connection.h', + 'Core/SQLite/FunctionContext.cpp', + 'Core/SQLite/FunctionContext.h', + 'Core/SQLite/IScalarFunction.h', + 'Core/SQLite/ITransaction.h', + 'Core/SQLite/NonCopyable.h', + 'Core/SQLite/OrthancSQLiteException.h', + 'Core/SQLite/Statement.cpp', + 'Core/SQLite/Statement.h', + 'Core/SQLite/StatementId.cpp', + 'Core/SQLite/StatementId.h', + 'Core/SQLite/StatementReference.cpp', + 'Core/SQLite/StatementReference.h', + 'Core/SQLite/Transaction.cpp', + 'Core/SQLite/Transaction.h', + 'Core/Toolbox.cpp', + 'Core/Toolbox.h', + 'Core/Uuid.cpp', + 'Core/Uuid.h', + 'Resources/ThirdParty/base64/base64.cpp', + 'Resources/ThirdParty/base64/base64.h', + 'Resources/ThirdParty/md5/md5.c', + 'Resources/ThirdParty/md5/md5.h', + 'Resources/CMake/AutoGeneratedCode.cmake', + 'Resources/CMake/BoostConfiguration.cmake', + 'Resources/CMake/Compiler.cmake', + 'Resources/CMake/DownloadPackage.cmake', + 'Resources/CMake/GoogleTestConfiguration.cmake', + 'Resources/CMake/LibPngConfiguration.cmake', + 'Resources/CMake/SQLiteConfiguration.cmake', + 'Resources/CMake/ZlibConfiguration.cmake', ] for f in FILES:
--- a/Resources/ThirdParty/base64/base64.cpp Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - base64.cpp and base64.h - - Copyright (C) 2004-2008 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch - -*/ - -#include "base64.h" -#include <string.h> - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(const std::string& stringToEncode) -{ - const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*> - (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL); - unsigned int in_len = stringToEncode.size(); - - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; -} - - -std::string base64_decode(const std::string& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; -}
--- a/Resources/ThirdParty/base64/base64.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -#include <string> - -std::string base64_encode(const std::string& stringToEncode); -std::string base64_decode(const std::string& s);
--- a/Resources/ThirdParty/md5/md5.c Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include <string.h> - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include <stdio.h> in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include <string.h> - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -}
--- a/Resources/ThirdParty/md5/md5.h Mon Jun 01 12:48:18 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke <purschke@bnl.gov>. - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */