Tag Parser 11.0.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
tagvalue.cpp
Go to the documentation of this file.
1#include "./tagvalue.h"
2
4#include "./tag.h"
5
6#include "./id3/id3genres.h"
7
8#include <c++utilities/conversion/binaryconversion.h>
9#include <c++utilities/conversion/conversionexception.h>
10#include <c++utilities/conversion/stringbuilder.h>
11#include <c++utilities/conversion/stringconversion.h>
12
13#include <algorithm>
14#include <cstring>
15#include <utility>
16
17using namespace std;
18using namespace CppUtilities;
19
20namespace TagParser {
21
25std::string_view tagDataTypeString(TagDataType dataType)
26{
27 switch (dataType) {
29 return "text";
31 return "integer";
33 return "position in set";
35 return "genre index";
37 return "time span";
39 return "date time";
41 return "picture";
43 return "binary";
44 default:
45 return "undefined";
46 }
47}
48
52pair<const char *, float> encodingParameter(TagTextEncoding tagTextEncoding)
53{
54 switch (tagTextEncoding) {
56 return make_pair("ISO-8859-1", 1.0f);
58 return make_pair("UTF-8", 1.0f);
60 return make_pair("UTF-16LE", 2.0f);
62 return make_pair("UTF-16BE", 2.0f);
63 default:
64 return make_pair(nullptr, 0.0f);
65 }
66}
67
97 : m_size(other.m_size)
98 , m_desc(other.m_desc)
99 , m_mimeType(other.m_mimeType)
100 , m_locale(other.m_locale)
101 , m_type(other.m_type)
102 , m_encoding(other.m_encoding)
103 , m_descEncoding(other.m_descEncoding)
104 , m_flags(TagValueFlags::None)
105{
106 if (!other.isEmpty()) {
107 m_ptr = make_unique<char[]>(m_size);
108 std::copy(other.m_ptr.get(), other.m_ptr.get() + other.m_size, m_ptr.get());
109 }
110}
111
116{
117 if (this == &other) {
118 return *this;
119 }
120 m_size = other.m_size;
121 m_type = other.m_type;
122 m_desc = other.m_desc;
123 m_mimeType = other.m_mimeType;
124 m_locale = other.m_locale;
125 m_flags = other.m_flags;
126 m_encoding = other.m_encoding;
127 m_descEncoding = other.m_descEncoding;
128 if (other.isEmpty()) {
129 m_ptr.reset();
130 } else {
131 m_ptr = make_unique<char[]>(m_size);
132 std::copy(other.m_ptr.get(), other.m_ptr.get() + other.m_size, m_ptr.get());
133 }
134 return *this;
135}
136
138TagTextEncoding pickUtfEncoding(TagTextEncoding encoding1, TagTextEncoding encoding2)
139{
140 switch (encoding1) {
144 return encoding1;
145 default:
146 switch (encoding2) {
150 return encoding2;
151 default:;
152 }
153 }
155}
157
182{
183 // check whether meta-data is equal (except description)
185 // check meta-data which always uses UTF-8 (everything but description)
186 if (m_mimeType != other.m_mimeType || m_locale != other.m_locale || m_flags != other.m_flags) {
187 return false;
188 }
189
190 // check description which might use different encodings
191 if (m_descEncoding == other.m_descEncoding || m_descEncoding == TagTextEncoding::Unspecified
192 || other.m_descEncoding == TagTextEncoding::Unspecified || m_desc.empty() || other.m_desc.empty()) {
193 if (!compareData(m_desc, other.m_desc, options & TagValueComparisionFlags::CaseInsensitive)) {
194 return false;
195 }
196 } else {
197 const auto utfEncodingToUse = pickUtfEncoding(m_descEncoding, other.m_descEncoding);
198 StringData str1, str2;
199 const char *data1, *data2;
200 size_t size1, size2;
201 if (m_descEncoding != utfEncodingToUse) {
202 const auto inputParameter = encodingParameter(m_descEncoding), outputParameter = encodingParameter(utfEncodingToUse);
203 str1 = convertString(
204 inputParameter.first, outputParameter.first, m_desc.data(), m_desc.size(), outputParameter.second / inputParameter.second);
205 data1 = str1.first.get();
206 size1 = str1.second;
207 } else {
208 data1 = m_desc.data();
209 size1 = m_desc.size();
210 }
211 if (other.m_descEncoding != utfEncodingToUse) {
212 const auto inputParameter = encodingParameter(other.m_descEncoding), outputParameter = encodingParameter(utfEncodingToUse);
213 str2 = convertString(inputParameter.first, outputParameter.first, other.m_desc.data(), other.m_desc.size(),
214 outputParameter.second / inputParameter.second);
215 data2 = str2.first.get();
216 size2 = str2.second;
217 } else {
218 data2 = other.m_desc.data();
219 size2 = other.m_desc.size();
220 }
221 if (!compareData(data1, size1, data2, size2, options & TagValueComparisionFlags::CaseInsensitive)) {
222 return false;
223 }
224 }
225 }
226
227 // check for equality if both types are identical
228 if (m_type == other.m_type) {
229 switch (m_type) {
230 case TagDataType::Text: {
231 // compare raw data directly if the encoding is the same
232 if (m_size != other.m_size && m_encoding == other.m_encoding) {
233 return false;
234 }
235 if (m_encoding == other.m_encoding || m_encoding == TagTextEncoding::Unspecified || other.m_encoding == TagTextEncoding::Unspecified) {
237 }
238
239 // compare UTF-8 or UTF-16 representation of strings avoiding unnecessary conversions
240 const auto utfEncodingToUse = pickUtfEncoding(m_encoding, other.m_encoding);
241 string str1, str2;
242 const char *data1, *data2;
243 size_t size1, size2;
244 if (m_encoding != utfEncodingToUse) {
245 str1 = toString(utfEncodingToUse);
246 data1 = str1.data();
247 size1 = str1.size();
248 } else {
249 data1 = m_ptr.get();
250 size1 = m_size;
251 }
252 if (other.m_encoding != utfEncodingToUse) {
253 str2 = other.toString(utfEncodingToUse);
254 data2 = str2.data();
255 size2 = str2.size();
256 } else {
257 data2 = other.m_ptr.get();
258 size2 = other.m_size;
259 }
260 return compareData(data1, size1, data2, size2, options & TagValueComparisionFlags::CaseInsensitive);
261 }
263 return toPositionInSet() == other.toPositionInSet();
265 return toInteger() == other.toInteger();
267 return toStandardGenreIndex() == other.toStandardGenreIndex();
269 return toTimeSpan() == other.toTimeSpan();
271 return toDateTime() == other.toDateTime();
275 return compareData(other);
276 }
277 return false;
278 }
279
280 // check for equality if types are different by comparing the string representation (if that makes sense)
281 for (const auto dataType : { m_type, other.m_type }) {
282 switch (dataType) {
288 // do not attempt to convert these types to string because it will always fail anyways
289 return false;
290 default:;
291 }
292 }
293 try {
294 return compareData(toString(), other.toString(m_encoding), options & TagValueComparisionFlags::CaseInsensitive);
295 } catch (const ConversionException &) {
296 return false;
297 }
298}
299
307{
308 m_desc.clear();
309 m_mimeType.clear();
310 m_locale.clear();
311 m_flags = TagValueFlags::None;
312 m_encoding = TagTextEncoding::Latin1;
313 m_descEncoding = TagTextEncoding::Latin1;
314 m_type = TagDataType::Undefined;
315}
316
322std::int32_t TagValue::toInteger() const
323{
324 if (isEmpty()) {
325 return 0;
326 }
327 switch (m_type) {
329 switch (m_encoding) {
332 auto u16str = u16string(reinterpret_cast<char16_t *>(m_ptr.get()), m_size / 2);
333 ensureHostByteOrder(u16str, m_encoding);
334 return stringToNumber<std::int32_t>(u16str);
335 }
336 default:
337 return bufferToNumber<std::int32_t>(m_ptr.get(), m_size);
338 }
340 if (m_size == sizeof(PositionInSet)) {
341 return *reinterpret_cast<std::int32_t *>(m_ptr.get());
342 }
343 throw ConversionException("Can not convert assigned data to integer because the data size is not appropriate.");
346 if (m_size == sizeof(std::int32_t)) {
347 return *reinterpret_cast<std::int32_t *>(m_ptr.get());
348 }
349 throw ConversionException("Can not convert assigned data to integer because the data size is not appropriate.");
350 default:
351 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to integer."));
352 }
353}
354
361{
362 if (isEmpty()) {
364 }
365 int index = 0;
366 switch (m_type) {
367 case TagDataType::Text: {
368 try {
369 index = toInteger();
370 } catch (const ConversionException &) {
372 if (m_encoding == TagTextEncoding::Latin1) {
373 // no need to convert Latin-1 to UTF-8 (makes no difference in case of genre strings)
375 }
376 index = Id3Genres::indexFromString(toString(encoding));
377 }
378 break;
379 }
382 if (m_size != sizeof(std::int32_t)) {
383 throw ConversionException("The assigned index/integer is of unappropriate size.");
384 }
385 index = static_cast<int>(*reinterpret_cast<std::int32_t *>(m_ptr.get()));
386 break;
387 default:
388 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to genre index."));
389 }
391 throw ConversionException("The assigned number is not a valid standard genre index.");
392 }
393 return index;
394}
395
402{
403 if (isEmpty()) {
404 return PositionInSet();
405 }
406 switch (m_type) {
408 switch (m_encoding) {
411 auto u16str = u16string(reinterpret_cast<char16_t *>(m_ptr.get()), m_size / 2);
412 ensureHostByteOrder(u16str, m_encoding);
413 return PositionInSet(u16str);
414 }
415 default:
416 return PositionInSet(string(m_ptr.get(), m_size));
417 }
420 switch (m_size) {
421 case sizeof(std::int32_t):
422 return PositionInSet(*(reinterpret_cast<std::int32_t *>(m_ptr.get())));
423 case 2 * sizeof(std::int32_t):
424 return PositionInSet(
425 *(reinterpret_cast<std::int32_t *>(m_ptr.get())), *(reinterpret_cast<std::int32_t *>(m_ptr.get() + sizeof(std::int32_t))));
426 default:
427 throw ConversionException("The size of the assigned data is not appropriate.");
428 }
429 default:
430 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to position in set."));
431 }
432}
433
440{
441 if (isEmpty()) {
442 return TimeSpan();
443 }
444 switch (m_type) {
446 return TimeSpan::fromString(toString(m_encoding == TagTextEncoding::Utf8 ? TagTextEncoding::Utf8 : TagTextEncoding::Latin1));
449 switch (m_size) {
450 case sizeof(std::int32_t):
451 return TimeSpan(*(reinterpret_cast<std::int32_t *>(m_ptr.get())));
452 case sizeof(std::int64_t):
453 return TimeSpan(*(reinterpret_cast<std::int64_t *>(m_ptr.get())));
454 default:
455 throw ConversionException("The size of the assigned integer is not appropriate for conversion to time span.");
456 }
457 default:
458 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to time span."));
459 }
460}
461
467DateTime TagValue::toDateTime() const
468{
469 if (isEmpty()) {
470 return DateTime();
471 }
472 switch (m_type) {
473 case TagDataType::Text: {
475 try {
476 return DateTime::fromIsoStringGmt(str.data());
477 } catch (const ConversionException &) {
478 return DateTime::fromString(str);
479 }
480 }
483 if (m_size == sizeof(std::int32_t)) {
484 return DateTime(*(reinterpret_cast<std::uint32_t *>(m_ptr.get())));
485 } else if (m_size == sizeof(std::int64_t)) {
486 return DateTime(*(reinterpret_cast<std::uint64_t *>(m_ptr.get())));
487 } else {
488 throw ConversionException("The size of the assigned integer is not appropriate for conversion to date time.");
489 }
490 default:
491 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to date time."));
492 }
493}
494
505{
506 if (m_encoding == encoding) {
507 return;
508 }
509 if (type() == TagDataType::Text) {
510 StringData encodedData;
511 switch (encoding) {
513 // use pre-defined methods when encoding to UTF-8
514 switch (dataEncoding()) {
516 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
517 break;
519 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
520 break;
522 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
523 break;
524 default:;
525 }
526 break;
527 default: {
528 // otherwise, determine input and output parameter to use general covertString method
529 const auto inputParameter = encodingParameter(dataEncoding());
530 const auto outputParameter = encodingParameter(encoding);
531 encodedData
532 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
533 }
534 }
535 // can't just move the encoded data because it needs to be deleted with free
536 m_ptr = make_unique<char[]>(m_size = encodedData.second);
537 copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
538 }
539 m_encoding = encoding;
540}
541
547{
550 }
551}
552
557{
558 if (encoding == m_descEncoding) {
559 return;
560 }
561 if (m_desc.empty()) {
562 m_descEncoding = encoding;
563 return;
564 }
565 StringData encodedData;
566 switch (encoding) {
568 // use pre-defined methods when encoding to UTF-8
569 switch (descriptionEncoding()) {
571 encodedData = convertLatin1ToUtf8(m_desc.data(), m_desc.size());
572 break;
574 encodedData = convertUtf16LEToUtf8(m_desc.data(), m_desc.size());
575 break;
577 encodedData = convertUtf16BEToUtf8(m_desc.data(), m_desc.size());
578 break;
579 default:;
580 }
581 break;
582 default: {
583 // otherwise, determine input and output parameter to use general covertString method
584 const auto inputParameter = encodingParameter(m_descEncoding);
585 const auto outputParameter = encodingParameter(encoding);
586 encodedData = convertString(
587 inputParameter.first, outputParameter.first, m_desc.data(), m_desc.size(), outputParameter.second / inputParameter.second);
588 }
589 }
590 m_desc.assign(encodedData.first.get(), encodedData.second);
591 m_descEncoding = encoding;
592}
593
606void TagValue::toString(string &result, TagTextEncoding encoding) const
607{
608 if (isEmpty()) {
609 result.clear();
610 return;
611 }
612
613 switch (m_type) {
616 result.assign(m_ptr.get(), m_size);
617 } else {
618 StringData encodedData;
619 switch (encoding) {
621 // use pre-defined methods when encoding to UTF-8
622 switch (dataEncoding()) {
624 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
625 break;
627 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
628 break;
630 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
631 break;
632 default:;
633 }
634 break;
635 default: {
636 // otherwise, determine input and output parameter to use general covertString method
637 const auto inputParameter = encodingParameter(dataEncoding());
638 const auto outputParameter = encodingParameter(encoding);
639 encodedData
640 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
641 }
642 }
643 result.assign(encodedData.first.get(), encodedData.second);
644 }
645 return;
647 result = numberToString(toInteger());
648 break;
650 result = toPositionInSet().toString();
651 break;
653 const auto genreIndex = toInteger();
654 if (Id3Genres::isEmptyGenre(genreIndex)) {
655 result.clear();
656 } else if (const auto genreName = Id3Genres::stringFromIndex(genreIndex); !genreName.empty()) {
657 result.assign(genreName);
658 } else {
659 throw ConversionException("No string representation for the assigned standard genre index available.");
660 }
661 break;
662 }
664 result = toTimeSpan().toString();
665 break;
667 result = toDateTime().toString(DateTimeOutputFormat::IsoOmittingDefaultComponents);
668 break;
669 default:
670 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to string."));
671 }
673 auto encodedData = encoding == TagTextEncoding::Utf16LittleEndian ? convertUtf8ToUtf16LE(result.data(), result.size())
674 : convertUtf8ToUtf16BE(result.data(), result.size());
675 result.assign(encodedData.first.get(), encodedData.second);
676 }
677}
678
689void TagValue::toWString(std::u16string &result, TagTextEncoding encoding) const
690{
691 if (isEmpty()) {
692 result.clear();
693 return;
694 }
695
696 string regularStrRes;
697 switch (m_type) {
699 if (encoding == TagTextEncoding::Unspecified || encoding == dataEncoding()) {
700 result.assign(reinterpret_cast<const char16_t *>(m_ptr.get()), m_size / sizeof(char16_t));
701 } else {
702 StringData encodedData;
703 switch (encoding) {
705 // use pre-defined methods when encoding to UTF-8
706 switch (dataEncoding()) {
708 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
709 break;
711 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
712 break;
714 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
715 break;
716 default:;
717 }
718 break;
719 default: {
720 // otherwise, determine input and output parameter to use general covertString method
721 const auto inputParameter = encodingParameter(dataEncoding());
722 const auto outputParameter = encodingParameter(encoding);
723 encodedData
724 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
725 }
726 }
727 result.assign(reinterpret_cast<const char16_t *>(encodedData.first.get()), encodedData.second / sizeof(char16_t));
728 }
729 return;
731 regularStrRes = numberToString(toInteger());
732 break;
734 regularStrRes = toPositionInSet().toString();
735 break;
737 const auto genreIndex = toInteger();
738 if (Id3Genres::isEmptyGenre(genreIndex)) {
739 regularStrRes.clear();
740 } else if (const auto genreName = Id3Genres::stringFromIndex(genreIndex); !genreName.empty()) {
741 regularStrRes.assign(genreName);
742 } else {
743 throw ConversionException("No string representation for the assigned standard genre index available.");
744 }
745 break;
746 }
748 regularStrRes = toTimeSpan().toString();
749 break;
750 default:
751 throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to string."));
752 }
754 auto encodedData = encoding == TagTextEncoding::Utf16LittleEndian ? convertUtf8ToUtf16LE(regularStrRes.data(), result.size())
755 : convertUtf8ToUtf16BE(regularStrRes.data(), result.size());
756 result.assign(reinterpret_cast<const char16_t *>(encodedData.first.get()), encodedData.second / sizeof(const char16_t));
757 }
758}
759
770void TagValue::assignText(const char *text, std::size_t textSize, TagTextEncoding textEncoding, TagTextEncoding convertTo)
771{
772 m_type = TagDataType::Text;
773 m_encoding = convertTo == TagTextEncoding::Unspecified ? textEncoding : convertTo;
774
775 stripBom(text, textSize, textEncoding);
776 if (!textSize) {
777 m_size = 0;
778 m_ptr.reset();
779 return;
780 }
781
782 if (convertTo == TagTextEncoding::Unspecified || textEncoding == convertTo) {
783 m_ptr = make_unique<char[]>(m_size = textSize);
784 copy(text, text + textSize, m_ptr.get());
785 return;
786 }
787
788 StringData encodedData;
789 switch (textEncoding) {
791 // use pre-defined methods when encoding to UTF-8
792 switch (convertTo) {
794 encodedData = convertUtf8ToLatin1(text, textSize);
795 break;
797 encodedData = convertUtf8ToUtf16LE(text, textSize);
798 break;
800 encodedData = convertUtf8ToUtf16BE(text, textSize);
801 break;
802 default:;
803 }
804 break;
805 default: {
806 // otherwise, determine input and output parameter to use general covertString method
807 const auto inputParameter = encodingParameter(textEncoding);
808 const auto outputParameter = encodingParameter(convertTo);
809 encodedData = convertString(inputParameter.first, outputParameter.first, text, textSize, outputParameter.second / inputParameter.second);
810 }
811 }
812 // can't just move the encoded data because it needs to be deleted with free
813 m_ptr = make_unique<char[]>(m_size = encodedData.second);
814 copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
815}
816
822{
823 m_size = sizeof(value);
824 m_ptr = make_unique<char[]>(m_size);
825 std::copy(reinterpret_cast<const char *>(&value), reinterpret_cast<const char *>(&value) + m_size, m_ptr.get());
826 m_type = TagDataType::Integer;
827 m_encoding = TagTextEncoding::Latin1;
828}
829
838void TagValue::assignData(const char *data, size_t length, TagDataType type, TagTextEncoding encoding)
839{
840 if (type == TagDataType::Text) {
841 stripBom(data, length, encoding);
842 }
843 if (length > m_size) {
844 m_ptr = make_unique<char[]>(length);
845 }
846 if (length) {
847 std::copy(data, data + length, m_ptr.get());
848 } else {
849 m_ptr.reset();
850 }
851 m_size = length;
852 m_type = type;
853 m_encoding = encoding;
854}
855
868void TagValue::assignData(unique_ptr<char[]> &&data, size_t length, TagDataType type, TagTextEncoding encoding)
869{
870 m_size = length;
871 m_type = type;
872 m_encoding = encoding;
873 m_ptr = move(data);
874}
875
879void TagValue::stripBom(const char *&text, size_t &length, TagTextEncoding encoding)
880{
881 switch (encoding) {
883 if ((length >= 3) && (BE::toUInt24(text) == 0x00EFBBBF)) {
884 text += 3;
885 length -= 3;
886 }
887 break;
889 if ((length >= 2) && (LE::toUInt16(text) == 0xFEFF)) {
890 text += 2;
891 length -= 2;
892 }
893 break;
895 if ((length >= 2) && (BE::toUInt16(text) == 0xFEFF)) {
896 text += 2;
897 length -= 2;
898 }
899 break;
900 default:;
901 }
902}
903
908void TagValue::ensureHostByteOrder(u16string &u16str, TagTextEncoding currentEncoding)
909{
910 if (currentEncoding !=
911#if defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN)
913#elif defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN)
915#else
916#error "Host byte order not supported"
917#endif
918 ) {
919 for (auto &c : u16str) {
920 c = swapOrder(static_cast<std::uint16_t>(c));
921 }
922 }
923}
924
928bool TagValue::compareData(const char *data1, std::size_t size1, const char *data2, std::size_t size2, bool ignoreCase)
929{
930 if (size1 != size2) {
931 return false;
932 }
933 if (!size1) {
934 return true;
935 }
936 if (ignoreCase) {
937 for (auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
938 if (CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i1))
939 != CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i2))) {
940 return false;
941 }
942 }
943 } else {
944 for (auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
945 if (*i1 != *i2) {
946 return false;
947 }
948 }
949 }
950 return true;
951}
952
959{
960 static TagValue emptyTagValue;
961 return emptyTagValue;
962}
963
964} // namespace TagParser
static constexpr bool isEmptyGenre(int index)
Returns whether the genre index indicates the genre field is not set at all.
Definition: id3genres.h:53
static constexpr bool isIndexSupported(int index)
Returns an indication whether the specified numerical denotation is supported by this class.
Definition: id3genres.h:62
static constexpr int emptyGenreIndex()
Returns the preferred genre index to indicate that no genre is set at all.
Definition: id3genres.h:45
static int indexFromString(std::string_view genre)
Returns the numerical denotation of the specified genre or -1 if genre is unknown.
Definition: id3genres.cpp:42
static std::string_view stringFromIndex(int index)
Returns the genre name for the specified numerical denotation as C-style string.
Definition: id3genres.h:27
The PositionInSet class describes the position of an element in a set which consists of a certain num...
Definition: positioninset.h:21
StringType toString() const
Returns the string representation of the current PositionInSet.
The TagValue class wraps values of different types.
Definition: tagvalue.h:95
bool compareData(const TagValue &other, bool ignoreCase=false) const
Returns whether the raw data of the current instance equals the raw data of other.
Definition: tagvalue.h:789
void clearMetadata()
Wipes assigned meta data.
Definition: tagvalue.cpp:306
void assignText(const char *text, std::size_t textSize, TagTextEncoding textEncoding=TagTextEncoding::Latin1, TagTextEncoding convertTo=TagTextEncoding::Unspecified)
Assigns a copy of the given text.
Definition: tagvalue.cpp:770
void assignInteger(int value)
Assigns the given integer value.
Definition: tagvalue.cpp:821
bool compareTo(const TagValue &other, TagValueComparisionFlags options=TagValueComparisionFlags::None) const
Returns whether both instances are equal.
Definition: tagvalue.cpp:181
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.
Definition: tagvalue.cpp:908
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
Definition: tagvalue.cpp:467
TagTextEncoding dataEncoding() const
Returns the data encoding.
Definition: tagvalue.h:753
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
std::int32_t toInteger() const
Converts the value of the current TagValue object to its equivalent integer representation.
Definition: tagvalue.cpp:322
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition: tagvalue.cpp:401
TagDataType type() const
Returns the type of the assigned value.
Definition: tagvalue.h:468
void convertDataEncodingForTag(const Tag *tag)
Ensures the encoding of the currently assigned text value is supported by the specified tag.
Definition: tagvalue.cpp:546
std::string_view data() const
Returns the currently assigned raw data.
Definition: tagvalue.h:581
std::u16string toWString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::wstring representation.
Definition: tagvalue.h:498
void convertDataEncoding(TagTextEncoding encoding)
Converts the currently assigned text value to the specified encoding.
Definition: tagvalue.cpp:504
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
Definition: tagvalue.h:763
TagValue & operator=(const TagValue &other)
Assigns the value of another TagValue to the current instance.
Definition: tagvalue.cpp:115
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
Definition: tagvalue.h:485
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition: tagvalue.cpp:958
static void stripBom(const char *&text, std::size_t &length, TagTextEncoding encoding)
Strips the byte order mask from the specified text.
Definition: tagvalue.cpp:879
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition: tagvalue.h:525
void convertDescriptionEncoding(TagTextEncoding encoding)
Converts the assigned description to use the specified encoding.
Definition: tagvalue.cpp:556
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Definition: tagvalue.cpp:360
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition: tagvalue.cpp:439
TagValue()
Constructs an empty TagValue.
Definition: tagvalue.h:209
The Tag class is used to store, read and write tag information.
Definition: tag.h:108
virtual TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
Definition: tag.h:159
virtual bool canEncodingBeUsed(TagTextEncoding encoding) const
Returns an indication whether the specified encoding can be used to provide string values for the tag...
Definition: tag.h:164
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
std::string_view tagDataTypeString(TagDataType dataType)
Returns the string representation of the specified dataType.
Definition: tagvalue.cpp:25
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:28
pair< const char *, float > encodingParameter(TagTextEncoding tagTextEncoding)
Returns the encoding parameter (name of the character set and bytes per character) for the specified ...
Definition: tagvalue.cpp:52
TagValueComparisionFlags
The TagValueComparisionOption enum specifies options for TagValue::compareTo().
Definition: tagvalue.h:89
TagValueFlags
Specifies additional flags about the tag value.
Definition: tagvalue.h:42
TagDataType
Specifies the data type.
Definition: tagvalue.h:74
static constexpr unsigned char toLower(const unsigned char c)