5 #include "../diagnostics.h"
6 #include "../exceptions.h"
8 #include <c++utilities/conversion/stringbuilder.h>
9 #include <c++utilities/conversion/stringconversion.h>
24 namespace Id3v2TextEncodingBytes {
25 enum Id3v2TextEncodingByte : std::uint8_t { Ascii, Utf16WithBom, Utf16BigEndianWithoutBom,
Utf8 };
40 Id3v2Frame::Id3v2Frame()
71 for (
auto c : denotation) {
82 if (c >=
'0' && c <=
'9') {
95 if (c >=
'0' && c <=
'9') {
96 index = index * 10 + c -
'0';
111 return string(get<0>(substr), get<1>(substr));
119 u16string res(
reinterpret_cast<u16string::const_pointer
>(get<0>(substr)), get<1>(substr) / 2);
136 static const string defaultContext(
"parsing ID3v2 frame");
143 setId(reader.readUInt24BE());
144 if (
id() & 0xFFFF0000u) {
153 context =
"parsing " %
idToString() +
" frame";
156 m_dataSize = reader.readUInt24BE();
157 m_totalSize = m_dataSize + 6;
158 if (m_totalSize > maximalSize) {
159 diag.emplace_back(
DiagLevel::Warning,
"The frame is truncated and will be ignored.", context);
170 setId(reader.readUInt32BE());
171 if (
id() & 0xFF000000u) {
180 context =
"parsing " %
idToString() +
" frame";
183 m_dataSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
184 m_totalSize = m_dataSize + 10;
185 if (m_totalSize > maximalSize) {
186 diag.emplace_back(
DiagLevel::Warning,
"The frame is truncated and will be ignored.", context);
191 m_flag = reader.readUInt16BE();
203 argsToString(
"The frame is only supported in ID3v2.4 and newer but the tag's version is ID3v2.",
version,
'.'), context);
206 argsToString(
"The frame is only supported in ID3v2.3 and older but the tag's version is ID3v2.",
version,
'.'), context);
210 if (m_dataSize <= 0) {
216 unique_ptr<char[]> buffer;
220 uLongf decompressedSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
221 if (decompressedSize < m_dataSize) {
222 diag.emplace_back(
DiagLevel::Critical,
"The decompressed size is smaller than the compressed size.", context);
225 const auto bufferCompressed = make_unique<char[]>(m_dataSize);
226 reader.read(bufferCompressed.get(), m_dataSize);
227 buffer = make_unique<char[]>(decompressedSize);
229 uncompress(
reinterpret_cast<Bytef *
>(buffer.get()), &decompressedSize,
reinterpret_cast<Bytef *
>(bufferCompressed.get()), m_dataSize)) {
231 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
234 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
237 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The input data was corrupted or incomplete.", context);
246 diag.emplace_back(
DiagLevel::Critical,
"The decompressed data exceeds the maximum supported frame size.", context);
249 m_dataSize =
static_cast<std::uint32_t
>(decompressedSize);
251 buffer = make_unique<char[]>(m_dataSize);
252 reader.read(buffer.get(), m_dataSize);
261 const char *currentOffset = buffer.get() + 1;
262 for (
size_t currentIndex = 1; currentIndex < m_dataSize;) {
264 const auto substr(
parseSubstring(currentOffset, m_dataSize - currentIndex, dataEncoding,
false, diag));
267 if (!get<1>(substr)) {
268 if (currentIndex == 1) {
271 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
272 currentOffset = get<2>(substr);
278 if (this->
value().isEmpty()) {
279 return &this->
value();
281 m_additionalValues.emplace_back();
282 return &m_additionalValues.back();
295 }
catch (
const ConversionException &) {
296 diag.emplace_back(
DiagLevel::Warning,
"The value of track/disk position frame is not numeric and will be ignored.", context);
302 const auto milliseconds = [&] {
304 const auto parsedStringRef =
parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding,
false, diag);
306 ? convertUtf16BEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef))
307 : convertUtf16LEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef));
308 return string(convertedStringData.first.get(), convertedStringData.second);
314 }
catch (
const ConversionException &) {
315 diag.emplace_back(
DiagLevel::Warning,
"The value of the length frame is not numeric and will be ignored.", context);
320 const auto genreIndex = [&] {
327 if (genreIndex != -1) {
339 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
340 currentOffset = get<2>(substr);
344 if (
version < 4 && !m_additionalValues.empty()) {
346 DiagLevel::Warning,
"Multiple strings found though the tag is pre-ID3v2.4. " + ignoreAdditionalValuesDiagMsg(), context);
403 void Id3v2Frame::internallyClearValue()
406 m_additionalValues.clear();
412 void Id3v2Frame::internallyClearFurtherData()
425 std::string Id3v2Frame::ignoreAdditionalValuesDiagMsg()
const
427 if (m_additionalValues.size() == 1) {
428 return argsToString(
"Additional value \"", m_additionalValues.front().toString(
TagTextEncoding::Utf8),
"\" is supposed to be ignored.");
444 Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, std::uint8_t
version, Diagnostics &diag)
446 , m_frameId(m_frame.id())
449 const string context(
"making " % m_frame.idToString() +
" frame");
452 if (m_frame.isEncrypted()) {
453 diag.emplace_back(
DiagLevel::Critical,
"Cannot make an encrypted frame (isn't supported by this tagging library).", context);
454 throw InvalidDataException();
456 if (m_frame.hasPaddingReached()) {
457 diag.emplace_back(
DiagLevel::Critical,
"Cannot make a frame which is marked as padding.", context);
458 throw InvalidDataException();
460 if (
version < 3 && m_frame.isCompressed()) {
461 diag.emplace_back(
DiagLevel::Warning,
"Compression is not supported by the version of ID3v2 and won't be applied.", context);
463 if (
version < 3 && (m_frame.flag() || m_frame.group())) {
465 "The existing flag and group information is not supported by the version of ID3v2 and will be ignored/discarted.", context);
469 vector<const TagValue *> values;
470 values.reserve(1 + frame.additionalValues().size());
471 if (!frame.value().isEmpty()) {
472 values.emplace_back(&frame.value());
474 for (
const auto &
value : frame.additionalValues()) {
476 values.emplace_back(&
value);
481 if (values.empty()) {
482 throw NoDataProvidedException();
487 if (values.size() != 1) {
489 diag.emplace_back(
DiagLevel::Critical,
"Multiple values are not supported for non-text-frames.", context);
490 throw InvalidDataException();
493 DiagLevel::Warning,
"Multiple strings assigned to pre-ID3v2.4 text frame. " + frame.ignoreAdditionalValuesDiagMsg(), context);
503 "The short frame ID can't be converted to its long equivalent which is needed to use the frame in a newer version of ID3v2.",
505 throw InvalidDataException();
513 "The long frame ID can't be converted to its short equivalent which is needed to use the frame in the old version of ID3v2.",
515 throw InvalidDataException();
523 argsToString(
"The frame is only supported in ID3v2.4 and newer but version of the tag being written is ID3v2.",
version,
524 ". The frame is written nevertheless but other tools might not be able to deal with it."),
528 argsToString(
"The frame is only supported in ID3v2.3 and older but version of the tag being written is ID3v2.",
version,
529 ". The frame is written nevertheless but other tools might not be able to deal with it."),
537 vector<string> substrings;
538 substrings.reserve(1 + frame.additionalValues().size());
545 for (
const auto *
const value : values) {
554 }
catch (
const ConversionException &) {
556 argsToString(
"The track/disk number \"", substrings.back(),
"\" is not of the expected form, eg. \"4/10\"."), context);
563 for (
const auto *
const value : values) {
567 throw InvalidDataException();
569 substrings.emplace_back(numberToString(
static_cast<std::uint64_t
>(
duration.totalMilliseconds())));
575 for (
const auto *
const value : values) {
601 for (
const auto *
const value : values) {
616 const auto byteOrderMark = [&] {
619 return string({
'\xFF',
'\xFE' });
621 return string({
'\xFE',
'\xFF' });
626 const auto concatenatedSubstrings = joinStrings(substrings,
string(),
false, byteOrderMark,
string(terminationLength,
'\0'));
629 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<std::uint32_t
>(1 + concatenatedSubstrings.size()));
631 concatenatedSubstrings.copy(&m_data[1], concatenatedSubstrings.size());
635 m_frame.makePicture(m_data, m_decompressedSize, *values.front(), m_frame.isTypeInfoAssigned() ? m_frame.typeInfo() : 0,
version, diag);
641 m_frame.makeComment(m_data, m_decompressedSize, *values.front(),
version, diag);
645 const auto &
value(*values.front());
648 throw InvalidDataException();
650 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<std::uint32_t
>(
value.
dataSize()));
653 }
catch (
const ConversionException &) {
657 argsToString(
"Assigned value(s) \"",
DiagMessage::formatList(valuesAsString),
"\" can not be converted appropriately."), context);
658 }
catch (
const ConversionException &) {
659 diag.emplace_back(
DiagLevel::Critical,
"Assigned value(s) can not be converted appropriately.", context);
661 throw InvalidDataException();
665 if (
version >= 3 && m_frame.isCompressed()) {
666 auto compressedSize = compressBound(m_decompressedSize);
667 auto compressedData = make_unique<char[]>(compressedSize);
668 switch (compress(
reinterpret_cast<Bytef *
>(compressedData.get()),
reinterpret_cast<uLongf *
>(&compressedSize),
669 reinterpret_cast<Bytef *
>(m_data.get()), m_decompressedSize)) {
671 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
672 throw InvalidDataException();
674 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
675 throw InvalidDataException();
679 diag.emplace_back(
DiagLevel::Critical,
"Compressed size exceeds maximum data size.", context);
680 throw InvalidDataException();
682 m_data.swap(compressedData);
683 m_dataSize =
static_cast<std::uint32_t
>(compressedSize);
685 m_dataSize = m_decompressedSize;
690 m_requiredSize = m_dataSize;
696 m_requiredSize += 10;
698 if (m_frame.hasGroupInformation()) {
702 if (
version >= 3 && m_frame.isCompressed()) {
718 writer.writeUInt24BE(m_frameId);
719 writer.writeUInt24BE(m_dataSize);
721 writer.writeUInt32BE(m_frameId);
722 if (m_version >= 4) {
723 writer.writeSynchsafeUInt32BE(m_dataSize);
725 writer.writeUInt32BE(m_dataSize);
727 writer.writeUInt16BE(m_frame.
flag());
729 writer.writeByte(m_frame.
group());
732 if (m_version >= 4) {
733 writer.writeSynchsafeUInt32BE(m_decompressedSize);
735 writer.writeUInt32BE(m_decompressedSize);
739 writer.write(m_data.get(), m_dataSize);
750 switch (textEncodingByte) {
751 case Id3v2TextEncodingBytes::Ascii:
753 case Id3v2TextEncodingBytes::Utf16WithBom:
755 case Id3v2TextEncodingBytes::Utf16BigEndianWithoutBom:
771 switch (textEncoding) {
773 return Id3v2TextEncodingBytes::Ascii;
777 return Id3v2TextEncodingBytes::Utf16WithBom;
779 return Id3v2TextEncodingBytes::Utf16WithBom;
802 tuple<const char *, size_t, const char *> res(buffer, 0, buffer + bufferSize);
807 if ((bufferSize >= 3) && (BE::toUInt24(buffer) == 0x00EFBBBF)) {
809 diag.emplace_back(
DiagLevel::Critical,
"Denoted character set is Latin-1 but an UTF-8 BOM is present - assuming UTF-8.",
815 const char *pos = get<0>(res);
816 for (; *pos != 0x00; ++pos) {
817 if (pos < get<2>(res)) {
827 get<2>(res) = pos + 1;
832 if (bufferSize >= 2) {
833 switch (LE::toUInt16(buffer)) {
837 "Denoted character set is UTF-16 Big Endian but UTF-16 Little Endian BOM is present - assuming UTF-16 LE.",
848 const std::uint16_t *pos =
reinterpret_cast<const std::uint16_t *
>(get<0>(res));
849 for (; *pos != 0x0000; ++pos) {
850 if (pos <
reinterpret_cast<const std::uint16_t *
>(get<2>(res))) {
860 get<2>(res) =
reinterpret_cast<const char *
>(pos + 1);
901 if ((maxSize >= 2) && (BE::toUInt16(buffer) == 0xFFFE)) {
903 }
else if ((maxSize >= 2) && (BE::toUInt16(buffer) == 0xFEFF)) {
908 if ((maxSize >= 3) && (BE::toUInt24(buffer) == 0x00EFBBBF)) {
910 diag.emplace_back(
DiagLevel::Warning,
"UTF-8 byte order mark found in text frame.",
"parsing byte order mark of frame " +
idToString());
924 static const string context(
"parsing ID3v2.2 picture frame");
929 const char *end = buffer + maxSize;
931 typeInfo =
static_cast<unsigned char>(*(buffer + 4));
932 auto substr =
parseSubstring(buffer + 5,
static_cast<size_t>(end - 5 - buffer), dataEncoding,
true, diag);
933 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
934 if (get<2>(substr) >= end) {
935 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
950 static const string context(
"parsing ID3v2.3 picture frame");
951 const char *end = buffer + maxSize;
954 auto substr =
parseSubstring(buffer + 1, maxSize - 1, mimeTypeEncoding,
true, diag);
955 if (get<1>(substr)) {
956 tagValue.
setMimeType(
string(get<0>(substr), get<1>(substr)));
958 if (get<2>(substr) >= end) {
959 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (type info, description and actual data are missing).", context);
962 typeInfo =
static_cast<unsigned char>(*get<2>(substr));
963 if (++get<2>(substr) >= end) {
964 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (description and actual data are missing).", context);
967 substr =
parseSubstring(get<2>(substr),
static_cast<size_t>(end - get<2>(substr)), dataEncoding,
true, diag);
968 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
969 if (get<2>(substr) >= end) {
970 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
984 static const string context(
"parsing comment/unsynchronized lyrics frame");
985 const char *end = buffer +
dataSize;
995 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
996 if (get<2>(substr) > end) {
997 diag.emplace_back(
DiagLevel::Critical,
"Comment frame is incomplete (description not terminated?).", context);
1000 substr =
parseSubstring(get<2>(substr),
static_cast<size_t>(end - get<2>(substr)), dataEncoding,
false, diag);
1012 LE::getBytes(
static_cast<std::uint16_t
>(0xFEFF), buffer);
1015 BE::getBytes(
static_cast<std::uint16_t
>(0xFEFF), buffer);
1026 unique_ptr<
char[]> &buffer, std::uint32_t &bufferSize,
const TagValue &picture, std::uint8_t typeInfo,
Diagnostics &diag)
1030 StringData convertedDescription;
1031 string::size_type descriptionSize = picture.
description().find(
1033 if (descriptionSize == string::npos) {
1039 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1040 descriptionSize = convertedDescription.second;
1045 const auto requiredBufferSize = 1 + 3 + 1 + descriptionSize
1048 if (requiredBufferSize > numeric_limits<std::uint32_t>::max()) {
1049 diag.emplace_back(
DiagLevel::Critical,
"Required size exceeds maximum.",
"making legacy picture frame");
1052 buffer = make_unique<char[]>(bufferSize =
static_cast<std::uint32_t
>(requiredBufferSize));
1053 char *offset = buffer.get();
1059 const char *imageFormat;
1060 if (picture.
mimeType() ==
"image/jpeg") {
1061 imageFormat =
"JPG";
1062 }
else if (picture.
mimeType() ==
"image/png") {
1063 imageFormat =
"PNG";
1064 }
else if (picture.
mimeType() ==
"image/gif") {
1065 imageFormat =
"GIF";
1066 }
else if (picture.
mimeType() ==
"-->") {
1067 imageFormat = picture.
mimeType().data();
1069 imageFormat =
"UND";
1071 strncpy(++offset, imageFormat, 3);
1074 *(offset += 3) =
static_cast<char>(
typeInfo);
1077 offset +=
makeBom(offset + 1, descriptionEncoding);
1078 if (convertedDescription.first) {
1079 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1081 picture.
description().copy(++offset, descriptionSize);
1083 *(offset += descriptionSize) = 0x00;
1105 StringData convertedDescription;
1106 string::size_type descriptionSize = picture.
description().find(
1108 if (descriptionSize == string::npos) {
1114 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1115 descriptionSize = convertedDescription.second;
1118 string::size_type mimeTypeSize = picture.
mimeType().find(
'\0');
1119 if (mimeTypeSize == string::npos) {
1120 mimeTypeSize = picture.
mimeType().length();
1125 const auto requiredBufferSize = 1 + mimeTypeSize + 1 + 1 + descriptionSize
1128 if (requiredBufferSize > numeric_limits<uint32_t>::max()) {
1129 diag.emplace_back(
DiagLevel::Critical,
"Required size exceeds maximum.",
"making picture frame");
1132 buffer = make_unique<char[]>(bufferSize =
static_cast<uint32_t
>(requiredBufferSize));
1133 char *offset = buffer.get();
1139 picture.
mimeType().copy(++offset, mimeTypeSize);
1141 *(offset += mimeTypeSize) = 0x00;
1143 *(++offset) =
static_cast<char>(
typeInfo);
1146 offset +=
makeBom(offset + 1, descriptionEncoding);
1147 if (convertedDescription.first) {
1148 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1150 picture.
description().copy(++offset, descriptionSize);
1152 *(offset += descriptionSize) = 0x00;
1166 static const string context(
"making comment frame");
1170 if (!
comment.description().empty() && encoding !=
comment.descriptionEncoding()) {
1171 diag.emplace_back(
DiagLevel::Critical,
"Data encoding and description encoding aren't equal.", context);
1176 diag.emplace_back(
DiagLevel::Critical,
"The language must be 3 bytes long (ISO-639-2).", context);
1179 StringData convertedDescription;
1180 string::size_type descriptionSize =
comment.description().find(
1182 if (descriptionSize == string::npos) {
1183 descriptionSize =
comment.description().size();
1188 convertedDescription = convertUtf8ToUtf16LE(
comment.description().data(), descriptionSize);
1189 descriptionSize = convertedDescription.second;
1194 const auto data =
comment.toString(encoding);
1195 const auto requiredBufferSize = 1 + 3 + descriptionSize + data.size()
1197 if (requiredBufferSize > numeric_limits<uint32_t>::max()) {
1201 buffer = make_unique<char[]>(bufferSize =
static_cast<uint32_t
>(requiredBufferSize));
1202 char *offset = buffer.get();
1208 for (
unsigned int i = 0; i < 3; ++i) {
1213 offset +=
makeBom(offset + 1, encoding);
1214 if (convertedDescription.first) {
1215 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1217 comment.description().copy(++offset, descriptionSize);
1219 offset += descriptionSize;
1226 offset +=
makeBom(offset + 1, encoding);
1227 data.copy(++offset, data.size());
static std::string formatList(const std::vector< std::string > &values)
Concatenates the specified string values to a list.
The Diagnostics class is a container for DiagMessage.
The Id3v2FrameMaker class helps making ID3v2 frames.
void make(CppUtilities::BinaryWriter &writer)
Saves the frame (specified when constructing the object) using the specified writer.
The Id3v2Frame class is used by Id3v2Tag to store the fields.
bool isEncrypted() const
Returns whether the frame is encrypted.
static std::size_t makeBom(char *buffer, TagTextEncoding encoding)
Writes the BOM for the specified encoding to the specified buffer.
std::uint32_t dataSize() const
Returns the size of the data stored in the frame in bytes.
static std::uint8_t makeTextEncodingByte(TagTextEncoding textEncoding)
Returns a text encoding byte for the specified textEncoding.
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag)
Parses a substring from the specified buffer.
void parseBom(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, Diagnostics &diag)
Parses a byte order mark from the specified buffer.
static void makeComment(std::unique_ptr< char[]> &buffer, std::uint32_t &bufferSize, const TagValue &comment, std::uint8_t version, Diagnostics &diag)
Writes the specified comment to the specified buffer.
void parseLegacyPicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, std::uint8_t &typeInfo, Diagnostics &diag)
Parses the ID3v2.2 picture from the specified buffer.
void parsePicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, std::uint8_t &typeInfo, Diagnostics &diag)
Parses the ID3v2.3 picture from the specified buffer.
void parse(CppUtilities::BinaryReader &reader, std::uint32_t version, std::uint32_t maximalSize, Diagnostics &diag)
Parses a frame from the stream read using the specified reader.
std::tuple< const char *, std::size_t, const char * > parseSubstring(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag)
Parses a substring from the specified buffer.
bool hasGroupInformation() const
Returns whether the frame contains group information.
std::uint16_t flag() const
Returns the flags.
Id3v2Frame()
Constructs a new Id3v2Frame.
bool isCompressed() const
Returns whether the frame is compressed.
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)
Writes the specified picture to the specified buffer.
TagTextEncoding parseTextEncodingByte(std::uint8_t textEncodingByte, Diagnostics &diag)
Returns the text encoding for the specified textEncodingByte.
Id3v2FrameMaker prepareMaking(std::uint8_t version, Diagnostics &diag)
Prepares making.
void parseComment(const char *buffer, std::size_t maxSize, TagValue &tagValue, Diagnostics &diag)
Parses the comment/unsynchronized lyrics from the specified buffer.
static void makeLegacyPicture(std::unique_ptr< char[]> &buffer, std::uint32_t &bufferSize, const TagValue &picture, std::uint8_t typeInfo, Diagnostics &diag)
Writes the specified picture to the specified buffer (ID3v2.2 compatible).
std::u16string parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag)
Parses a substring from the specified buffer.
void make(CppUtilities::BinaryWriter &writer, std::uint8_t version, Diagnostics &diag)
Writes the frame to a stream using the specified writer and the specified ID3v2 version.
friend class Id3v2FrameMaker
std::uint8_t group() const
Returns the group.
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
The exception that is thrown when the data to be parsed holds no parsable information (e....
The PositionInSet class describes the position of an element in a set which consists of a certain num...
The TagField class is used by FieldMapBasedTag to store the fields.
void setTypeInfo(const TypeInfoType &typeInfo)
Sets the type info of the current TagField.
const TypeInfoType & typeInfo() const
Returns the type info of the current TagField.
const IdentifierType & id() const
Returns the id of the current TagField.
void setId(const IdentifierType &id)
Sets the id of the current Tag Field.
std::string idToString() const
TagValue & value()
Returns the value of the current TagField.
The TagValue class wraps values of different types.
void setMimeType(std::string_view mimeType)
Sets the MIME type.
const std::string & mimeType() const
Returns the MIME type.
static void ensureHostByteOrder(std::u16string &u16str, TagTextEncoding currentEncoding)
Ensures the byte-order of the specified UTF-16 string matches the byte-order of the machine.
TagTextEncoding dataEncoding() const
Returns the data encoding.
void assignPosition(PositionInSet value)
Assigns the given PositionInSet value.
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
void setDescription(std::string_view value, TagTextEncoding encoding=TagTextEncoding::Latin1)
Sets the description.
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
TagDataType type() const
Returns the type of the assigned value.
void assignTimeSpan(CppUtilities::TimeSpan value)
Assigns the given TimeSpan value.
static std::vector< std::string > toStrings(const ContainerType &values, TagTextEncoding encoding=TagTextEncoding::Utf8)
Converts the specified values to string using the specified encoding.
void clearDataAndMetadata()
Wipes assigned data including meta data.
std::size_t dataSize() const
Returns the size of the assigned value in bytes.
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
void assignStandardGenreIndex(int index)
Assigns the given standard genre index to be assigned.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
void setLocale(const Locale &locale)
Sets the setLocale.
bool isEmpty() const
Returns whether no or an empty value is assigned.
const std::string & description() const
Returns the description.
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
char * dataPointer()
Returns a pointer to the raw data assigned to the current instance.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
The exception that is thrown when an operation fails because the detected or specified version is not...
TAG_PARSER_EXPORT bool isPreId3v24Id(std::uint32_t id)
TAG_PARSER_EXPORT std::uint32_t convertToShortId(std::uint32_t id)
Converts the specified long frame ID to the equivalent short frame ID.
constexpr bool isLongId(std::uint32_t id)
Returns an indication whether the specified id is a long frame id.
constexpr bool isTextFrame(std::uint32_t id)
Returns an indication whether the specified id is a text frame id.
constexpr bool isShortId(std::uint32_t id)
Returns an indication whether the specified id is a short frame id.
TAG_PARSER_EXPORT bool isOnlyId3v24Id(std::uint32_t id)
TAG_PARSER_EXPORT std::uint32_t convertToLongId(std::uint32_t id)
Converts the specified short frame ID to the equivalent long frame ID.
constexpr TAG_PARSER_EXPORT std::string_view comment()
constexpr TAG_PARSER_EXPORT std::string_view language()
constexpr TAG_PARSER_EXPORT std::string_view duration()
Contains all classes and functions of the TagInfo library.
constexpr int characterSize(TagTextEncoding encoding)
Returns the size of one character for the specified encoding in bytes.
u16string wideStringFromSubstring(tuple< const char *, size_t, const char * > substr, TagTextEncoding encoding)
Returns an std::u16string instance for the substring parsed using parseSubstring().
constexpr auto maxId3v2FrameDataSize(numeric_limits< std::uint32_t >::max() - 15)
The maximum (supported) size of an ID3v2Frame.
TagTextEncoding
Specifies the text encoding.
int parseGenreIndex(const stringtype &denotation)
Helper function to parse the genre index.
string stringFromSubstring(tuple< const char *, size_t, const char * > substr)
Returns an std::string instance for the substring parsed using parseSubstring().
The Locale struct specifies a language and/or a country using one or more LocaleDetail objects.