#include "./flacmetadata.h" #include "../exceptions.h" #include "../tagvalue.h" #include #include #include #include #include #include using namespace std; using namespace CppUtilities; namespace TagParser { /*! * \class TagParser::FlacMetaDataBlockHeader * \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(const char *buffer) { m_last = *buffer & 0x80; m_type = *buffer & (0x80 - 1); m_dataSize = BE::toUInt24(buffer + 1); } /*! * \brief Writes the header to the specified \a outputStream. * \remarks Writes always 4 bytes. */ void FlacMetaDataBlockHeader::makeHeader(std::ostream &outputStream) { std::uint8_t buff[4]; *buff = (m_last ? (0x80 | m_type) : m_type); BE::getBytes24(m_dataSize, reinterpret_cast(buff) + 1); outputStream.write(reinterpret_cast(buff), sizeof(buff)); } /*! * \class TagParser::FlacMetaDataBlockStreamInfo * \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. * \remarks The specified \a buffer must be at least 0x22 bytes long. */ void FlacMetaDataBlockStreamInfo::parse(const char *buffer) { BitReader reader(buffer, 0x22); m_minBlockSize = reader.readBits(16); m_maxBlockSize = reader.readBits(16); m_minFrameSize = reader.readBits(24); m_maxFrameSize = reader.readBits(24); m_samplingFrequency = reader.readBits(20); m_channelCount = reader.readBits(3) + 1; m_bitsPerSample = reader.readBits(5) + 1; m_totalSampleCount = reader.readBits(36); memcpy(m_md5Sum, buffer + 0x22 - sizeof(m_md5Sum), sizeof(m_md5Sum)); } /*! * \class TagParser::FlacMetaDataBlockPicture * \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". * * \a maxSize specifies the maximum size of the structure. */ void FlacMetaDataBlockPicture::parse(istream &inputStream, std::uint32_t maxSize) { CHECK_MAX_SIZE(32); BinaryReader reader(&inputStream); m_pictureType = reader.readUInt32BE(); std::uint32_t size = reader.readUInt32BE(); CHECK_MAX_SIZE(size); m_value.setMimeType(reader.readString(size)); size = reader.readUInt32BE(); CHECK_MAX_SIZE(size); 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(); CHECK_MAX_SIZE(size); if (size) { auto data = make_unique(size); inputStream.read(data.get(), size); m_value.assignData(move(data), size, TagDataType::Picture); } else { m_value.clearData(); } } /*! * \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. */ std::uint32_t FlacMetaDataBlockPicture::requiredSize() const { const auto requiredSize(32 + m_value.mimeType().size() + m_value.description().size() + m_value.dataSize()); if (requiredSize > numeric_limits::max()) { throw InvalidDataException(); } return static_cast(requiredSize); } /*! * \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. */ void FlacMetaDataBlockPicture::make(ostream &outputStream) { if (m_value.mimeType().size() > numeric_limits::max() || m_value.description().size() > numeric_limits::max() || m_value.dataSize() > numeric_limits::max()) { throw InvalidDataException(); } BinaryWriter writer(&outputStream); writer.writeUInt32BE(pictureType()); writer.writeUInt32BE(static_cast(m_value.mimeType().size())); writer.writeString(m_value.mimeType()); writer.writeUInt32BE(static_cast(m_value.description().size())); 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 writer.writeUInt32BE(static_cast(m_value.dataSize())); writer.write(value().dataPointer(), static_cast(m_value.dataSize())); } } // namespace TagParser