5 #include "../diagnostics.h" 6 #include "../exceptions.h" 8 #include <c++utilities/conversion/stringbuilder.h> 9 #include <c++utilities/conversion/stringconversion.h> 19 using namespace ConversionUtilities;
20 using namespace ChronoUtilities;
25 namespace Id3v2TextEncodingBytes {
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();
201 if (m_dataSize <= 0) {
207 unique_ptr<char[]> buffer;
211 uLongf decompressedSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
212 if (decompressedSize < m_dataSize) {
213 diag.emplace_back(
DiagLevel::Critical,
"The decompressed size is smaller than the compressed size.", context);
216 const auto bufferCompressed = make_unique<char[]>(m_dataSize);
217 reader.read(bufferCompressed.get(), m_dataSize);
218 buffer = make_unique<char[]>(decompressedSize);
220 uncompress(reinterpret_cast<Bytef *>(buffer.get()), &decompressedSize, reinterpret_cast<Bytef *>(bufferCompressed.get()), m_dataSize)) {
222 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
225 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
228 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The input data was corrupted or incomplete.", context);
237 diag.emplace_back(
DiagLevel::Critical,
"The decompressed data exceeds the maximum supported frame size.", context);
240 m_dataSize = static_cast<uint32>(decompressedSize);
242 buffer = make_unique<char[]>(m_dataSize);
243 reader.read(buffer.get(), m_dataSize);
252 const char *currentOffset = buffer.get() + 1;
253 for (
size_t currentIndex = 1; currentIndex < m_dataSize;) {
255 const auto substr(
parseSubstring(currentOffset, m_dataSize - currentIndex, dataEncoding,
false, diag));
258 if (!get<1>(substr)) {
259 if (currentIndex == 1) {
262 currentIndex = static_cast<size_t>(get<2>(substr) - buffer.get());
263 currentOffset = get<2>(substr);
269 if (this->
value().isEmpty()) {
270 return &this->
value();
272 m_additionalValues.emplace_back();
273 return &m_additionalValues.back();
286 }
catch (
const ConversionException &) {
287 diag.emplace_back(
DiagLevel::Warning,
"The value of track/disk position frame is not numeric and will be ignored.", context);
293 const auto milliseconds = [&] {
295 const auto parsedStringRef =
parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding,
false, diag);
297 ? convertUtf16BEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef))
298 : convertUtf16LEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef));
299 return string(convertedStringData.first.get(), convertedStringData.second);
305 }
catch (
const ConversionException &) {
306 diag.emplace_back(
DiagLevel::Warning,
"The value of the length frame is not numeric and will be ignored.", context);
311 const auto genreIndex = [&] {
318 if (genreIndex != -1) {
330 currentIndex = static_cast<size_t>(get<2>(substr) - buffer.get());
331 currentOffset = get<2>(substr);
335 if (
version < 4 && !m_additionalValues.empty()) {
337 DiagLevel::Warning,
"Multiple strings found though the tag is pre-ID3v2.4. " + ignoreAdditionalValuesDiagMsg(), context);
394 void Id3v2Frame::reset()
402 m_additionalValues.clear();
408 std::string Id3v2Frame::ignoreAdditionalValuesDiagMsg()
const 410 if (m_additionalValues.size() == 1) {
411 return argsToString(
"Additional value \"", m_additionalValues.front().toString(
TagTextEncoding::Utf8),
"\" is supposed to be ignored.");
427 Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame,
byte version, Diagnostics &diag)
429 , m_frameId(m_frame.id())
432 const string context(
"making " % m_frame.idToString() +
" frame");
435 if (m_frame.isEncrypted()) {
436 diag.emplace_back(
DiagLevel::Critical,
"Cannot make an encrypted frame (isn't supported by this tagging library).", context);
437 throw InvalidDataException();
439 if (m_frame.hasPaddingReached()) {
440 diag.emplace_back(
DiagLevel::Critical,
"Cannot make a frame which is marked as padding.", context);
441 throw InvalidDataException();
443 if (
version < 3 && m_frame.isCompressed()) {
444 diag.emplace_back(
DiagLevel::Warning,
"Compression is not supported by the version of ID3v2 and won't be applied.", context);
446 if (
version < 3 && (m_frame.flag() || m_frame.group())) {
448 "The existing flag and group information is not supported by the version of ID3v2 and will be ignored/discarted.", context);
452 vector<const TagValue *> values;
453 values.reserve(1 + frame.additionalValues().size());
454 if (!frame.value().isEmpty()) {
455 values.emplace_back(&frame.value());
457 for (
const auto &
value : frame.additionalValues()) {
459 values.emplace_back(&
value);
464 if (values.empty()) {
465 throw NoDataProvidedException();
470 if (values.size() != 1) {
472 diag.emplace_back(
DiagLevel::Critical,
"Multiple values are not supported for non-text-frames.", context);
473 throw InvalidDataException();
476 DiagLevel::Warning,
"Multiple strings assigned to pre-ID3v2.4 text frame. " + frame.ignoreAdditionalValuesDiagMsg(), context);
486 "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.",
488 throw InvalidDataException();
496 "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.",
498 throw InvalidDataException();
507 vector<string> substrings;
508 substrings.reserve(1 + frame.additionalValues().size());
515 for (
const auto *
const value : values) {
524 }
catch (
const ConversionException &) {
526 argsToString(
"The track/disk number \"", substrings.back(),
"\" is not of the expected form, eg. \"4/10\"."), context);
533 for (
const auto *
const value : values) {
537 throw InvalidDataException();
539 substrings.emplace_back(ConversionUtilities::numberToString(static_cast<uint64>(
duration.totalMilliseconds())));
545 for (
const auto *
const value : values) {
571 for (
const auto *
const value : values) {
586 const auto byteOrderMark = [&] {
589 return string({
'\xFF',
'\xFE' });
591 return string({
'\xFE',
'\xFF' });
596 const auto concatenatedSubstrings = joinStrings(substrings,
string(),
false, byteOrderMark,
string(terminationLength,
'\0'));
599 m_data = make_unique<char[]>(m_decompressedSize = static_cast<uint32>(1 + concatenatedSubstrings.size()));
601 concatenatedSubstrings.copy(&m_data[1], concatenatedSubstrings.size());
605 m_frame.makePicture(m_data, m_decompressedSize, *values.front(), m_frame.isTypeInfoAssigned() ? m_frame.typeInfo() : 0,
version);
611 m_frame.makeComment(m_data, m_decompressedSize, *values.front(),
version, diag);
615 const auto &
value(*values.front());
618 throw InvalidDataException();
620 m_data = make_unique<char[]>(m_decompressedSize = static_cast<uint32>(
value.
dataSize()));
623 }
catch (
const ConversionException &) {
627 argsToString(
"Assigned value(s) \"",
DiagMessage::formatList(valuesAsString),
"\" can not be converted appropriately."), context);
628 }
catch (
const ConversionException &) {
629 diag.emplace_back(
DiagLevel::Critical,
"Assigned value(s) can not be converted appropriately.", context);
631 throw InvalidDataException();
635 if (
version >= 3 && m_frame.isCompressed()) {
636 auto compressedSize = compressBound(m_decompressedSize);
637 auto compressedData = make_unique<char[]>(compressedSize);
638 switch (compress(reinterpret_cast<Bytef *>(compressedData.get()), reinterpret_cast<uLongf *>(&compressedSize),
639 reinterpret_cast<Bytef *>(m_data.get()), m_decompressedSize)) {
641 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
642 throw InvalidDataException();
644 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
645 throw InvalidDataException();
649 diag.emplace_back(
DiagLevel::Critical,
"Compressed size exceeds maximum data size.", context);
650 throw InvalidDataException();
652 m_data.swap(compressedData);
653 m_dataSize = static_cast<uint32>(compressedSize);
655 m_dataSize = m_decompressedSize;
660 m_requiredSize = m_dataSize;
666 m_requiredSize += 10;
668 if (m_frame.hasGroupInformation()) {
672 if (
version >= 3 && m_frame.isCompressed()) {
688 writer.writeUInt24BE(m_frameId);
689 writer.writeUInt24BE(m_dataSize);
691 writer.writeUInt32BE(m_frameId);
692 if (m_version >= 4) {
693 writer.writeSynchsafeUInt32BE(m_dataSize);
695 writer.writeUInt32BE(m_dataSize);
697 writer.writeUInt16BE(m_frame.
flag());
699 writer.writeByte(m_frame.
group());
702 if (m_version >= 4) {
703 writer.writeSynchsafeUInt32BE(m_decompressedSize);
705 writer.writeUInt32BE(m_decompressedSize);
709 writer.write(m_data.get(), m_dataSize);
720 switch (textEncodingByte) {
741 switch (textEncoding) {
772 tuple<const char *, size_t, const char *> res(buffer, 0, buffer + bufferSize);
777 if ((bufferSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
779 diag.emplace_back(
DiagLevel::Critical,
"Denoted character set is Latin-1 but an UTF-8 BOM is present - assuming UTF-8.",
785 const char *pos = get<0>(res);
786 for (; *pos != 0x00; ++pos) {
787 if (pos < get<2>(res)) {
797 get<2>(res) = pos + 1;
802 if (bufferSize >= 2) {
803 switch (ConversionUtilities::LE::toUInt16(buffer)) {
807 "Denoted character set is UTF-16 Big Endian but UTF-16 Little Endian BOM is present - assuming UTF-16 LE.",
818 const uint16 *pos = reinterpret_cast<const uint16 *>(get<0>(res));
819 for (; *pos != 0x0000; ++pos) {
820 if (pos < reinterpret_cast<const uint16 *>(get<2>(res))) {
830 get<2>(res) = reinterpret_cast<const char *>(pos + 1);
871 if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFFFE)) {
873 }
else if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFEFF)) {
878 if ((maxSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
894 static const string context(
"parsing ID3v2.2 picture frame");
899 const char *end = buffer + maxSize;
901 typeInfo = static_cast<unsigned char>(*(buffer + 4));
902 auto substr =
parseSubstring(buffer + 5, static_cast<size_t>(end - 5 - buffer), dataEncoding,
true, diag);
903 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
904 if (get<2>(substr) >= end) {
905 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
920 static const string context(
"parsing ID3v2.3 picture frame");
921 const char *end = buffer + maxSize;
924 auto substr =
parseSubstring(buffer + 1, maxSize - 1, mimeTypeEncoding,
true, diag);
925 if (get<1>(substr)) {
926 tagValue.
setMimeType(
string(get<0>(substr), get<1>(substr)));
928 if (get<2>(substr) >= end) {
929 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (type info, description and actual data are missing).", context);
932 typeInfo = static_cast<unsigned char>(*get<2>(substr));
933 if (++get<2>(substr) >= end) {
934 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (description and actual data are missing).", context);
937 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
true, diag);
938 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
939 if (get<2>(substr) >= end) {
940 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
954 static const string context(
"parsing comment/unsynchronized lyrics frame");
955 const char *end = buffer +
dataSize;
965 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
966 if (get<2>(substr) > end) {
967 diag.emplace_back(
DiagLevel::Critical,
"Comment frame is incomplete (description not terminated?).", context);
970 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
false, diag);
999 std::unique_ptr<
char[]> &buffer, uint32 &bufferSize,
TagTextEncoding encoding,
const char *data, std::size_t dataSize)
1005 if (
dataSize > numeric_limits<uint32>::max() - 5) {
1008 char *bufferDataAddress;
1014 buffer = make_unique<char[]>(bufferSize = static_cast<uint32>(1 +
dataSize + 1));
1016 bufferDataAddress = buffer.get() + 1;
1021 buffer = make_unique<char[]>(bufferSize = static_cast<uint32>(1 + 2 +
dataSize + 2));
1023 ConversionUtilities::LE::getBytes(
1025 bufferDataAddress = buffer.get() + 3;
1033 copy(data, data +
dataSize, bufferDataAddress);
1045 ConversionUtilities::LE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1048 ConversionUtilities::BE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1062 StringData convertedDescription;
1063 string::size_type descriptionSize = picture.
description().find(
1065 if (descriptionSize == string::npos) {
1071 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1072 descriptionSize = convertedDescription.second;
1077 const auto requiredBufferSize = 1 + 3 + 1 + descriptionSize
1080 if (requiredBufferSize > numeric_limits<uint32>::max()) {
1083 buffer = make_unique<char[]>(bufferSize = static_cast<uint32>(requiredBufferSize));
1084 char *offset = buffer.get();
1090 const char *imageFormat;
1091 if (picture.
mimeType() ==
"image/jpeg") {
1092 imageFormat =
"JPG";
1093 }
else if (picture.
mimeType() ==
"image/png") {
1094 imageFormat =
"PNG";
1095 }
else if (picture.
mimeType() ==
"image/gif") {
1096 imageFormat =
"GIF";
1097 }
else if (picture.
mimeType() ==
"-->") {
1098 imageFormat = picture.
mimeType().data();
1100 imageFormat =
"UND";
1102 strncpy(++offset, imageFormat, 3);
1105 *(offset += 3) = static_cast<char>(
typeInfo);
1108 offset +=
makeBom(offset + 1, descriptionEncoding);
1109 if (convertedDescription.first) {
1110 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1112 picture.
description().copy(++offset, descriptionSize);
1114 *(offset += descriptionSize) = 0x00;
1135 StringData convertedDescription;
1136 string::size_type descriptionSize = picture.
description().find(
1138 if (descriptionSize == string::npos) {
1144 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1145 descriptionSize = convertedDescription.second;
1148 string::size_type mimeTypeSize = picture.
mimeType().find(
'\0');
1149 if (mimeTypeSize == string::npos) {
1150 mimeTypeSize = picture.
mimeType().length();
1154 buffer = make_unique<char[]>(bufferSize = 1 + mimeTypeSize + 1 + 1 + descriptionSize
1158 char *offset = buffer.get();
1162 picture.
mimeType().copy(++offset, mimeTypeSize);
1163 *(offset += mimeTypeSize) = 0x00;
1165 *(++offset) = static_cast<char>(
typeInfo);
1167 offset +=
makeBom(offset + 1, descriptionEncoding);
1168 if (convertedDescription.first) {
1169 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1171 picture.
description().copy(++offset, descriptionSize);
1173 *(offset += descriptionSize) = 0x00;
1186 static const string context(
"making comment frame");
1189 if (!
comment.description().empty() && encoding !=
comment.descriptionEncoding()) {
1190 diag.emplace_back(
DiagLevel::Critical,
"Data enoding and description encoding aren't equal.", context);
1193 const string &lng =
comment.language();
1194 if (lng.length() > 3) {
1195 diag.emplace_back(
DiagLevel::Critical,
"The language must be 3 bytes long (ISO-639-2).", context);
1198 StringData convertedDescription;
1199 string::size_type descriptionSize =
comment.description().find(
1201 if (descriptionSize == string::npos) {
1202 descriptionSize =
comment.description().size();
1207 convertedDescription = convertUtf8ToUtf16LE(
comment.description().data(), descriptionSize);
1208 descriptionSize = convertedDescription.second;
1211 const auto data =
comment.toString(encoding);
1212 buffer = make_unique<char[]>(bufferSize = 1 + 3 + descriptionSize + data.size()
1215 char *offset = buffer.get();
1219 for (
unsigned int i = 0; i < 3; ++i) {
1220 *(++offset) = (lng.length() > i) ? lng[i] : 0x00;
1223 offset +=
makeBom(offset + 1, encoding);
1224 if (convertedDescription.first) {
1225 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1227 comment.description().copy(++offset, descriptionSize);
1229 offset += descriptionSize;
1235 offset +=
makeBom(offset + 1, encoding);
1236 data.copy(++offset, data.size());
friend class Id3v2FrameMaker
TagTextEncoding dataEncoding() const
Returns the data encoding.
uint16 flag() const
Returns the flags.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
void setTypeInfo(const TypeInfoType &typeInfo)
Sets the type info of the current TagField.
static void makeLegacyPicture(std::unique_ptr< char[]> &buffer, uint32 &bufferSize, const TagValue &picture, byte typeInfo)
Writes the specified picture to the specified buffer (ID3v2.2 compatible).
static void makeComment(std::unique_ptr< char[]> &buffer, uint32 &bufferSize, const TagValue &comment, byte version, Diagnostics &diag)
Writes the specified comment to the specified buffer.
bool hasGroupInformation() const
Returns whether the frame contains group information.
byte group() const
Returns the group.
u16string wideStringFromSubstring(tuple< const char *, size_t, const char * > substr, TagTextEncoding encoding)
Returns an std::u16string instance for the substring parsed using parseSubstring().
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
const std::string & description() const
Returns the description.
void setMimeType(const std::string &mimeType)
Sets the MIME type.
static byte makeTextEncodingByte(TagTextEncoding textEncoding)
Returns a text encoding byte for the specified textEncoding.
The exception that is thrown when an operation fails because the detected or specified version is not...
TagTextEncoding parseTextEncodingByte(byte textEncodingByte, Diagnostics &diag)
Returns the text encoding for the specified textEncodingByte.
void make(IoUtilities::BinaryWriter &writer, byte version, Diagnostics &diag)
Writes the frame to a stream using the specified writer and the specified ID3v2 version.
std::u16string parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag)
Parses a substring from the specified buffer.
constexpr bool isLongId(uint32 id)
Returns an indication whether the specified id is a long frame id.
static std::string formatList(const std::vector< std::string > &values)
Concatenates the specified string values to a list.
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
uint32 convertToLongId(uint32 id)
Converts the specified short frame ID to the equivalent long frame ID.
constexpr auto maxId3v2FrameDataSize(numeric_limits< uint32 >::max() - 15)
The maximum (supported) size of an ID3v2Frame.
constexpr bool isShortId(uint32 id)
Returns an indication whether the specified id is a short frame id.
void clearDataAndMetadata()
Wipes assigned data including meta data.
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings, Diagnostics &diag)
Parses a substring from the specified buffer.
bool isCompressed() const
Returns whether the frame is compressed.
static void makePicture(std::unique_ptr< char[]> &buffer, uint32 &bufferSize, const TagValue &picture, byte typeInfo, byte version)
Writes the specified picture to the specified buffer.
The Id3v2Frame class is used by Id3v2Tag to store the fields.
bool isEmpty() const
Returns an indication whether an value is assigned.
const std::string & mimeType() const
Returns the MIME type.
void parseLegacyPicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, byte &typeInfo, Diagnostics &diag)
Parses the ID3v2.2 picture from the specified buffer.
std::size_t dataSize() const
Returns the size of the assigned value in bytes.
void parseBom(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, Diagnostics &diag)
Parses a byte order mark from the specified buffer.
static void makeString(std::unique_ptr< char[]> &buffer, uint32 &bufferSize, const std::string &value, TagTextEncoding encoding)
Writes an encoding denoation and the specified string value to a buffer.
std::string idToString() const
constexpr TAG_PARSER_EXPORT const char * comment()
uint32 convertToShortId(uint32 id)
Converts the specified long frame ID to the equivalent short frame ID.
static void makeEncodingAndData(std::unique_ptr< char[]> &buffer, uint32 &bufferSize, TagTextEncoding encoding, const char *data, std::size_t m_dataSize)
Writes an encoding denoation and the specified data to a buffer.
constexpr bool isTextFrame(uint32 id)
Returns an indication whether the specified id is a text frame id.
ChronoUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Contains utility classes helping to read and write streams.
bool isEncrypted() const
Returns whether the frame is encrypted.
void assignPosition(PositionInSet value)
Assigns the given PositionInSet value.
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
void parseComment(const char *buffer, std::size_t maxSize, TagValue &tagValue, Diagnostics &diag)
Parses the comment/unsynchronized lyrics from the specified buffer.
void assignStandardGenreIndex(int index)
Assigns the given standard genre index to be assigned.
const TypeInfoType & typeInfo() const
Returns the type info of the current TagField.
The exception that is thrown when the data to be parsed holds no parsable information (e....
The Id3v2FrameMaker class helps making ID3v2 frames.
void parsePicture(const char *buffer, std::size_t maxSize, TagValue &tagValue, byte &typeInfo, Diagnostics &diag)
Parses the ID3v2.3 picture from the specified buffer.
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.
The TagField class is used by FieldMapBasedTag to store the fields.
int parseGenreIndex(const stringtype &denotation)
Helper function to parse the genre index.
void setLanguage(const std::string &language)
Sets the language.
char * dataPointer()
Returns a pointer to the raw data assigned to the current instance.
typename TagFieldTraits< ImplementationType >::IdentifierType IdentifierType
const IdentifierType & id() const
Returns the id of the current TagField.
static std::size_t makeBom(char *buffer, TagTextEncoding encoding)
Writes the BOM for the specified encoding to the specified buffer.
TagDataType type() const
Returns the type of the assigned value.
void make(IoUtilities::BinaryWriter &writer)
Saves the frame (specified when constructing the object) using the specified writer.
Id3v2Frame()
Constructs a new Id3v2Frame.
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
constexpr TAG_PARSER_EXPORT const char * duration()
void setDescription(const std::string &value, TagTextEncoding encoding=TagTextEncoding::Latin1)
Sets the description.
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
static std::vector< std::string > toStrings(const ContainerType &values, TagTextEncoding encoding=TagTextEncoding::Utf8)
Converts the specified values to string using the specified encoding.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
void assignTimeSpan(ChronoUtilities::TimeSpan value)
Assigns the given TimeSpan value.
constexpr int characterSize(TagTextEncoding encoding)
Returns the size of one character for the specified encoding in bytes.
The TagValue class wraps values of different types.
uint32 dataSize() const
Returns the size of the data stored in the frame in bytes.
Id3v2FrameMaker prepareMaking(byte version, Diagnostics &diag)
Prepares making.
TagTextEncoding
Specifies the text encoding.
void parse(IoUtilities::BinaryReader &reader, uint32 version, uint32 maximalSize, Diagnostics &diag)
Parses a frame from the stream read using the specified reader.
Contains all classes and functions of the TagInfo library.
void setId(const IdentifierType &id)
Sets the id of the current Tag Field.
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.
The Diagnostics class is a container for DiagMessage.
string stringFromSubstring(tuple< const char *, size_t, const char * > substr)
Returns an std::string instance for the substring parsed using parseSubstring().
TagValue & value()
Returns the value of the current TagField.