void ServerContext::ReadFile(std::string& result, const std::string& instancePublicId, FileContentType content) { FileInfo attachment; if (!index_.LookupAttachment(attachment, instancePublicId, content)) { throw OrthancException(ErrorCode_InternalError); } accessor_.SetCompressionForNextOperations(attachment.GetCompressionType()); accessor_.Read(result, attachment.GetUuid()); }
void DatabaseWrapperBase::AddAttachment(int64_t id, const FileInfo& attachment) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); s.BindInt64(0, id); s.BindInt(1, attachment.GetContentType()); s.BindString(2, attachment.GetUuid()); s.BindInt64(3, attachment.GetCompressedSize()); s.BindInt64(4, attachment.GetUncompressedSize()); s.BindInt(5, attachment.GetCompressionType()); s.BindString(6, attachment.GetUncompressedMD5()); s.BindString(7, attachment.GetCompressedMD5()); s.Run(); }
void ServerContext::AnswerFile(RestApiOutput& output, const std::string& instancePublicId, FileContentType content) { FileInfo attachment; if (!index_.LookupAttachment(attachment, instancePublicId, content)) { throw OrthancException(ErrorCode_InternalError); } accessor_.SetCompressionForNextOperations(attachment.GetCompressionType()); std::auto_ptr<HttpFileSender> sender(accessor_.ConstructHttpFileSender(attachment.GetUuid())); sender->SetContentType("application/dicom"); sender->SetDownloadFilename(instancePublicId + ".dcm"); output.AnswerFile(*sender); }
TEST(StorageAccessor, Compression) { FilesystemStorage s("UnitTestsStorage"); StorageAccessor accessor(s); std::string data = "Hello world"; FileInfo info = accessor.Write(data, FileContentType_DicomAsJson, CompressionType_ZlibWithSize, true); std::string r; accessor.Read(r, info); ASSERT_EQ(data, r); ASSERT_EQ(CompressionType_ZlibWithSize, info.GetCompressionType()); ASSERT_EQ(11u, info.GetUncompressedSize()); ASSERT_EQ(FileContentType_DicomAsJson, info.GetContentType()); ASSERT_EQ("3e25960a79dbc69b674cd4ec67a72c62", info.GetUncompressedMD5()); ASSERT_NE(info.GetUncompressedMD5(), info.GetCompressedMD5()); }
void ServerContext::ChangeAttachmentCompression(const std::string& resourceId, FileContentType attachmentType, CompressionType compression) { LOG(INFO) << "Changing compression type for attachment " << EnumerationToString(attachmentType) << " of resource " << resourceId << " to " << compression; FileInfo attachment; if (!index_.LookupAttachment(attachment, resourceId, attachmentType)) { throw OrthancException(ErrorCode_UnknownResource); } if (attachment.GetCompressionType() == compression) { // Nothing to do return; } std::string content; StorageAccessor accessor(area_); accessor.Read(content, attachment); FileInfo modified = accessor.Write(content.empty() ? NULL : content.c_str(), content.size(), attachmentType, compression, storeMD5_); try { StoreStatus status = index_.AddAttachment(modified, resourceId); if (status != StoreStatus_Success) { accessor.Remove(modified); throw OrthancException(ErrorCode_Database); } } catch (OrthancException&) { accessor.Remove(modified); throw; } }
TEST_P(DatabaseWrapperTest, Simple) { int64_t a[] = { index_->CreateResource("a", ResourceType_Patient), // 0 index_->CreateResource("b", ResourceType_Study), // 1 index_->CreateResource("c", ResourceType_Series), // 2 index_->CreateResource("d", ResourceType_Instance), // 3 index_->CreateResource("e", ResourceType_Instance), // 4 index_->CreateResource("f", ResourceType_Instance), // 5 index_->CreateResource("g", ResourceType_Study) // 6 }; ASSERT_EQ("a", index_->GetPublicId(a[0])); ASSERT_EQ("b", index_->GetPublicId(a[1])); ASSERT_EQ("c", index_->GetPublicId(a[2])); ASSERT_EQ("d", index_->GetPublicId(a[3])); ASSERT_EQ("e", index_->GetPublicId(a[4])); ASSERT_EQ("f", index_->GetPublicId(a[5])); ASSERT_EQ("g", index_->GetPublicId(a[6])); ASSERT_EQ(ResourceType_Patient, index_->GetResourceType(a[0])); ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[1])); ASSERT_EQ(ResourceType_Series, index_->GetResourceType(a[2])); ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[3])); ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[4])); ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[5])); ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[6])); { std::list<std::string> t; index_->GetAllPublicIds(t, ResourceType_Patient); ASSERT_EQ(1u, t.size()); ASSERT_EQ("a", t.front()); index_->GetAllPublicIds(t, ResourceType_Series); ASSERT_EQ(1u, t.size()); ASSERT_EQ("c", t.front()); index_->GetAllPublicIds(t, ResourceType_Study); ASSERT_EQ(2u, t.size()); index_->GetAllPublicIds(t, ResourceType_Instance); ASSERT_EQ(3u, t.size()); } index_->SetGlobalProperty(GlobalProperty_FlushSleep, "World"); index_->AttachChild(a[0], a[1]); index_->AttachChild(a[1], a[2]); index_->AttachChild(a[2], a[3]); index_->AttachChild(a[2], a[4]); index_->AttachChild(a[6], a[5]); int64_t parent; ASSERT_FALSE(index_->LookupParent(parent, a[0])); ASSERT_TRUE(index_->LookupParent(parent, a[1])); ASSERT_EQ(a[0], parent); ASSERT_TRUE(index_->LookupParent(parent, a[2])); ASSERT_EQ(a[1], parent); ASSERT_TRUE(index_->LookupParent(parent, a[3])); ASSERT_EQ(a[2], parent); ASSERT_TRUE(index_->LookupParent(parent, a[4])); ASSERT_EQ(a[2], parent); ASSERT_TRUE(index_->LookupParent(parent, a[5])); ASSERT_EQ(a[6], parent); ASSERT_FALSE(index_->LookupParent(parent, a[6])); std::string s; CheckNoParent(a[0]); CheckNoParent(a[6]); CheckParentPublicId("a", a[1]); CheckParentPublicId("b", a[2]); CheckParentPublicId("c", a[3]); CheckParentPublicId("c", a[4]); CheckParentPublicId("g", a[5]); std::list<std::string> l; index_->GetChildrenPublicId(l, a[0]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("b", l.front()); index_->GetChildrenPublicId(l, a[1]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("c", l.front()); index_->GetChildrenPublicId(l, a[3]); ASSERT_EQ(0u, l.size()); index_->GetChildrenPublicId(l, a[4]); ASSERT_EQ(0u, l.size()); index_->GetChildrenPublicId(l, a[5]); ASSERT_EQ(0u, l.size()); index_->GetChildrenPublicId(l, a[6]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("f", l.front()); index_->GetChildrenPublicId(l, a[2]); ASSERT_EQ(2u, l.size()); if (l.front() == "d") { ASSERT_EQ("e", l.back()); } else { ASSERT_EQ("d", l.back()); ASSERT_EQ("e", l.front()); } std::list<MetadataType> md; index_->ListAvailableMetadata(md, a[4]); ASSERT_EQ(0u, md.size()); index_->AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", CompressionType_Zlib, 21, "compressedMD5")); index_->AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5")); index_->AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5")); index_->SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE"); index_->ListAvailableMetadata(md, a[4]); ASSERT_EQ(1u, md.size()); ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front()); index_->SetMetadata(a[4], MetadataType_ModifiedFrom, "TUTU"); index_->ListAvailableMetadata(md, a[4]); ASSERT_EQ(2u, md.size()); std::map<MetadataType, std::string> md2; index_->GetAllMetadata(md2, a[4]); ASSERT_EQ(2u, md2.size()); ASSERT_EQ("TUTU", md2[MetadataType_ModifiedFrom]); ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]); index_->DeleteMetadata(a[4], MetadataType_ModifiedFrom); index_->ListAvailableMetadata(md, a[4]); ASSERT_EQ(1u, md.size()); ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front()); index_->GetAllMetadata(md2, a[4]); ASSERT_EQ(1u, md2.size()); ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]); ASSERT_EQ(21u + 42u + 44u, index_->GetTotalCompressedSize()); ASSERT_EQ(42u + 42u + 44u, index_->GetTotalUncompressedSize()); index_->SetMainDicomTag(a[3], DicomTag(0x0010, 0x0010), "PatientName"); int64_t b; ResourceType t; ASSERT_TRUE(index_->LookupResource(b, t, "g")); ASSERT_EQ(7, b); ASSERT_EQ(ResourceType_Study, t); ASSERT_TRUE(index_->LookupMetadata(s, a[4], MetadataType_Instance_RemoteAet)); ASSERT_FALSE(index_->LookupMetadata(s, a[4], MetadataType_Instance_IndexInSeries)); ASSERT_EQ("PINNACLE", s); std::string u; ASSERT_TRUE(index_->LookupMetadata(u, a[4], MetadataType_Instance_RemoteAet)); ASSERT_EQ("PINNACLE", u); ASSERT_FALSE(index_->LookupMetadata(u, a[4], MetadataType_Instance_IndexInSeries)); ASSERT_TRUE(index_->LookupGlobalProperty(s, GlobalProperty_FlushSleep)); ASSERT_FALSE(index_->LookupGlobalProperty(s, static_cast<GlobalProperty>(42))); ASSERT_EQ("World", s); FileInfo att; ASSERT_TRUE(index_->LookupAttachment(att, a[4], FileContentType_DicomAsJson)); ASSERT_EQ("my json file", att.GetUuid()); ASSERT_EQ(21u, att.GetCompressedSize()); ASSERT_EQ("md5", att.GetUncompressedMD5()); ASSERT_EQ("compressedMD5", att.GetCompressedMD5()); ASSERT_EQ(42u, att.GetUncompressedSize()); ASSERT_EQ(CompressionType_Zlib, att.GetCompressionType()); ASSERT_TRUE(index_->LookupAttachment(att, a[6], FileContentType_Dicom)); ASSERT_EQ("world", att.GetUuid()); ASSERT_EQ(44u, att.GetCompressedSize()); ASSERT_EQ("md5", att.GetUncompressedMD5()); ASSERT_EQ("md5", att.GetCompressedMD5()); ASSERT_EQ(44u, att.GetUncompressedSize()); ASSERT_EQ(CompressionType_None, att.GetCompressionType()); ASSERT_EQ(0u, listener_->deletedFiles_.size()); ASSERT_EQ(0u, listener_->deletedResources_.size()); CheckTableRecordCount(7, "Resources"); CheckTableRecordCount(3, "AttachedFiles"); CheckTableRecordCount(1, "Metadata"); CheckTableRecordCount(1, "MainDicomTags"); index_->DeleteResource(a[0]); ASSERT_EQ(5u, listener_->deletedResources_.size()); ASSERT_EQ(2u, listener_->deletedFiles_.size()); ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), listener_->deletedFiles_.end(), "my json file") == listener_->deletedFiles_.end()); ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), listener_->deletedFiles_.end(), "my dicom file") == listener_->deletedFiles_.end()); CheckTableRecordCount(2, "Resources"); CheckTableRecordCount(0, "Metadata"); CheckTableRecordCount(1, "AttachedFiles"); CheckTableRecordCount(0, "MainDicomTags"); index_->DeleteResource(a[5]); ASSERT_EQ(7u, listener_->deletedResources_.size()); CheckTableRecordCount(0, "Resources"); CheckTableRecordCount(0, "AttachedFiles"); CheckTableRecordCount(2, "GlobalProperties"); ASSERT_EQ(3u, listener_->deletedFiles_.size()); ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), listener_->deletedFiles_.end(), "world") == listener_->deletedFiles_.end()); }