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 {
39 Id3v2Frame::Id3v2Frame()
70 for (
auto c : denotation) {
81 if (c >=
'0' && c <=
'9') {
94 if (c >=
'0' && c <=
'9') {
95 index = index * 10 + c -
'0';
110 return string(get<0>(substr), get<1>(substr));
118 u16string res(reinterpret_cast<u16string::const_pointer>(get<0>(substr)), get<1>(substr) / 2);
135 static const string defaultContext(
"parsing ID3v2 frame");
142 setId(reader.readUInt24BE());
143 if (
id() & 0xFFFF0000u) {
152 context =
"parsing " %
idToString() +
" frame";
155 m_dataSize = reader.readUInt24BE();
156 m_totalSize = m_dataSize + 6;
157 if (m_totalSize > maximalSize) {
158 diag.emplace_back(
DiagLevel::Warning,
"The frame is truncated and will be ignored.", context);
169 setId(reader.readUInt32BE());
170 if (
id() & 0xFF000000u) {
179 context =
"parsing " %
idToString() +
" frame";
182 m_dataSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
183 m_totalSize = m_dataSize + 10;
184 if (m_totalSize > maximalSize) {
185 diag.emplace_back(
DiagLevel::Warning,
"The frame is truncated and will be ignored.", context);
190 m_flag = reader.readUInt16BE();
200 if (m_dataSize <= 0) {
206 unique_ptr<char[]> buffer;
210 uLongf decompressedSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
211 if (decompressedSize < m_dataSize) {
212 diag.emplace_back(
DiagLevel::Critical,
"The decompressed size is smaller than the compressed size.", context);
215 const auto bufferCompressed = make_unique<char[]>(m_dataSize);
216 reader.read(bufferCompressed.get(), m_dataSize);
217 buffer = make_unique<char[]>(decompressedSize);
219 uncompress(reinterpret_cast<Bytef *>(buffer.get()), &decompressedSize, reinterpret_cast<Bytef *>(bufferCompressed.get()), m_dataSize)) {
221 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
224 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
227 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The input data was corrupted or incomplete.", context);
236 diag.emplace_back(
DiagLevel::Critical,
"The decompressed data exceeds the maximum supported frame size.", context);
239 m_dataSize =
static_cast<uint32
>(decompressedSize);
241 buffer = make_unique<char[]>(m_dataSize);
242 reader.read(buffer.get(), m_dataSize);
251 const char *currentOffset = buffer.get() + 1;
252 for (
size_t currentIndex = 1; currentIndex < m_dataSize;) {
254 const auto substr(
parseSubstring(currentOffset, m_dataSize - currentIndex, dataEncoding,
false, diag));
257 if (!get<1>(substr)) {
258 if (currentIndex == 1) {
261 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
262 currentOffset = get<2>(substr);
269 return &this->
value();
271 m_additionalValues.emplace_back();
272 return &m_additionalValues.back();
285 }
catch (
const ConversionException &) {
286 diag.emplace_back(
DiagLevel::Warning,
"The value of track/disk position frame is not numeric and will be ignored.", context);
292 const auto milliseconds = [&] {
294 const auto parsedStringRef =
parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding,
false, diag);
296 ? convertUtf16BEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef))
297 : convertUtf16LEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef));
298 return string(convertedStringData.first.get(), convertedStringData.second);
304 }
catch (
const ConversionException &) {
305 diag.emplace_back(
DiagLevel::Warning,
"The value of the length frame is not numeric and will be ignored.", context);
310 const auto genreIndex = [&] {
317 if (genreIndex != -1) {
329 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
330 currentOffset = get<2>(substr);
334 if (
version < 4 && !m_additionalValues.empty()) {
336 DiagLevel::Warning,
"Multiple strings found though the tag is pre-ID3v2.4. " + ignoreAdditionalValuesDiagMsg(), context);
393 void Id3v2Frame::reset()
401 m_additionalValues.clear();
407 std::string Id3v2Frame::ignoreAdditionalValuesDiagMsg()
const 409 if (m_additionalValues.size() == 1) {
410 return argsToString(
"Additional value \"", m_additionalValues.front().toString(
TagTextEncoding::Utf8),
"\" is supposed to be ignored.");
426 Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, byte
version, Diagnostics &diag)
428 , m_frameId(m_frame.id())
431 const string context(
"making " % m_frame.idToString() +
" frame");
434 vector<const TagValue *> values;
435 values.reserve(1 + frame.additionalValues().size());
436 if (!frame.value().isEmpty()) {
437 values.emplace_back(&frame.value());
439 for (
const auto &
value : frame.additionalValues()) {
441 values.emplace_back(&
value);
446 if (values.empty()) {
448 throw InvalidDataException();
450 if (m_frame.isEncrypted()) {
451 diag.emplace_back(
DiagLevel::Critical,
"Cannot make an encrypted frame (isn't supported by this tagging library).", context);
452 throw InvalidDataException();
454 if (m_frame.hasPaddingReached()) {
455 diag.emplace_back(
DiagLevel::Critical,
"Cannot make a frame which is marked as padding.", context);
456 throw InvalidDataException();
458 if (
version < 3 && m_frame.isCompressed()) {
459 diag.emplace_back(
DiagLevel::Warning,
"Compression is not supported by the version of ID3v2 and won't be applied.", context);
461 if (
version < 3 && (m_frame.flag() || m_frame.group())) {
463 "The existing flag and group information is not supported by the version of ID3v2 and will be ignored/discarted.", context);
466 if (values.size() != 1) {
468 diag.emplace_back(
DiagLevel::Critical,
"Multiple values are not supported for non-text-frames.", context);
469 throw InvalidDataException();
472 DiagLevel::Warning,
"Multiple strings assigned to pre-ID3v2.4 text frame. " + frame.ignoreAdditionalValuesDiagMsg(), context);
482 "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.",
484 throw InvalidDataException();
492 "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.",
494 throw InvalidDataException();
503 vector<string> substrings;
504 substrings.reserve(1 + frame.additionalValues().size());
511 for (
const auto *
const value : values) {
520 }
catch (
const ConversionException &) {
522 argsToString(
"The track/disk number \"", substrings.back(),
"\" is not of the expected form, eg. \"4/10\"."), context);
529 for (
const auto *
const value : values) {
533 throw InvalidDataException();
535 substrings.emplace_back(ConversionUtilities::numberToString(static_cast<uint64>(
duration.totalMilliseconds())));
541 for (
const auto *
const value : values) {
567 for (
const auto *
const value : values) {
582 const auto byteOrderMark = [&] {
585 return string({
'\xFF',
'\xFE' });
587 return string({
'\xFE',
'\xFF' });
592 const auto concatenatedSubstrings = joinStrings(substrings,
string(),
false, byteOrderMark,
string(terminationLength,
'\0'));
595 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<uint32
>(1 + concatenatedSubstrings.size()));
597 concatenatedSubstrings.copy(&m_data[1], concatenatedSubstrings.size());
601 m_frame.makePicture(m_data, m_decompressedSize, *values.front(), m_frame.isTypeInfoAssigned() ? m_frame.typeInfo() : 0,
version);
607 m_frame.makeComment(m_data, m_decompressedSize, *values.front(),
version, diag);
611 const auto &
value(*values.front());
614 throw InvalidDataException();
616 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<uint32
>(
value.
dataSize()));
619 }
catch (
const ConversionException &) {
623 argsToString(
"Assigned value(s) \"",
DiagMessage::formatList(valuesAsString),
"\" can not be converted appropriately."), context);
624 }
catch (
const ConversionException &) {
625 diag.emplace_back(
DiagLevel::Critical,
"Assigned value(s) can not be converted appropriately.", context);
627 throw InvalidDataException();
631 if (
version >= 3 && m_frame.isCompressed()) {
632 auto compressedSize = compressBound(m_decompressedSize);
633 auto compressedData = make_unique<char[]>(compressedSize);
634 switch (compress(reinterpret_cast<Bytef *>(compressedData.get()), reinterpret_cast<uLongf *>(&compressedSize),
635 reinterpret_cast<Bytef *
>(m_data.get()), m_decompressedSize)) {
637 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
638 throw InvalidDataException();
640 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
641 throw InvalidDataException();
645 diag.emplace_back(
DiagLevel::Critical,
"Compressed size exceeds maximum data size.", context);
646 throw InvalidDataException();
648 m_data.swap(compressedData);
649 m_dataSize =
static_cast<uint32
>(compressedSize);
651 m_dataSize = m_decompressedSize;
656 m_requiredSize = m_dataSize;
662 m_requiredSize += 10;
664 if (m_frame.hasGroupInformation()) {
668 if (
version >= 3 && m_frame.isCompressed()) {
684 writer.writeUInt24BE(m_frameId);
685 writer.writeUInt24BE(m_dataSize);
687 writer.writeUInt32BE(m_frameId);
688 if (m_version >= 4) {
689 writer.writeSynchsafeUInt32BE(m_dataSize);
691 writer.writeUInt32BE(m_dataSize);
693 writer.writeUInt16BE(m_frame.
flag());
695 writer.writeByte(m_frame.
group());
698 if (m_version >= 4) {
699 writer.writeSynchsafeUInt32BE(m_decompressedSize);
701 writer.writeUInt32BE(m_decompressedSize);
705 writer.write(m_data.get(), m_dataSize);
716 switch (textEncodingByte) {
737 switch (textEncoding) {
768 tuple<const char *, size_t, const char *> res(buffer, 0, buffer + bufferSize);
773 if ((bufferSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
775 diag.emplace_back(
DiagLevel::Critical,
"Denoted character set is Latin-1 but an UTF-8 BOM is present - assuming UTF-8.",
781 const char *pos = get<0>(res);
782 for (; *pos != 0x00; ++pos) {
783 if (pos < get<2>(res)) {
793 get<2>(res) = pos + 1;
798 if (bufferSize >= 2) {
799 switch (ConversionUtilities::LE::toUInt16(buffer)) {
803 "Denoted character set is UTF-16 Big Endian but UTF-16 Little Endian BOM is present - assuming UTF-16 LE.",
814 const uint16 *pos =
reinterpret_cast<const uint16 *
>(get<0>(res));
815 for (; *pos != 0x0000; ++pos) {
816 if (pos < reinterpret_cast<const uint16 *>(get<2>(res))) {
826 get<2>(res) = reinterpret_cast<const char *>(pos + 1);
867 if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFFFE)) {
869 }
else if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFEFF)) {
874 if ((maxSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
890 static const string context(
"parsing ID3v2.2 picture frame");
895 const char *end = buffer + maxSize;
897 typeInfo =
static_cast<unsigned char>(*(buffer + 4));
898 auto substr =
parseSubstring(buffer + 5, static_cast<size_t>(end - 5 - buffer), dataEncoding,
true, diag);
899 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
900 if (get<2>(substr) >= end) {
901 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
916 static const string context(
"parsing ID3v2.3 picture frame");
917 const char *end = buffer + maxSize;
920 auto substr =
parseSubstring(buffer + 1, maxSize - 1, mimeTypeEncoding,
true, diag);
921 if (get<1>(substr)) {
922 tagValue.
setMimeType(
string(get<0>(substr), get<1>(substr)));
924 if (get<2>(substr) >= end) {
925 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (type info, description and actual data are missing).", context);
928 typeInfo =
static_cast<unsigned char>(*get<2>(substr));
929 if (++get<2>(substr) >= end) {
930 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (description and actual data are missing).", context);
933 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
true, diag);
934 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
935 if (get<2>(substr) >= end) {
936 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
950 static const string context(
"parsing comment/unsynchronized lyrics frame");
951 const char *end = buffer +
dataSize;
961 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
962 if (get<2>(substr) > end) {
963 diag.emplace_back(
DiagLevel::Critical,
"Comment frame is incomplete (description not terminated?).", context);
966 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
false, diag);
991 std::unique_ptr<
char[]> &buffer, uint32 &bufferSize,
TagTextEncoding encoding,
const char *data, std::size_t dataSize)
997 char *bufferDataAddress;
1003 buffer = make_unique<char[]>(bufferSize = 1 +
dataSize + 1);
1005 bufferDataAddress = buffer.get() + 1;
1010 buffer = make_unique<char[]>(bufferSize = 1 + 2 +
dataSize + 2);
1012 ConversionUtilities::LE::getBytes(
1014 bufferDataAddress = buffer.get() + 3;
1022 copy(data, data +
dataSize, bufferDataAddress);
1034 ConversionUtilities::LE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1037 ConversionUtilities::BE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1051 StringData convertedDescription;
1052 string::size_type descriptionSize = picture.
description().find(
1054 if (descriptionSize == string::npos) {
1060 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1061 descriptionSize = convertedDescription.second;
1065 buffer = make_unique<char[]>(bufferSize = 1 + 3 + 1 + descriptionSize
1069 char *offset = buffer.get();
1073 const char *imageFormat;
1074 if (picture.
mimeType() ==
"image/jpeg") {
1075 imageFormat =
"JPG";
1076 }
else if (picture.
mimeType() ==
"image/png") {
1077 imageFormat =
"PNG";
1078 }
else if (picture.
mimeType() ==
"image/gif") {
1079 imageFormat =
"GIF";
1080 }
else if (picture.
mimeType() ==
"-->") {
1081 imageFormat = picture.
mimeType().data();
1083 imageFormat =
"UND";
1085 strncpy(++offset, imageFormat, 3);
1087 *(offset += 3) = static_cast<char>(
typeInfo);
1089 offset +=
makeBom(offset + 1, descriptionEncoding);
1090 if (convertedDescription.first) {
1091 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1093 picture.
description().copy(++offset, descriptionSize);
1095 *(offset += descriptionSize) = 0x00;
1115 StringData convertedDescription;
1116 string::size_type descriptionSize = picture.
description().find(
1118 if (descriptionSize == string::npos) {
1124 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1125 descriptionSize = convertedDescription.second;
1128 string::size_type mimeTypeSize = picture.
mimeType().find(
'\0');
1129 if (mimeTypeSize == string::npos) {
1130 mimeTypeSize = picture.
mimeType().length();
1134 buffer = make_unique<char[]>(bufferSize = 1 + mimeTypeSize + 1 + 1 + descriptionSize
1138 char *offset = buffer.get();
1142 picture.
mimeType().copy(++offset, mimeTypeSize);
1143 *(offset += mimeTypeSize) = 0x00;
1145 *(++offset) = static_cast<char>(
typeInfo);
1147 offset +=
makeBom(offset + 1, descriptionEncoding);
1148 if (convertedDescription.first) {
1149 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1151 picture.
description().copy(++offset, descriptionSize);
1153 *(offset += descriptionSize) = 0x00;
1166 static const string context(
"making comment frame");
1169 if (!
comment.description().empty() && encoding !=
comment.descriptionEncoding()) {
1170 diag.emplace_back(
DiagLevel::Critical,
"Data enoding and description encoding aren't equal.", context);
1173 const string &lng =
comment.language();
1174 if (lng.length() > 3) {
1175 diag.emplace_back(
DiagLevel::Critical,
"The language must be 3 bytes long (ISO-639-2).", context);
1178 StringData convertedDescription;
1179 string::size_type descriptionSize =
comment.description().find(
1181 if (descriptionSize == string::npos) {
1182 descriptionSize =
comment.description().size();
1187 convertedDescription = convertUtf8ToUtf16LE(
comment.description().data(), descriptionSize);
1188 descriptionSize = convertedDescription.second;
1191 const auto data =
comment.toString(encoding);
1192 buffer = make_unique<char[]>(bufferSize = 1 + 3 + descriptionSize + data.size()
1195 char *offset = buffer.get();
1199 for (
unsigned int i = 0; i < 3; ++i) {
1200 *(++offset) = (lng.length() > i) ? lng[i] : 0x00;
1203 offset +=
makeBom(offset + 1, encoding);
1204 if (convertedDescription.first) {
1205 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1207 comment.description().copy(++offset, descriptionSize);
1209 offset += descriptionSize;
1215 offset +=
makeBom(offset + 1, encoding);
1216 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.
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.
string stringFromSubstring(tuple< const char *, size_t, const char *> substr)
Returns an std::string instance for the substring parsed using parseSubstring().
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.
u16string wideStringFromSubstring(tuple< const char *, size_t, const char *> substr, TagTextEncoding encoding)
Returns an std::u16string instance for the substring parsed using parseSubstring().
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.
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.
TagValue & value()
Returns the value of the current TagField.