# HG changeset patch # User Sebastien Jodogne # Date 1352456009 -3600 # Node ID 5739b4d10a4b9be4f793c71375cdbdc54bafc4cc # Parent 81b6f30137384ddd2de80dc1f079b292aeabc5ad hashing diff -r 81b6f3013738 -r 5739b4d10a4b CMakeLists.txt --- a/CMakeLists.txt Fri Nov 09 10:42:00 2012 +0100 +++ b/CMakeLists.txt Fri Nov 09 11:13:29 2012 +0100 @@ -102,6 +102,7 @@ Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomTag.cpp Core/DicomFormat/DicomIntegerPixelAccessor.cpp + Core/DicomFormat/DicomInstanceHasher.cpp Core/FileStorage.cpp Core/HttpServer/EmbeddedResourceHttpHandler.cpp Core/HttpServer/FilesystemHttpHandler.cpp diff -r 81b6f3013738 -r 5739b4d10a4b Core/DicomFormat/DicomInstanceHasher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/DicomFormat/DicomInstanceHasher.cpp Fri Nov 09 11:13:29 2012 +0100 @@ -0,0 +1,82 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012 Medical Physics Department, CHU 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 . + **/ + +#include "DicomInstanceHasher.h" + +#include "../OrthancException.h" +#include "../Toolbox.h" + +namespace Orthanc +{ + DicomInstanceHasher::DicomInstanceHasher(const DicomMap& instance) + { + patientId_ = instance.GetValue(DICOM_TAG_PATIENT_ID).AsString(); + instanceUid_ = instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); + seriesUid_ = instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); + studyUid_ = instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); + + if (patientId_.size() == 0 || + instanceUid_.size() == 0 || + seriesUid_.size() == 0 || + studyUid_.size() == 0) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + std::string DicomInstanceHasher::HashPatient() const + { + std::string s; + Toolbox::ComputeSHA1(s, patientId_); + return s; + } + + std::string DicomInstanceHasher::HashStudy() const + { + std::string s; + Toolbox::ComputeSHA1(s, patientId_ + "|" + studyUid_); + return s; + } + + std::string DicomInstanceHasher::HashSeries() const + { + std::string s; + Toolbox::ComputeSHA1(s, patientId_ + "|" + studyUid_ + "|" + seriesUid_); + return s; + } + + std::string DicomInstanceHasher::HashInstance() const + { + std::string s; + Toolbox::ComputeSHA1(s, patientId_ + "|" + studyUid_ + "|" + seriesUid_ + "|" + instanceUid_); + return s; + } +} diff -r 81b6f3013738 -r 5739b4d10a4b Core/DicomFormat/DicomInstanceHasher.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/DicomFormat/DicomInstanceHasher.h Fri Nov 09 11:13:29 2012 +0100 @@ -0,0 +1,88 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012 Medical Physics Department, CHU 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 . + **/ + + +#pragma once + +#include "DicomMap.h" + +namespace Orthanc +{ + /** + * This class implements the hashing mechanism that is used to + * convert DICOM unique identifiers to Orthanc identifiers. Any + * Orthanc identifier for a DICOM resource corresponds to the SHA-1 + * hash of the DICOM identifiers. + + * \note SHA-1 hash is used because it is less sensitive to + * collision attacks than MD5. [Reference] + **/ + class DicomInstanceHasher + { + private: + std::string patientId_; + std::string instanceUid_; + std::string seriesUid_; + std::string studyUid_; + + public: + DicomInstanceHasher(const DicomMap& instance); + + const std::string& GetPatientId() const + { + return patientId_; + } + + const std::string& GetInstanceUid() const + { + return instanceUid_; + } + + const std::string& GetSeriesUid() const + { + return seriesUid_; + } + + const std::string& GetStudyUid() const + { + return studyUid_; + } + + std::string HashPatient() const; + + std::string HashStudy() const; + + std::string HashSeries() const; + + std::string HashInstance() const; + }; +} diff -r 81b6f3013738 -r 5739b4d10a4b OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Fri Nov 09 10:42:00 2012 +0100 +++ b/OrthancServer/ServerIndex.cpp Fri Nov 09 11:13:29 2012 +0100 @@ -42,6 +42,7 @@ #include "../Core/Toolbox.h" #include "../Core/Uuid.h" #include "../Core/DicomFormat/DicomArray.h" +#include "../Core/DicomFormat/DicomInstanceHasher.h" #include "../Core/SQLite/Transaction.h" #include "FromDcmtkBridge.h" @@ -530,53 +531,50 @@ { boost::mutex::scoped_lock scoped_lock(mutex_); - std::string dicomPatientId = dicomSummary.GetValue(DICOM_TAG_PATIENT_ID).AsString(); - std::string dicomInstance = dicomSummary.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); - std::string dicomSeries = dicomSummary.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); - std::string dicomStudy = dicomSummary.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); + DicomInstanceHasher hasher(dicomSummary); try { SQLite::Transaction t(db_); t.Begin(); - if (HasInstance(instanceUuid, dicomInstance)) + if (HasInstance(instanceUuid, hasher.GetInstanceUid())) { return StoreStatus_AlreadyStored; // TODO: Check consistency? } std::string patientUuid; - if (HasPatient(patientUuid, dicomPatientId)) + if (HasPatient(patientUuid, hasher.GetPatientId())) { // TODO: Check consistency? } else { - patientUuid = CreatePatient(dicomPatientId, dicomSummary); + patientUuid = CreatePatient(hasher.GetPatientId(), dicomSummary); } std::string studyUuid; - if (HasStudy(studyUuid, dicomStudy)) + if (HasStudy(studyUuid, hasher.GetStudyUid())) { // TODO: Check consistency? } else { - studyUuid = CreateStudy(patientUuid, dicomStudy, dicomSummary); + studyUuid = CreateStudy(patientUuid, hasher.GetStudyUid(), dicomSummary); } std::string seriesUuid; - if (HasSeries(seriesUuid, dicomSeries)) + if (HasSeries(seriesUuid, hasher.GetSeriesUid())) { // TODO: Check consistency? } else { - seriesUuid = CreateSeries(studyUuid, dicomSeries, dicomSummary); + seriesUuid = CreateSeries(studyUuid, hasher.GetSeriesUid(), dicomSummary); } - instanceUuid = CreateInstance(seriesUuid, dicomInstance, dicomSummary, fileUuid, + instanceUuid = CreateInstance(seriesUuid, hasher.GetInstanceUid(), dicomSummary, fileUuid, uncompressedFileSize, jsonUuid, distantAet); t.Commit(); diff -r 81b6f3013738 -r 5739b4d10a4b OrthancServer/main.cpp --- a/OrthancServer/main.cpp Fri Nov 09 10:42:00 2012 +0100 +++ b/OrthancServer/main.cpp Fri Nov 09 11:13:29 2012 +0100 @@ -249,8 +249,8 @@ httpServer.SetSslEnabled(false); } - LOG(INFO) << "DICOM server listening on port: " << dicomServer.GetPortNumber(); - LOG(INFO) << "HTTP server listening on port: " << httpServer.GetPortNumber(); + LOG(WARNING) << "DICOM server listening on port: " << dicomServer.GetPortNumber(); + LOG(WARNING) << "HTTP server listening on port: " << httpServer.GetPortNumber(); #if ORTHANC_STANDALONE == 1 httpServer.RegisterHandler(new EmbeddedResourceHttpHandler("/app", EmbeddedResources::ORTHANC_EXPLORER));