2018-03-06 23:09:15 +01:00
|
|
|
#ifndef TAG_PARSER_ID3V2FRAME_H
|
|
|
|
#define TAG_PARSER_ID3V2FRAME_H
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./id3v2frameids.h"
|
2015-09-06 15:42:18 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "../generictagfield.h"
|
|
|
|
#include "../tagvalue.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <c++utilities/io/binaryreader.h>
|
|
|
|
#include <c++utilities/io/binarywriter.h>
|
|
|
|
|
2016-05-16 20:56:53 +02:00
|
|
|
#include <iosfwd>
|
2018-03-07 01:17:50 +01:00
|
|
|
#include <string>
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
namespace TagParser {
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
class Id3v2Frame;
|
2018-03-05 17:49:29 +01:00
|
|
|
class Diagnostics;
|
2015-12-22 23:54:35 +01:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
class TAG_PARSER_EXPORT Id3v2FrameMaker {
|
2015-12-22 23:54:35 +01:00
|
|
|
friend class Id3v2Frame;
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
public:
|
2019-06-10 22:49:11 +02:00
|
|
|
void make(CppUtilities::BinaryWriter &writer);
|
2015-12-22 23:54:35 +01:00
|
|
|
const Id3v2Frame &field() const;
|
|
|
|
const std::unique_ptr<char[]> &data() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t dataSize() const;
|
|
|
|
std::uint32_t requiredSize() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
private:
|
2019-03-13 19:06:42 +01:00
|
|
|
Id3v2FrameMaker(Id3v2Frame &frame, std::uint8_t version, Diagnostics &diag);
|
2018-07-01 23:06:36 +02:00
|
|
|
void makeSubstring(const TagValue &value, Diagnostics &diag, const std::string &context);
|
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
Id3v2Frame &m_frame;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t m_frameId;
|
|
|
|
const std::uint8_t m_version;
|
2015-12-22 23:54:35 +01:00
|
|
|
std::unique_ptr<char[]> m_data;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t m_dataSize;
|
|
|
|
std::uint32_t m_decompressedSize;
|
|
|
|
std::uint32_t m_requiredSize;
|
2015-12-22 23:54:35 +01:00
|
|
|
};
|
2015-12-22 17:01:25 +01:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the associated frame.
|
|
|
|
*/
|
|
|
|
inline const Id3v2Frame &Id3v2FrameMaker::field() const
|
|
|
|
{
|
|
|
|
return m_frame;
|
|
|
|
}
|
2015-12-22 17:01:25 +01:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the frame data.
|
|
|
|
*/
|
|
|
|
inline const std::unique_ptr<char[]> &Id3v2FrameMaker::data() const
|
|
|
|
{
|
|
|
|
return m_data;
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the size of the array returned by data().
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint32_t Id3v2FrameMaker::dataSize() const
|
2015-12-22 23:54:35 +01:00
|
|
|
{
|
|
|
|
return m_dataSize;
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns number of bytes which will be written when making the frame.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint32_t Id3v2FrameMaker::requiredSize() const
|
2015-12-22 23:54:35 +01:00
|
|
|
{
|
|
|
|
return m_requiredSize;
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Defines traits for the TagField implementation of the Id3v2Frame class.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <> class TAG_PARSER_EXPORT TagFieldTraits<Id3v2Frame> {
|
2015-04-22 19:22:01 +02:00
|
|
|
public:
|
2019-03-13 19:06:42 +01:00
|
|
|
using IdentifierType = std::uint32_t;
|
|
|
|
using TypeInfoType = std::uint8_t;
|
2015-04-22 19:22:01 +02:00
|
|
|
};
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
class TAG_PARSER_EXPORT Id3v2Frame : public TagField<Id3v2Frame> {
|
2015-04-22 19:22:01 +02:00
|
|
|
friend class TagField<Id3v2Frame>;
|
2018-07-01 23:06:36 +02:00
|
|
|
friend class Id3v2FrameMaker;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
Id3v2Frame();
|
2019-03-13 19:06:42 +01:00
|
|
|
Id3v2Frame(const IdentifierType &id, const TagValue &value, std::uint8_t group = 0, std::uint16_t flag = 0);
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
// parsing/making
|
2019-06-10 22:49:11 +02:00
|
|
|
void parse(CppUtilities::BinaryReader &reader, std::uint32_t version, std::uint32_t maximalSize, Diagnostics &diag);
|
2019-03-13 19:06:42 +01:00
|
|
|
Id3v2FrameMaker prepareMaking(std::uint8_t version, Diagnostics &diag);
|
2019-06-10 22:49:11 +02:00
|
|
|
void make(CppUtilities::BinaryWriter &writer, std::uint8_t version, Diagnostics &diag);
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
// member access
|
2018-07-01 23:06:36 +02:00
|
|
|
const std::vector<TagValue> &additionalValues() const;
|
|
|
|
std::vector<TagValue> &additionalValues();
|
2015-04-22 19:22:01 +02:00
|
|
|
bool isAdditionalTypeInfoUsed() const;
|
|
|
|
bool isValid() const;
|
|
|
|
bool hasPaddingReached() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint16_t flag() const;
|
|
|
|
void setFlag(std::uint16_t value);
|
|
|
|
std::uint32_t totalSize() const;
|
|
|
|
std::uint32_t dataSize() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool toDiscardWhenUnknownAndTagIsAltered() const;
|
|
|
|
bool toDiscardWhenUnknownAndFileIsAltered() const;
|
|
|
|
bool isReadOnly() const;
|
|
|
|
bool isCompressed() const;
|
|
|
|
bool isEncrypted() const;
|
|
|
|
bool hasGroupInformation() const;
|
|
|
|
bool isUnsynchronized() const;
|
|
|
|
bool hasDataLengthIndicator() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint8_t group() const;
|
|
|
|
void setGroup(std::uint8_t value);
|
|
|
|
std::uint32_t parsedVersion() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool supportsNestedFields() const;
|
|
|
|
|
2015-12-22 23:54:35 +01:00
|
|
|
// parsing helper
|
2019-03-13 19:06:42 +01:00
|
|
|
TagTextEncoding parseTextEncodingByte(std::uint8_t textEncodingByte, Diagnostics &diag);
|
2018-07-01 02:04:29 +02:00
|
|
|
std::tuple<const char *, std::size_t, const char *> parseSubstring(
|
2018-03-07 01:17:50 +01:00
|
|
|
const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag);
|
2018-03-05 17:49:29 +01:00
|
|
|
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag);
|
|
|
|
std::u16string parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag);
|
2019-03-13 19:06:42 +01:00
|
|
|
void parseLegacyPicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, std::uint8_t &typeInfo, Diagnostics &diag);
|
|
|
|
void parsePicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, std::uint8_t &typeInfo, Diagnostics &diag);
|
2018-03-05 17:49:29 +01:00
|
|
|
void parseComment(const char *buffer, std::size_t maxSize, TagValue &tagValue, Diagnostics &diag);
|
|
|
|
void parseBom(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, Diagnostics &diag);
|
2015-12-22 23:54:35 +01:00
|
|
|
|
|
|
|
// making helper
|
2019-03-13 19:06:42 +01:00
|
|
|
static std::uint8_t makeTextEncodingByte(TagTextEncoding textEncoding);
|
2018-07-01 23:06:36 +02:00
|
|
|
static std::size_t makeBom(char *buffer, TagTextEncoding encoding);
|
2019-06-01 22:26:16 +02:00
|
|
|
static void makeLegacyPicture(
|
|
|
|
std::unique_ptr<char[]> &buffer, std::uint32_t &bufferSize, const TagValue &picture, std::uint8_t typeInfo, Diagnostics &diag);
|
|
|
|
static void makePicture(std::unique_ptr<char[]> &buffer, std::uint32_t &bufferSize, const TagValue &picture, std::uint8_t typeInfo,
|
|
|
|
std::uint8_t version, Diagnostics &diag);
|
2019-03-13 19:06:42 +01:00
|
|
|
static void makeComment(
|
|
|
|
std::unique_ptr<char[]> &buffer, std::uint32_t &bufferSize, const TagValue &comment, std::uint8_t version, Diagnostics &diag);
|
2015-12-22 23:54:35 +01:00
|
|
|
|
2021-01-30 21:53:06 +01:00
|
|
|
static IdentifierType fieldIdFromString(std::string_view idString);
|
2017-03-07 17:16:17 +01:00
|
|
|
static std::string fieldIdToString(IdentifierType id);
|
2017-01-23 00:25:53 +01:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
private:
|
2021-01-30 18:25:46 +01:00
|
|
|
void internallyClearValue();
|
|
|
|
void internallyClearFurtherData();
|
2018-07-01 23:06:36 +02:00
|
|
|
std::string ignoreAdditionalValuesDiagMsg() const;
|
|
|
|
|
|
|
|
std::vector<TagValue> m_additionalValues;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t m_parsedVersion;
|
|
|
|
std::uint32_t m_dataSize;
|
|
|
|
std::uint32_t m_totalSize;
|
|
|
|
std::uint16_t m_flag;
|
|
|
|
std::uint8_t m_group;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool m_padding;
|
|
|
|
};
|
|
|
|
|
2018-07-01 23:06:36 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns additional values.
|
|
|
|
* \remarks Frames might allow to store multiple values, eg. ID3v2.4 text frames allow to store multiple strings.
|
|
|
|
*/
|
|
|
|
inline const std::vector<TagValue> &Id3v2Frame::additionalValues() const
|
|
|
|
{
|
|
|
|
return m_additionalValues;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns additional values.
|
|
|
|
* \remarks Frames might allow to store multiple values, eg. ID3v2.4 text frames allow to store multiple strings.
|
|
|
|
*/
|
|
|
|
inline std::vector<TagValue> &Id3v2Frame::additionalValues()
|
|
|
|
{
|
|
|
|
return m_additionalValues;
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether the instance uses the additional type info.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isAdditionalTypeInfoUsed() const
|
|
|
|
{
|
|
|
|
return id() == Id3v2FrameIds::lCover || id() == Id3v2FrameIds::sCover;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame is valid.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isValid() const
|
|
|
|
{
|
|
|
|
return !(id() == 0 || value().isEmpty() || m_padding);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the padding has reached.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::hasPaddingReached() const
|
|
|
|
{
|
|
|
|
return m_padding;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the flags.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint16_t Id3v2Frame::flag() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the flags.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline void Id3v2Frame::setFlag(std::uint16_t value)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
m_flag = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2015-12-22 17:01:25 +01:00
|
|
|
* \brief Returns the total size of the frame in bytes.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint32_t Id3v2Frame::totalSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_totalSize;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the size of the data stored in the frame in bytes.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint32_t Id3v2Frame::dataSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_dataSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-07-02 03:00:50 +02:00
|
|
|
* \brief Returns whether the frame is flagged to be discarded when it is unknown and the tag is altered.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::toDiscardWhenUnknownAndTagIsAltered() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_flag & 0x8000;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-07-02 03:00:50 +02:00
|
|
|
* \brief Returns whether the frame is flagged to be discarded when it is unknown and the file (but NOT the tag) is altered.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::toDiscardWhenUnknownAndFileIsAltered() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_flag & 0x4000;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame is flagged as read-only.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isReadOnly() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_flag & 0x2000;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame is compressed.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isCompressed() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_parsedVersion >= 4 ? m_flag & 0x8 : m_flag & 0x80;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame is encrypted.
|
|
|
|
* \remarks Reading encrypted frames is not supported.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isEncrypted() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_parsedVersion >= 4 ? m_flag & 0x4 : m_flag & 0x40;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame contains group information.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::hasGroupInformation() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_parsedVersion >= 4 ? m_flag & 0x40 : m_flag & 0x20;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame is unsynchronized.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::isUnsynchronized() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_parsedVersion >= 4 ? m_flag & 0x2 : false;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the frame has a data length indicator.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::hasDataLengthIndicator() const
|
|
|
|
{
|
2015-12-22 17:01:25 +01:00
|
|
|
return m_parsedVersion >= 4 ? m_flag & 0x1 : isCompressed();
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the group.
|
|
|
|
* \sa hasGroupInformation()
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint8_t Id3v2Frame::group() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_group;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Sets the group information.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline void Id3v2Frame::setGroup(std::uint8_t value)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
m_group = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the version of the frame (read when parsing the frame).
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
inline std::uint32_t Id3v2Frame::parsedVersion() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_parsedVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether nested fields are supported.
|
|
|
|
*/
|
|
|
|
inline bool Id3v2Frame::supportsNestedFields() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-23 00:25:53 +01:00
|
|
|
/*!
|
|
|
|
* \brief Converts the specified ID string representation to an actual ID.
|
|
|
|
*/
|
2021-01-30 21:53:06 +01:00
|
|
|
inline Id3v2Frame::IdentifierType Id3v2Frame::fieldIdFromString(std::string_view idString)
|
2017-01-23 00:25:53 +01:00
|
|
|
{
|
2021-01-30 21:53:06 +01:00
|
|
|
switch (idString.size()) {
|
2017-01-23 00:25:53 +01:00
|
|
|
case 3:
|
2021-01-30 21:53:06 +01:00
|
|
|
return CppUtilities::BE::toUInt24(idString.data());
|
2017-01-23 00:25:53 +01:00
|
|
|
case 4:
|
2021-01-30 21:53:06 +01:00
|
|
|
return CppUtilities::BE::toUInt32(idString.data());
|
2017-01-23 00:25:53 +01:00
|
|
|
default:
|
2019-06-10 22:49:11 +02:00
|
|
|
throw CppUtilities::ConversionException("ID3v2 ID must be 3 or 4 chars");
|
2017-01-23 00:25:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the string representation for the specified \a id.
|
|
|
|
*/
|
2017-03-07 17:16:17 +01:00
|
|
|
inline std::string Id3v2Frame::fieldIdToString(Id3v2Frame::IdentifierType id)
|
2017-01-23 00:25:53 +01:00
|
|
|
{
|
2019-06-10 22:49:11 +02:00
|
|
|
return CppUtilities::interpretIntegerAsString<std::uint32_t>(id, Id3v2FrameIds::isLongId(id) ? 0 : 1);
|
2017-01-23 00:25:53 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
} // namespace TagParser
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
#endif // TAG_PARSER_ID3V2FRAME_H
|