# HG changeset patch # User Sebastien Jodogne # Date 1383119925 -3600 # Node ID fb49bf72ac2d8317cb2a51d8ada667964241b218 # Parent 75af92b18e2342328c387f45ad4c9d9fa412ec0c fix issue 7 diff -r 75af92b18e23 -r fb49bf72ac2d Core/Compression/HierarchicalZipWriter.h --- a/Core/Compression/HierarchicalZipWriter.h Tue Oct 29 20:32:24 2013 +0100 +++ b/Core/Compression/HierarchicalZipWriter.h Wed Oct 30 08:58:45 2013 +0100 @@ -94,6 +94,16 @@ ~HierarchicalZipWriter(); + void SetZip64(bool isZip64) + { + writer_.SetZip64(isZip64); + } + + bool IsZip64() const + { + return writer_.IsZip64(); + } + void SetCompressionLevel(uint8_t level) { writer_.SetCompressionLevel(level); diff -r 75af92b18e23 -r fb49bf72ac2d OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Tue Oct 29 20:32:24 2013 +0100 +++ b/OrthancServer/OrthancRestApi.cpp Wed Oct 30 08:58:45 2013 +0100 @@ -46,6 +46,9 @@ #include #include +static const uint64_t MEGA_BYTES = 1024 * 1024; +static const uint64_t GIGA_BYTES = 1024 * 1024 * 1024; + #define RETRIEVE_CONTEXT(call) \ OrthancRestApi& contextApi = \ @@ -551,12 +554,12 @@ const std::string& publicId, ResourceType resourceType, bool isFirstLevel) - { + { Json::Value resource; if (!context.GetIndex().LookupResource(resource, publicId, resourceType)) { return false; - } + } if (isFirstLevel && !CreateRootDirectoryInArchive(writer, context, resource, resourceType)) @@ -612,14 +615,36 @@ static void GetArchive(RestApi::GetCall& call) { RETRIEVE_CONTEXT(call); + std::string id = call.GetUriComponent("id", ""); + + /** + * Determine whether ZIP64 is required. Original ZIP format can + * store up to 2GB of data (some implementation supporting up to + * 4GB of data), and up to 65535 files. + * https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64 + **/ + + uint64_t uncompressedSize; + uint64_t compressedSize; + unsigned int countStudies; + unsigned int countSeries; + unsigned int countInstances; + context.GetIndex().GetStatistics(compressedSize, uncompressedSize, + countStudies, countSeries, countInstances, id); + const bool isZip64 = (uncompressedSize >= 2 * GIGA_BYTES || + countInstances >= 65535); + + LOG(INFO) << "Creating a ZIP file with " << countInstances << " files of size " + << (uncompressedSize / MEGA_BYTES) << "MB using the " + << (isZip64 ? "ZIP64" : "ZIP32") << " file format"; // Create a RAII for the temporary file to manage the ZIP file Toolbox::TemporaryFile tmp; - std::string id = call.GetUriComponent("id", ""); { // Create a ZIP writer HierarchicalZipWriter writer(tmp.GetPath().c_str()); + writer.SetZip64(isZip64); // Store the requested resource into the ZIP if (!ArchiveInternal(writer, context, id, resourceType, true)) diff -r 75af92b18e23 -r fb49bf72ac2d OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Tue Oct 29 20:32:24 2013 +0100 +++ b/OrthancServer/ServerIndex.cpp Wed Oct 30 08:58:45 2013 +0100 @@ -1301,26 +1301,22 @@ } - void ServerIndex::GetStatistics(Json::Value& target, - const std::string& publicId) + void ServerIndex::GetStatisticsInternal(/* out */ uint64_t& compressedSize, + /* out */ uint64_t& uncompressedSize, + /* out */ unsigned int& countStudies, + /* out */ unsigned int& countSeries, + /* out */ unsigned int& countInstances, + /* in */ int64_t id, + /* in */ ResourceType type) { - boost::mutex::scoped_lock lock(mutex_); + std::stack toExplore; + toExplore.push(id); - ResourceType type; - int64_t top; - if (!db_->LookupResource(publicId, top, type)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - std::stack toExplore; - toExplore.push(top); - - int countInstances = 0; - int countSeries = 0; - int countStudies = 0; - uint64_t compressedSize = 0; - uint64_t uncompressedSize = 0; + countInstances = 0; + countSeries = 0; + countStudies = 0; + compressedSize = 0; + uncompressedSize = 0; while (!toExplore.empty()) { @@ -1375,6 +1371,39 @@ } } + if (countStudies == 0) + { + countStudies = 1; + } + + if (countSeries == 0) + { + countSeries = 1; + } + } + + + + void ServerIndex::GetStatistics(Json::Value& target, + const std::string& publicId) + { + boost::mutex::scoped_lock lock(mutex_); + + ResourceType type; + int64_t top; + if (!db_->LookupResource(publicId, top, type)) + { + throw OrthancException(ErrorCode_UnknownResource); + } + + uint64_t uncompressedSize; + uint64_t compressedSize; + unsigned int countStudies; + unsigned int countSeries; + unsigned int countInstances; + GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, + countSeries, countInstances, top, type); + target = Json::objectValue; target["DiskSize"] = boost::lexical_cast(compressedSize); target["DiskSizeMB"] = boost::lexical_cast(compressedSize / MEGA_BYTES); @@ -1400,6 +1429,27 @@ } + void ServerIndex::GetStatistics(/* out */ uint64_t& compressedSize, + /* out */ uint64_t& uncompressedSize, + /* out */ unsigned int& countStudies, + /* out */ unsigned int& countSeries, + /* out */ unsigned int& countInstances, + const std::string& publicId) + { + boost::mutex::scoped_lock lock(mutex_); + + ResourceType type; + int64_t top; + if (!db_->LookupResource(publicId, top, type)) + { + throw OrthancException(ErrorCode_UnknownResource); + } + + GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, + countSeries, countInstances, top, type); + } + + void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that) { int stableAge = GetGlobalIntegerParameter("StableAge", 60); diff -r 75af92b18e23 -r fb49bf72ac2d OrthancServer/ServerIndex.h --- a/OrthancServer/ServerIndex.h Tue Oct 29 20:32:24 2013 +0100 +++ b/OrthancServer/ServerIndex.h Wed Oct 30 08:58:45 2013 +0100 @@ -90,6 +90,14 @@ void MarkAsUnstable(int64_t id, Orthanc::ResourceType type); + void GetStatisticsInternal(/* out */ uint64_t& compressedSize, + /* out */ uint64_t& uncompressedSize, + /* out */ unsigned int& countStudies, + /* out */ unsigned int& countSeries, + /* out */ unsigned int& countInstances, + /* in */ int64_t id, + /* in */ ResourceType type); + public: typedef std::list Attachments; @@ -187,6 +195,13 @@ void GetStatistics(Json::Value& target, const std::string& publicId); + void GetStatistics(/* out */ uint64_t& compressedSize, + /* out */ uint64_t& uncompressedSize, + /* out */ unsigned int& countStudies, + /* out */ unsigned int& countSeries, + /* out */ unsigned int& countInstances, + const std::string& publicId); + void LookupTagValue(std::list& result, DicomTag tag, const std::string& value,