2015-09-06 19:57:33 +02:00
|
|
|
#include "./abstractattachment.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./mediafileinfo.h"
|
|
|
|
#include "./exceptions.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-10-06 22:30:05 +02:00
|
|
|
#include <c++utilities/misc/memory.h>
|
2016-06-14 22:53:43 +02:00
|
|
|
#include <c++utilities/io/catchiofailure.h>
|
2016-08-04 00:16:19 +02:00
|
|
|
#include <c++utilities/io/copy.h>
|
2015-10-06 22:30:05 +02:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
using namespace std;
|
2016-08-04 00:16:19 +02:00
|
|
|
using namespace IoUtilities;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
namespace Media {
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \class Media::StreamDataBlock
|
|
|
|
* \brief The StreamDataBlock class is a reference to a certain data block of a stream.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new StreamDataBlock.
|
|
|
|
*
|
|
|
|
* The derived is responsible for the prober initialization of the object.
|
|
|
|
*/
|
|
|
|
StreamDataBlock::StreamDataBlock() :
|
|
|
|
m_stream(nullptr),
|
|
|
|
m_startOffset(0),
|
|
|
|
m_endOffset(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new StreamDataBlock with the specified \a stream and offsets.
|
|
|
|
*
|
|
|
|
* The \a stream must be provided as function returning a reference the associated stream. This way of passing the stream
|
|
|
|
* allows the caller to change the stream without the need to update all StreamDataBlock objects
|
|
|
|
* referring to the stream. This is required when rewriting a file because during rewriting the original file
|
|
|
|
* gets renamed and then reopend with another stream object.
|
|
|
|
*
|
|
|
|
* The object does NOT take ownership over the stream returned by the specified function.
|
|
|
|
*/
|
2016-06-10 23:08:01 +02:00
|
|
|
StreamDataBlock::StreamDataBlock(const std::function<std::istream & ()> &stream, std::istream::off_type startOffset, std::ios_base::seekdir startDir, std::istream::off_type endOffset, std::ios_base::seekdir endDir) :
|
2015-04-22 19:22:01 +02:00
|
|
|
m_stream(stream)
|
|
|
|
{
|
|
|
|
auto &s = stream();
|
|
|
|
auto currentPos = s.tellg();
|
|
|
|
s.seekg(startOffset, startDir);
|
|
|
|
m_startOffset = s.tellg();
|
|
|
|
s.seekg(endOffset, endDir);
|
|
|
|
m_endOffset = s.tellg();
|
|
|
|
s.seekg(currentPos);
|
|
|
|
if(m_endOffset < m_startOffset) {
|
2016-06-14 22:53:43 +02:00
|
|
|
IoUtilities::throwIoFailure("End offset is less then start offset.");
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-26 14:22:44 +01:00
|
|
|
/*!
|
|
|
|
* \brief Buffers the data block. Buffered data can be accessed via buffer().
|
|
|
|
*/
|
|
|
|
void StreamDataBlock::makeBuffer() const
|
|
|
|
{
|
|
|
|
m_buffer = make_unique<char[]>(size());
|
|
|
|
stream().seekg(startOffset());
|
|
|
|
stream().read(m_buffer.get(), size());
|
|
|
|
}
|
|
|
|
|
2016-08-04 00:16:19 +02:00
|
|
|
/*!
|
|
|
|
* \brief Copies the data to the specified \a stream.
|
|
|
|
* \remarks Makes use of the buffer allocated with makeBuffer() if this method has been called before.
|
|
|
|
*/
|
|
|
|
void StreamDataBlock::copyTo(ostream &stream) const
|
|
|
|
{
|
|
|
|
if(buffer()) {
|
|
|
|
stream.write(buffer().get(), size());
|
|
|
|
} else {
|
|
|
|
CopyHelper<0x2000> copyHelper;
|
|
|
|
m_stream().seekg(startOffset());
|
|
|
|
copyHelper.copy(m_stream(), stream, size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \class Media::FileDataBlock
|
|
|
|
* \brief The FileDataBlock class is a reference to a certain data block of a file stream.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new FileDataBlock with the specified \a path.
|
|
|
|
*
|
|
|
|
* Opens a file stream with the specified \a path.
|
|
|
|
*
|
|
|
|
* \throws Throws ios_base::failure when an IO error occurs.
|
|
|
|
*/
|
|
|
|
FileDataBlock::FileDataBlock(const string &path) :
|
|
|
|
m_fileInfo(new MediaFileInfo)
|
|
|
|
{
|
|
|
|
m_fileInfo->setPath(path);
|
|
|
|
m_fileInfo->open(true);
|
|
|
|
m_fileInfo->parseContainerFormat();
|
|
|
|
m_startOffset = 0;
|
|
|
|
m_endOffset = m_fileInfo->size();
|
|
|
|
m_stream = [this] () -> std::istream & {
|
|
|
|
return this->m_fileInfo->stream();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \class Media::AbstractAttachment
|
|
|
|
* \brief The AbstractAttachment class parses and stores attachment information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns a label for the track.
|
|
|
|
*/
|
|
|
|
string AbstractAttachment::label() const
|
|
|
|
{
|
|
|
|
stringstream ss;
|
|
|
|
ss << "ID: " << id();
|
|
|
|
if(!name().empty()) {
|
|
|
|
ss << ", name: \"" << name() << "\"";
|
|
|
|
}
|
|
|
|
if(!mimeType().empty()) {
|
|
|
|
ss << ", mime-type: \"" << mimeType() << "\"";
|
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Resets the object to its initial state.
|
|
|
|
*/
|
|
|
|
void AbstractAttachment::clear()
|
|
|
|
{
|
|
|
|
m_description.clear();
|
|
|
|
m_name.clear();
|
|
|
|
m_mimeType.clear();
|
|
|
|
m_id = 0;
|
|
|
|
m_data.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the data, name and MIME-type for the specified \a path.
|
|
|
|
*
|
|
|
|
* A stream for the file with the specified \a path is opened (read-only).
|
|
|
|
* This stream will be freed by the attachment if the other data is assigned
|
|
|
|
* or the attachment gets destroyed.
|
|
|
|
*
|
|
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
|
|
|
* \throws Throws Media::Failure or a derived class when a parsing
|
|
|
|
* error occurs.
|
|
|
|
*
|
|
|
|
* When such an exception is thrown, the attachment remains unchanged.
|
|
|
|
*/
|
|
|
|
void AbstractAttachment::setFile(const std::string &path)
|
|
|
|
{
|
2015-10-06 22:30:05 +02:00
|
|
|
m_data.reset();
|
|
|
|
auto file = make_unique<FileDataBlock>(path);
|
|
|
|
const auto fileName = file->fileInfo()->fileName();
|
2015-04-22 19:22:01 +02:00
|
|
|
if(!fileName.empty()) {
|
|
|
|
m_name = fileName;
|
|
|
|
}
|
2015-10-06 22:30:05 +02:00
|
|
|
const char *mimeType = file->fileInfo()->mimeType();
|
2015-04-22 19:22:01 +02:00
|
|
|
if(*mimeType) {
|
|
|
|
m_mimeType = mimeType;
|
|
|
|
}
|
2015-10-06 22:30:05 +02:00
|
|
|
m_data = move(file);
|
2015-11-26 14:22:44 +01:00
|
|
|
m_isDataFromFile = true;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Media
|
|
|
|
|