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) {
148 diag.emplace_back(
DiagLevel::Debug,
"Frame ID starts with null-byte -> padding reached.", defaultContext);
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) {
176 diag.emplace_back(
DiagLevel::Debug,
"Frame ID starts with null-byte -> padding reached.", defaultContext);
181 context =
"parsing " %
idToString() +
" frame";
184 m_dataSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
185 m_totalSize = m_dataSize + 10;
186 if (m_totalSize > maximalSize) {
187 diag.emplace_back(
DiagLevel::Warning,
"The frame is truncated and will be ignored.", context);
192 m_flag = reader.readUInt16BE();
202 if (m_dataSize <= 0) {
208 unique_ptr<char[]> buffer;
212 uLongf decompressedSize =
version >= 4 ? reader.readSynchsafeUInt32BE() : reader.readUInt32BE();
213 if (decompressedSize < m_dataSize) {
214 diag.emplace_back(
DiagLevel::Critical,
"The decompressed size is smaller than the compressed size.", context);
217 const auto bufferCompressed = make_unique<char[]>(m_dataSize);
218 reader.read(bufferCompressed.get(), m_dataSize);
219 buffer = make_unique<char[]>(decompressedSize);
221 uncompress(reinterpret_cast<Bytef *>(buffer.get()), &decompressedSize, reinterpret_cast<Bytef *>(bufferCompressed.get()), m_dataSize)) {
223 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
226 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
229 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The input data was corrupted or incomplete.", context);
238 diag.emplace_back(
DiagLevel::Critical,
"The decompressed data exceeds the maximum supported frame size.", context);
241 m_dataSize =
static_cast<uint32
>(decompressedSize);
243 buffer = make_unique<char[]>(m_dataSize);
244 reader.read(buffer.get(), m_dataSize);
253 const char *currentOffset = buffer.get() + 1;
254 for (
size_t currentIndex = 1; currentIndex < m_dataSize;) {
256 const auto substr(
parseSubstring(currentOffset, m_dataSize - currentIndex, dataEncoding,
false, diag));
259 if (!get<1>(substr)) {
260 if (currentIndex == 1) {
263 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
264 currentOffset = get<2>(substr);
271 return &this->
value();
273 m_additionalValues.emplace_back();
274 return &m_additionalValues.back();
287 }
catch (
const ConversionException &) {
288 diag.emplace_back(
DiagLevel::Warning,
"The value of track/disk position frame is not numeric and will be ignored.", context);
294 const auto milliseconds = [&] {
296 const auto parsedStringRef =
parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding,
false, diag);
298 ? convertUtf16BEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef))
299 : convertUtf16LEToUtf8(get<0>(parsedStringRef), get<1>(parsedStringRef));
300 return string(convertedStringData.first.get(), convertedStringData.second);
306 }
catch (
const ConversionException &) {
307 diag.emplace_back(
DiagLevel::Warning,
"The value of the length frame is not numeric and will be ignored.", context);
312 const auto genreIndex = [&] {
319 if (genreIndex != -1) {
331 currentIndex =
static_cast<size_t>(get<2>(substr) - buffer.get());
332 currentOffset = get<2>(substr);
336 if (
version < 4 && !m_additionalValues.empty()) {
338 DiagLevel::Warning,
"Multiple strings found though the tag is pre-ID3v2.4. " + ignoreAdditionalValuesDiagMsg(), context);
395 void Id3v2Frame::reset()
403 m_additionalValues.clear();
409 std::string Id3v2Frame::ignoreAdditionalValuesDiagMsg()
const 411 if (m_additionalValues.size() == 1) {
412 return argsToString(
"Additional value \"", m_additionalValues.front().toString(
TagTextEncoding::Utf8),
"\" is supposed to be ignored.");
428 Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, byte
version, Diagnostics &diag)
430 , m_frameId(m_frame.id())
433 const string context(
"making " % m_frame.idToString() +
" frame");
436 vector<const TagValue *> values;
437 values.reserve(1 + frame.additionalValues().size());
438 if (!frame.value().isEmpty()) {
439 values.emplace_back(&frame.value());
441 for (
const auto &
value : frame.additionalValues()) {
443 values.emplace_back(&
value);
448 if (values.empty()) {
450 throw InvalidDataException();
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);
468 if (values.size() != 1) {
470 diag.emplace_back(
DiagLevel::Critical,
"Multiple values are not supported for non-text-frames.", context);
471 throw InvalidDataException();
474 DiagLevel::Warning,
"Multiple strings assigned to pre-ID3v2.4 text frame. " + frame.ignoreAdditionalValuesDiagMsg(), context);
484 "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.",
486 throw InvalidDataException();
494 "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.",
496 throw InvalidDataException();
505 vector<string> substrings;
506 substrings.reserve(1 + frame.additionalValues().size());
513 for (
const auto *
const value : values) {
522 }
catch (
const ConversionException &) {
524 argsToString(
"The track/disk number \"", substrings.back(),
"\" is not of the expected form, eg. \"4/10\"."), context);
531 for (
const auto *
const value : values) {
535 throw InvalidDataException();
537 substrings.emplace_back(ConversionUtilities::numberToString(static_cast<uint64>(
duration.totalMilliseconds())));
543 for (
const auto *
const value : values) {
569 for (
const auto *
const value : values) {
584 const auto byteOrderMark = [&] {
587 return string({
'\xFF',
'\xFE' });
589 return string({
'\xFE',
'\xFF' });
594 const auto concatenatedSubstrings = joinStrings(substrings,
string(),
false, byteOrderMark,
string(terminationLength,
'\0'));
597 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<uint32
>(1 + concatenatedSubstrings.size()));
599 concatenatedSubstrings.copy(&m_data[1], concatenatedSubstrings.size());
603 m_frame.makePicture(m_data, m_decompressedSize, *values.front(), m_frame.isTypeInfoAssigned() ? m_frame.typeInfo() : 0,
version);
609 m_frame.makeComment(m_data, m_decompressedSize, *values.front(),
version, diag);
613 const auto &
value(*values.front());
616 throw InvalidDataException();
618 m_data = make_unique<char[]>(m_decompressedSize =
static_cast<uint32
>(
value.
dataSize()));
621 }
catch (
const ConversionException &) {
625 argsToString(
"Assigned value(s) \"",
DiagMessage::formatList(valuesAsString),
"\" can not be converted appropriately."), context);
626 }
catch (
const ConversionException &) {
627 diag.emplace_back(
DiagLevel::Critical,
"Assigned value(s) can not be converted appropriately.", context);
629 throw InvalidDataException();
633 if (
version >= 3 && m_frame.isCompressed()) {
634 auto compressedSize = compressBound(m_decompressedSize);
635 auto compressedData = make_unique<char[]>(compressedSize);
636 switch (compress(reinterpret_cast<Bytef *>(compressedData.get()), reinterpret_cast<uLongf *>(&compressedSize),
637 reinterpret_cast<Bytef *
>(m_data.get()), m_decompressedSize)) {
639 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The source buffer was too small.", context);
640 throw InvalidDataException();
642 diag.emplace_back(
DiagLevel::Critical,
"Decompressing failed. The destination buffer was too small.", context);
643 throw InvalidDataException();
647 diag.emplace_back(
DiagLevel::Critical,
"Compressed size exceeds maximum data size.", context);
648 throw InvalidDataException();
650 m_data.swap(compressedData);
651 m_dataSize =
static_cast<uint32
>(compressedSize);
653 m_dataSize = m_decompressedSize;
658 m_requiredSize = m_dataSize;
664 m_requiredSize += 10;
666 if (m_frame.hasGroupInformation()) {
670 if (
version >= 3 && m_frame.isCompressed()) {
686 writer.writeUInt24BE(m_frameId);
687 writer.writeUInt24BE(m_dataSize);
689 writer.writeUInt32BE(m_frameId);
690 if (m_version >= 4) {
691 writer.writeSynchsafeUInt32BE(m_dataSize);
693 writer.writeUInt32BE(m_dataSize);
695 writer.writeUInt16BE(m_frame.
flag());
697 writer.writeByte(m_frame.
group());
700 if (m_version >= 4) {
701 writer.writeSynchsafeUInt32BE(m_decompressedSize);
703 writer.writeUInt32BE(m_decompressedSize);
707 writer.write(m_data.get(), m_dataSize);
718 switch (textEncodingByte) {
739 switch (textEncoding) {
770 tuple<const char *, size_t, const char *> res(buffer, 0, buffer + bufferSize);
775 if ((bufferSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
777 diag.emplace_back(
DiagLevel::Critical,
"Denoted character set is Latin-1 but an UTF-8 BOM is present - assuming UTF-8.",
783 const char *pos = get<0>(res);
784 for (; *pos != 0x00; ++pos) {
785 if (pos < get<2>(res)) {
795 get<2>(res) = pos + 1;
800 if (bufferSize >= 2) {
801 switch (ConversionUtilities::LE::toUInt16(buffer)) {
805 "Denoted character set is UTF-16 Big Endian but UTF-16 Little Endian BOM is present - assuming UTF-16 LE.",
816 const uint16 *pos =
reinterpret_cast<const uint16 *
>(get<0>(res));
817 for (; *pos != 0x0000; ++pos) {
818 if (pos < reinterpret_cast<const uint16 *>(get<2>(res))) {
828 get<2>(res) = reinterpret_cast<const char *>(pos + 1);
869 if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFFFE)) {
871 }
else if ((maxSize >= 2) && (ConversionUtilities::BE::toUInt16(buffer) == 0xFEFF)) {
876 if ((maxSize >= 3) && (ConversionUtilities::BE::toUInt24(buffer) == 0x00EFBBBF)) {
892 static const string context(
"parsing ID3v2.2 picture frame");
897 const char *end = buffer + maxSize;
899 typeInfo =
static_cast<unsigned char>(*(buffer + 4));
900 auto substr =
parseSubstring(buffer + 5, static_cast<size_t>(end - 5 - buffer), dataEncoding,
true, diag);
901 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
902 if (get<2>(substr) >= end) {
903 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
918 static const string context(
"parsing ID3v2.3 picture frame");
919 const char *end = buffer + maxSize;
922 auto substr =
parseSubstring(buffer + 1, maxSize - 1, mimeTypeEncoding,
true, diag);
923 if (get<1>(substr)) {
924 tagValue.
setMimeType(
string(get<0>(substr), get<1>(substr)));
926 if (get<2>(substr) >= end) {
927 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (type info, description and actual data are missing).", context);
930 typeInfo =
static_cast<unsigned char>(*get<2>(substr));
931 if (++get<2>(substr) >= end) {
932 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (description and actual data are missing).", context);
935 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
true, diag);
936 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
937 if (get<2>(substr) >= end) {
938 diag.emplace_back(
DiagLevel::Critical,
"Picture frame is incomplete (actual data is missing).", context);
952 static const string context(
"parsing comment/unsynchronized lyrics frame");
953 const char *end = buffer +
dataSize;
963 tagValue.
setDescription(
string(get<0>(substr), get<1>(substr)), dataEncoding);
964 if (get<2>(substr) > end) {
965 diag.emplace_back(
DiagLevel::Critical,
"Comment frame is incomplete (description not terminated?).", context);
968 substr =
parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding,
false, diag);
993 std::unique_ptr<
char[]> &buffer, uint32 &bufferSize,
TagTextEncoding encoding,
const char *data, std::size_t dataSize)
999 char *bufferDataAddress;
1005 buffer = make_unique<char[]>(bufferSize = 1 +
dataSize + 1);
1007 bufferDataAddress = buffer.get() + 1;
1012 buffer = make_unique<char[]>(bufferSize = 1 + 2 +
dataSize + 2);
1014 ConversionUtilities::LE::getBytes(
1016 bufferDataAddress = buffer.get() + 3;
1024 copy(data, data +
dataSize, bufferDataAddress);
1036 ConversionUtilities::LE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1039 ConversionUtilities::BE::getBytes(static_cast<uint16>(0xFEFF), buffer);
1053 StringData convertedDescription;
1054 string::size_type descriptionSize = picture.
description().find(
1056 if (descriptionSize == string::npos) {
1062 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1063 descriptionSize = convertedDescription.second;
1067 buffer = make_unique<char[]>(bufferSize = 1 + 3 + 1 + descriptionSize
1071 char *offset = buffer.get();
1075 const char *imageFormat;
1076 if (picture.
mimeType() ==
"image/jpeg") {
1077 imageFormat =
"JPG";
1078 }
else if (picture.
mimeType() ==
"image/png") {
1079 imageFormat =
"PNG";
1080 }
else if (picture.
mimeType() ==
"image/gif") {
1081 imageFormat =
"GIF";
1082 }
else if (picture.
mimeType() ==
"-->") {
1083 imageFormat = picture.
mimeType().data();
1085 imageFormat =
"UND";
1087 strncpy(++offset, imageFormat, 3);
1089 *(offset += 3) = static_cast<char>(
typeInfo);
1091 offset +=
makeBom(offset + 1, descriptionEncoding);
1092 if (convertedDescription.first) {
1093 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1095 picture.
description().copy(++offset, descriptionSize);
1097 *(offset += descriptionSize) = 0x00;
1117 StringData convertedDescription;
1118 string::size_type descriptionSize = picture.
description().find(
1120 if (descriptionSize == string::npos) {
1126 convertedDescription = convertUtf8ToUtf16LE(picture.
description().data(), descriptionSize);
1127 descriptionSize = convertedDescription.second;
1130 string::size_type mimeTypeSize = picture.
mimeType().find(
'\0');
1131 if (mimeTypeSize == string::npos) {
1132 mimeTypeSize = picture.
mimeType().length();
1136 buffer = make_unique<char[]>(bufferSize = 1 + mimeTypeSize + 1 + 1 + descriptionSize
1140 char *offset = buffer.get();
1144 picture.
mimeType().copy(++offset, mimeTypeSize);
1145 *(offset += mimeTypeSize) = 0x00;
1147 *(++offset) = static_cast<char>(
typeInfo);
1149 offset +=
makeBom(offset + 1, descriptionEncoding);
1150 if (convertedDescription.first) {
1151 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1153 picture.
description().copy(++offset, descriptionSize);
1155 *(offset += descriptionSize) = 0x00;
1168 static const string context(
"making comment frame");
1171 if (!
comment.description().empty() && encoding !=
comment.descriptionEncoding()) {
1172 diag.emplace_back(
DiagLevel::Critical,
"Data enoding and description encoding aren't equal.", context);
1175 const string &lng =
comment.language();
1176 if (lng.length() > 3) {
1177 diag.emplace_back(
DiagLevel::Critical,
"The language must be 3 bytes long (ISO-639-2).", context);
1180 StringData convertedDescription;
1181 string::size_type descriptionSize =
comment.description().find(
1183 if (descriptionSize == string::npos) {
1184 descriptionSize =
comment.description().size();
1189 convertedDescription = convertUtf8ToUtf16LE(
comment.description().data(), descriptionSize);
1190 descriptionSize = convertedDescription.second;
1193 const auto data =
comment.toString(encoding);
1194 buffer = make_unique<char[]>(bufferSize = 1 + 3 + descriptionSize + data.size()
1197 char *offset = buffer.get();
1201 for (
unsigned int i = 0; i < 3; ++i) {
1202 *(++offset) = (lng.length() > i) ? lng[i] : 0x00;
1205 offset +=
makeBom(offset + 1, encoding);
1206 if (convertedDescription.first) {
1207 copy(convertedDescription.first.get(), convertedDescription.first.get() + descriptionSize, ++offset);
1209 comment.description().copy(++offset, descriptionSize);
1211 offset += descriptionSize;
1217 offset +=
makeBom(offset + 1, encoding);
1218 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.