# HG changeset patch # User Sebastien Jodogne # Date 1447409928 -3600 # Node ID 1861e410a9d7e192c62358851ec8e53fba80c39e # Parent 784a6b92d2f123984f4db4635eb87bdea8324cee visitors diff -r 784a6b92d2f1 -r 1861e410a9d7 OrthancServer/OrthancRestApi/OrthancRestArchive.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Thu Nov 12 17:49:04 2015 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp Fri Nov 13 11:18:48 2015 +0100 @@ -34,6 +34,7 @@ #include "OrthancRestApi.h" #include "../DicomDirWriter.h" +#include "../../Core/FileStorage/StorageAccessor.h" #include "../../Core/Compression/HierarchicalZipWriter.h" #include "../../Core/HttpServer/FilesystemHttpSender.h" #include "../../Core/Logging.h" @@ -479,14 +480,44 @@ }; + class IArchiveVisitor : public boost::noncopyable + { + public: + virtual ~IArchiveVisitor() + { + } + + virtual void Open(ResourceType level, + const std::string& publicId) = 0; + + virtual void Close() = 0; + + virtual void AddInstance(const std::string& instanceId, + const FileInfo& dicom) = 0; + }; + + class ArchiveIndex { private: - typedef std::map Resources; + struct Instance + { + std::string id_; + FileInfo dicom_; - ServerIndex& index_; - ResourceType level_; - Resources resources_; + Instance(const std::string& id, + const FileInfo& dicom) : + id_(id), dicom_(dicom) + { + } + }; + + typedef std::map Resources; + + ServerIndex& index_; + ResourceType level_; + Resources resources_; + std::vector instances_; void AddResourceToExpand(const std::string& id) { @@ -547,82 +578,149 @@ { if (level_ == ResourceType_Instance) { - return; - } + // At the instance level, locate all the DICOM files + // associated with the instances + instances_.reserve(resources_.size()); - for (Resources::iterator it = resources_.begin(); - it != resources_.end(); ++it) - { - if (it->second == NULL) + for (Resources::iterator it = resources_.begin(); + it != resources_.end(); ++it) { - std::list children; - index_.GetChildren(children, it->first); - - std::auto_ptr child(new ArchiveIndex(index_, GetChildResourceType(level_))); + assert(it->second == NULL); - for (std::list::const_iterator - it2 = children.begin(); it2 != children.end(); ++it2) + FileInfo tmp; + if (index_.LookupAttachment(tmp, it->first, FileContentType_Dicom)) { - child->AddResourceToExpand(*it2); + instances_.push_back(Instance(it->first, tmp)); + } + } + } + else + { + // At the patient, study or series level + for (Resources::iterator it = resources_.begin(); + it != resources_.end(); ++it) + { + if (it->second == NULL) + { + // This is resource is marked for expansion + std::list children; + index_.GetChildren(children, it->first); + + std::auto_ptr child(new ArchiveIndex(index_, GetChildResourceType(level_))); + + for (std::list::const_iterator + it2 = children.begin(); it2 != children.end(); ++it2) + { + child->AddResourceToExpand(*it2); + } + + it->second = child.release(); } - it->second = child.release(); - } - - assert(it->second != NULL); - it->second->Expand(); - } + assert(it->second != NULL); + it->second->Expand(); + } + } } - void ComputeStatistics(uint64_t& totalSize, - unsigned int& totalInstances) + void Apply(IArchiveVisitor& visitor) const { - for (Resources::iterator it = resources_.begin(); - it != resources_.end(); ++it) + if (level_ == ResourceType_Instance) { - if (level_ == ResourceType_Instance) + for (size_t i = 0; i < instances_.size(); i++) + { + visitor.AddInstance(instances_[i].id_, instances_[i].dicom_); + } + } + else + { + for (Resources::const_iterator it = resources_.begin(); + it != resources_.end(); ++it) { - FileInfo dicom; - if (index_.LookupAttachment(dicom, it->first, FileContentType_Dicom)) - { - totalSize += dicom.GetUncompressedSize(); - totalInstances ++; - } + assert(it->second != NULL); // There must have been a call to "Expand()" + visitor.Open(level_, it->first); + it->second->Apply(visitor); + visitor.Close(); } - else - { - if (it->second == NULL) - { - // The method "Expand" was not called - throw OrthancException(ErrorCode_InternalError); - } + } + } + }; + - it->second->ComputeStatistics(totalSize, totalInstances); - } - } + class StatisticsVisitor : public IArchiveVisitor + { + private: + uint64_t size_; + unsigned int instances_; + + public: + StatisticsVisitor() : size_(0), instances_(0) + { + } + + uint64_t GetUncompressedSize() const + { + return size_; + } + + unsigned int GetInstancesCount() const + { + return instances_; } + virtual void Open(ResourceType level, + const std::string& publicId) + { + } - void Print(std::ostream& o, - const std::string& indent = "") const + virtual void Close() + { + } + + virtual void AddInstance(const std::string& instanceId, + const FileInfo& dicom) { - for (Resources::const_iterator it = resources_.begin(); - it != resources_.end(); ++it) + instances_ ++; + size_ += dicom.GetUncompressedSize(); + } + }; + + + class PrintVisitor : public IArchiveVisitor + { + private: + std::ostream& out_; + std::string indent_; + + public: + PrintVisitor(std::ostream& out) : out_(out) + { + } + + virtual void Open(ResourceType level, + const std::string& publicId) + { + switch (level) { - o << indent << it->first << std::endl; - if (it->second == NULL) - { - if (level_ != ResourceType_Instance) - { - o << indent << " *" << std::endl; - } - } - else - { - it->second->Print(o, indent + " "); - } + case ResourceType_Patient: indent_ = ""; break; + case ResourceType_Study: indent_ = " "; break; + case ResourceType_Series: indent_ = " "; break; + default: + throw OrthancException(ErrorCode_InternalError); } + + out_ << indent_ << publicId << std::endl; + } + + virtual void Close() + { + } + + virtual void AddInstance(const std::string& instanceId, + const FileInfo& dicom) + { + out_ << " " << instanceId << std::endl; } }; } @@ -651,13 +749,13 @@ archive.Expand(); - archive.Print(std::cout); + PrintVisitor v(std::cout); + archive.Apply(v); - uint64_t totalSize = 0; - unsigned int totalInstances = 0; - archive.ComputeStatistics(totalSize, totalInstances); + StatisticsVisitor s; + archive.Apply(s); - std::cout << totalSize << " " << totalInstances << std::endl; + std::cout << s.GetUncompressedSize() << " " << s.GetInstancesCount() << std::endl; } }