/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2023 Osimis S.A., Belgium
* Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
* Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* .
**/
#include "../PrecompiledHeaders.h"
#include "MemoryStorageArea.h"
#include "../Logging.h"
#include "../OrthancException.h"
#include "../StringMemoryBuffer.h"
#include "../Toolbox.h"
namespace Orthanc
{
MemoryStorageArea::~MemoryStorageArea()
{
for (Content::iterator it = content_.begin(); it != content_.end(); ++it)
{
if (it->second != NULL)
{
delete it->second;
}
}
}
void MemoryStorageArea::Create(const std::string& uuid,
const void* content,
size_t size,
FileContentType type)
{
LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << static_cast(type)
<< "\" type (size: " << Toolbox::GetHumanFileSize(size) << ")";
Mutex::ScopedLock lock(mutex_);
if (size != 0 &&
content == NULL)
{
throw OrthancException(ErrorCode_NullPointer);
}
else if (content_.find(uuid) != content_.end())
{
throw OrthancException(ErrorCode_InternalError);
}
else
{
content_[uuid] = new std::string(reinterpret_cast(content), size);
}
}
IMemoryBuffer* MemoryStorageArea::ReadRange(const std::string& uuid,
FileContentType type,
uint64_t start /* inclusive */,
uint64_t end /* exclusive */)
{
LOG(INFO) << "Reading attachment \"" << uuid << "\" of \""
<< static_cast(type) << "\" content type "
<< "(range from " << start << " to " << end << ")";
if (start > end)
{
throw OrthancException(ErrorCode_BadRange);
}
else if (start == end)
{
return new StringMemoryBuffer;
}
else
{
const uint64_t size = end - start;
if (static_cast(static_cast(size)) != size)
{
throw OrthancException(ErrorCode_InternalError, "Buffer larger than 4GB, which is too large for Orthanc running in 32bits");
}
Mutex::ScopedLock lock(mutex_);
Content::const_iterator found = content_.find(uuid);
if (found == content_.end())
{
throw OrthancException(ErrorCode_InexistentFile);
}
else if (found->second == NULL)
{
throw OrthancException(ErrorCode_InternalError);
}
else if (end > found->second->size())
{
throw OrthancException(ErrorCode_BadRange);
}
else
{
std::string range;
range.resize(static_cast(size));
assert(!range.empty());
memcpy(&range[0], &found->second[start], range.size());
return StringMemoryBuffer::CreateFromSwap(range);
}
}
}
void MemoryStorageArea::Remove(const std::string& uuid,
FileContentType type)
{
LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast(type);
Mutex::ScopedLock lock(mutex_);
Content::iterator found = content_.find(uuid);
if (found == content_.end())
{
// Ignore second removal
}
else if (found->second == NULL)
{
throw OrthancException(ErrorCode_InternalError);
}
else
{
delete found->second;
content_.erase(found);
}
}
}