diff OrthancServer/OrthancRestApi.cpp @ 250:f23318b11b39

creation of zip files
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Dec 2012 12:29:10 +0100
parents 5694365ecb96
children 15fcd925b05b
line wrap: on
line diff
--- a/OrthancServer/OrthancRestApi.cpp	Wed Dec 05 09:28:06 2012 +0100
+++ b/OrthancServer/OrthancRestApi.cpp	Wed Dec 05 12:29:10 2012 +0100
@@ -296,7 +296,6 @@
  
   static void GetSystemInformation(RestApi::GetCall& call)
   {
-    RETRIEVE_CONTEXT(call);
     Json::Value result = Json::objectValue;
 
     result["Version"] = ORTHANC_VERSION;
@@ -353,57 +352,182 @@
 
   // Download of ZIP files ----------------------------------------------------
  
-  static void GetPatientArchive(RestApi::GetCall& call)
+
+  static std::string GetDirectoryNameInArchive(const Json::Value& resource,
+                                               ResourceType resourceType)
+  {
+    switch (resourceType)
+    {
+      case ResourceType_Patient:
+      {
+        std::string p = resource["MainDicomTags"]["PatientID"].asString();
+        std::string n = resource["MainDicomTags"]["PatientName"].asString();
+        return p + " " + n;
+      }
+
+      case ResourceType_Study:
+        return resource["MainDicomTags"]["StudyDescription"].asString();
+        
+      case ResourceType_Series:
+        return resource["MainDicomTags"]["SeriesDescription"].asString();
+        
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+
+  static bool CreateRootDirectoryInArchive(HierarchicalZipWriter& writer,
+                                           ServerContext& context,
+                                           const Json::Value& resource,
+                                           ResourceType resourceType)
+  {
+    if (resourceType == ResourceType_Patient)
+    {
+      return true;
+    }
+
+    ResourceType parentType = GetParentResourceType(resourceType);
+    Json::Value parent;
+
+    switch (resourceType)
+    {
+      case ResourceType_Study:
+      {
+        if (!context.GetIndex().LookupResource(parent, resource["ParentPatient"].asString(), parentType))
+        {
+          return false;
+        }
+
+        break;
+      }
+        
+      case ResourceType_Series:
+        if (!context.GetIndex().LookupResource(parent, resource["ParentStudy"].asString(), parentType) ||
+            !CreateRootDirectoryInArchive(writer, context, parent, parentType))
+        {
+          return false;
+        }
+        break;
+        
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+
+    writer.OpenDirectory(GetDirectoryNameInArchive(parent, parentType).c_str());
+    return true;
+  }
+
+  static bool ArchiveInstance(HierarchicalZipWriter& writer,
+                              ServerContext& context,
+                              const std::string& instancePublicId)
+  {
+    Json::Value instance;
+    if (!context.GetIndex().LookupResource(instance, instancePublicId, ResourceType_Instance))
+    {
+      return false;
+    }
+
+    std::string filename = instance["MainDicomTags"]["SOPInstanceUID"].asString() + ".dcm";
+    writer.OpenFile(filename.c_str());
+
+    std::string dicom;
+    context.ReadFile(dicom, instancePublicId, FileContentType_Dicom);
+    writer.Write(dicom);
+
+    return true;
+  }
+
+  static bool ArchiveInternal(HierarchicalZipWriter& writer,
+                              ServerContext& context,
+                              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))
+    {
+      return false;
+    }
+
+    writer.OpenDirectory(GetDirectoryNameInArchive(resource, resourceType).c_str());
+
+    switch (resourceType)
+    {
+      case ResourceType_Patient:
+        for (size_t i = 0; i < resource["Studies"].size(); i++)
+        {
+          std::string studyId = resource["Studies"][i].asString();
+          if (!ArchiveInternal(writer, context, studyId, ResourceType_Study, false))
+          {
+            return false;
+          }
+        }
+        break;
+
+      case ResourceType_Study:
+        for (size_t i = 0; i < resource["Series"].size(); i++)
+        {
+          std::string seriesId = resource["Series"][i].asString();
+          if (!ArchiveInternal(writer, context, seriesId, ResourceType_Series, false))
+          {
+            return false;
+          }
+        }
+        break;
+
+      case ResourceType_Series:
+        for (size_t i = 0; i < resource["Instances"].size(); i++)
+        {
+          if (!ArchiveInstance(writer, context, resource["Instances"][i].asString()))
+          {
+            return false;
+          }
+        }
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+
+    writer.CloseDirectory();
+    return true;
+  }                                 
+
+  template <enum ResourceType resourceType>
+  static void GetArchive(RestApi::GetCall& call)
   {
     RETRIEVE_CONTEXT(call);
 
-    Json::Value patient;
-    if (!context.GetIndex().LookupResource(patient, call.GetUriComponent("id", ""), ResourceType_Patient))
-    {
-      return;
-    }
-
+    // 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());
-      
-      for (size_t i = 0; i < patient["Studies"].size(); i++)
-      {
-        Json::Value study;
-        if (context.GetIndex().LookupResource(study, patient["Studies"][i].asString(), ResourceType_Study))
-        {
-          writer.OpenDirectory(study["MainDicomTags"]["StudyDescription"].asString().c_str());
 
-          for (size_t i = 0; i < study["Series"].size(); i++)
-          {
-            Json::Value series;
-            if (context.GetIndex().LookupResource(series, study["Series"][i].asString(), ResourceType_Series))
-            {
-              std::string m = series["MainDicomTags"]["Modality"].asString();
-              std::string s = series["MainDicomTags"]["SeriesDescription"].asString();
-              writer.OpenDirectory((m + " " + s).c_str());
-
-              for (size_t i = 0; i < series["Instances"].size(); i++)
-              {
-                Json::Value instance;
-                if (context.GetIndex().LookupResource(instance, series["Instances"][i].asString(), ResourceType_Instance))
-                {
-                  writer.OpenFile(instance["MainDicomTags"]["SOPInstanceUID"].asString().c_str());
-                }
-              }
-
-              writer.CloseDirectory();
-            }
-          }
-
-          writer.CloseDirectory();
-        }
+      // Store the requested resource into the ZIP
+      if (!ArchiveInternal(writer, context, id, resourceType, true))
+      {
+        return;
       }
     }
-    
+
+    // Prepare the sending of the ZIP file
     FilesystemHttpSender sender(tmp.GetPath().c_str());
+    sender.SetContentType("application/zip");
+    sender.SetDownloadFilename(id + ".zip");
+
+    // Send the ZIP
     call.GetOutput().AnswerFile(sender);
+
+    // The temporary file is automatically removed thanks to the RAII
   }
 
 
@@ -710,7 +834,10 @@
     Register("/series/{id}", GetSingleResource<ResourceType_Series>);
     Register("/studies/{id}", DeleteSingleResource<ResourceType_Study>);
     Register("/studies/{id}", GetSingleResource<ResourceType_Study>);
-    Register("/patients/{id}/archive", GetPatientArchive);
+
+    Register("/patients/{id}/archive", GetArchive<ResourceType_Patient>);
+    Register("/studies/{id}/archive", GetArchive<ResourceType_Study>);
+    Register("/series/{id}/archive", GetArchive<ResourceType_Series>);
 
     Register("/instances/{id}/file", GetInstanceFile);
     Register("/instances/{id}/tags", GetInstanceTags<false>);