tagparser/flac/flacmetadata.cpp

146 lines
5.2 KiB
C++
Raw Normal View History

2016-05-14 00:24:01 +02:00
#include "./flacmetadata.h"
#include "../exceptions.h"
#include "../tagvalue.h"
#include <c++utilities/conversion/binaryconversion.h>
#include <c++utilities/io/binaryreader.h>
#include <c++utilities/io/binarywriter.h>
2018-03-07 01:17:50 +01:00
#include <c++utilities/io/bitreader.h>
2016-05-14 00:24:01 +02:00
#include <cstring>
2017-02-05 21:02:40 +01:00
#include <memory>
2016-05-14 00:24:01 +02:00
using namespace std;
2019-06-10 22:49:11 +02:00
using namespace CppUtilities;
2016-05-14 00:24:01 +02:00
namespace TagParser {
2016-05-14 00:24:01 +02:00
/*!
* \class TagParser::FlacMetaDataBlockHeader
2016-05-14 00:24:01 +02:00
* \brief The FlacMetaDataBlockHeader class is a FLAC "METADATA_BLOCK_HEADER" parser and maker.
* \sa https://xiph.org/flac/format.html
*/
/*!
* \brief Parses the FLAC "METADATA_BLOCK_HEADER" which is read using the specified \a iterator.
* \remarks The specified \a buffer must be at least 4 bytes long.
*/
void FlacMetaDataBlockHeader::parseHeader(std::string_view buffer)
2016-05-14 00:24:01 +02:00
{
2021-03-20 21:26:25 +01:00
m_last = static_cast<std::uint8_t>(buffer[0] & 0x80);
m_type = static_cast<std::uint8_t>(buffer[0] & (0x80 - 1));
m_dataSize = BE::toUInt24(buffer.data() + 1);
2016-05-14 00:24:01 +02:00
}
/*!
* \brief Writes the header to the specified \a outputStream.
* \remarks Writes always 4 bytes.
*/
void FlacMetaDataBlockHeader::makeHeader(std::ostream &outputStream)
{
2019-03-13 19:06:42 +01:00
std::uint8_t buff[4];
2016-05-14 00:24:01 +02:00
*buff = (m_last ? (0x80 | m_type) : m_type);
BE::getBytes24(m_dataSize, reinterpret_cast<char *>(buff) + 1);
outputStream.write(reinterpret_cast<char *>(buff), sizeof(buff));
}
/*!
* \class TagParser::FlacMetaDataBlockStreamInfo
2016-05-14 00:24:01 +02:00
* \brief The FlacMetaDataBlockStreamInfo class is a FLAC "METADATA_BLOCK_STREAMINFO" parser.
* \sa https://xiph.org/flac/format.html
*/
/*!
* \brief Parses the FLAC "METADATA_BLOCK_STREAMINFO" which is read using the specified \a iterator.
2016-05-16 20:56:53 +02:00
* \remarks The specified \a buffer must be at least 0x22 bytes long.
2016-05-14 00:24:01 +02:00
*/
void FlacMetaDataBlockStreamInfo::parse(std::string_view buffer)
2016-05-14 00:24:01 +02:00
{
auto reader = BitReader(buffer.data(), 0x22);
2019-03-13 19:06:42 +01:00
m_minBlockSize = reader.readBits<std::uint16_t>(16);
m_maxBlockSize = reader.readBits<std::uint16_t>(16);
m_minFrameSize = reader.readBits<std::uint32_t>(24);
m_maxFrameSize = reader.readBits<std::uint32_t>(24);
m_samplingFrequency = reader.readBits<std::uint32_t>(20);
m_channelCount = reader.readBits<std::uint8_t>(3) + 1;
m_bitsPerSample = reader.readBits<std::uint8_t>(5) + 1;
m_totalSampleCount = reader.readBits<std::uint64_t>(36);
2021-03-20 21:26:25 +01:00
std::memcpy(m_md5Sum, buffer.data() + 0x22u - sizeof(m_md5Sum), sizeof(m_md5Sum));
2016-05-14 00:24:01 +02:00
}
/*!
* \class TagParser::FlacMetaDataBlockPicture
2016-05-14 00:24:01 +02:00
* \brief The FlacMetaDataBlockPicture class is a FLAC "METADATA_BLOCK_PICTURE" parser and maker.
* \sa https://xiph.org/flac/format.html
*/
/*!
* \brief Parses the FLAC "METADATA_BLOCK_PICTURE".
2016-05-16 20:56:53 +02:00
*
* \a maxSize specifies the maximum size of the structure.
2016-05-14 00:24:01 +02:00
*/
2019-03-13 19:06:42 +01:00
void FlacMetaDataBlockPicture::parse(istream &inputStream, std::uint32_t maxSize)
2016-05-14 00:24:01 +02:00
{
2016-05-16 20:56:53 +02:00
CHECK_MAX_SIZE(32);
2016-05-14 00:24:01 +02:00
BinaryReader reader(&inputStream);
m_pictureType = reader.readUInt32BE();
2019-03-13 19:06:42 +01:00
std::uint32_t size = reader.readUInt32BE();
2016-05-16 20:56:53 +02:00
CHECK_MAX_SIZE(size);
2016-05-14 00:24:01 +02:00
m_value.setMimeType(reader.readString(size));
size = reader.readUInt32BE();
2016-05-16 20:56:53 +02:00
CHECK_MAX_SIZE(size);
2016-05-14 00:24:01 +02:00
m_value.setDescription(reader.readString(size));
// skip width, height, color depth, number of colors used
inputStream.seekg(4 * 4, ios_base::cur);
size = reader.readUInt32BE();
2016-05-16 20:56:53 +02:00
CHECK_MAX_SIZE(size);
2018-03-07 01:17:50 +01:00
if (size) {
auto data = make_unique<char[]>(size);
inputStream.read(data.get(), size);
m_value.assignData(move(data), size, TagDataType::Picture);
} else {
m_value.clearData();
}
2016-05-14 00:24:01 +02:00
}
/*!
* \brief Returns the number of bytes make() will write.
* \remarks Any changes to the object will invalidate this value.
* \throws Throws an InvalidDataException() if the assigned data is too big.
2016-05-14 00:24:01 +02:00
*/
2019-03-13 19:06:42 +01:00
std::uint32_t FlacMetaDataBlockPicture::requiredSize() const
2016-05-14 00:24:01 +02:00
{
const auto requiredSize(32 + m_value.mimeType().size() + m_value.description().size() + m_value.dataSize());
2019-03-13 19:06:42 +01:00
if (requiredSize > numeric_limits<std::uint32_t>::max()) {
throw InvalidDataException();
}
2019-03-13 19:06:42 +01:00
return static_cast<std::uint32_t>(requiredSize);
2016-05-14 00:24:01 +02:00
}
/*!
* \brief Makes the FLAC "METADATA_BLOCK_PICTURE".
* \throws Throws an InvalidDataException() if the assigned data can not be serialized into a "METADATA_BLOCK_PICTURE" structure.
2016-05-14 00:24:01 +02:00
*/
void FlacMetaDataBlockPicture::make(ostream &outputStream)
{
2019-03-13 19:06:42 +01:00
if (m_value.mimeType().size() > numeric_limits<std::uint32_t>::max() || m_value.description().size() > numeric_limits<std::uint32_t>::max()
|| m_value.dataSize() > numeric_limits<std::uint32_t>::max()) {
throw InvalidDataException();
}
2016-05-14 00:24:01 +02:00
BinaryWriter writer(&outputStream);
writer.writeUInt32BE(pictureType());
2019-03-13 19:06:42 +01:00
writer.writeUInt32BE(static_cast<std::uint32_t>(m_value.mimeType().size()));
2016-05-14 00:24:01 +02:00
writer.writeString(m_value.mimeType());
2019-03-13 19:06:42 +01:00
writer.writeUInt32BE(static_cast<std::uint32_t>(m_value.description().size()));
2016-05-14 00:24:01 +02:00
writer.writeString(m_value.description());
writer.writeUInt32BE(0); // skip width
writer.writeUInt32BE(0); // skip height
writer.writeUInt32BE(0); // skip color depth
writer.writeUInt32BE(0); // skip number of colors used
2019-03-13 19:06:42 +01:00
writer.writeUInt32BE(static_cast<std::uint32_t>(m_value.dataSize()));
writer.write(value().dataPointer(), static_cast<streamoff>(m_value.dataSize()));
2016-05-14 00:24:01 +02:00
}
2018-03-07 01:17:50 +01:00
} // namespace TagParser