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>
28 case TagDataType::Text:
30 case TagDataType::Integer:
32 case TagDataType::PositionInSet:
33 return "position in set";
34 case TagDataType::StandardGenreIndex:
36 case TagDataType::TimeSpan:
40 case TagDataType::Picture:
42 case TagDataType::Binary:
54 switch (tagTextEncoding) {
55 case TagTextEncoding::Latin1:
56 return make_pair(
"ISO-8859-1", 1.0f);
58 return make_pair(
"UTF-8", 1.0f);
59 case TagTextEncoding::Utf16LittleEndian:
60 return make_pair(
"UTF-16LE", 2.0f);
61 case TagTextEncoding::Utf16BigEndian:
62 return make_pair(
"UTF-16BE", 2.0f);
64 return make_pair(
nullptr, 0.0f);
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)
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());
117 if (
this == &other) {
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;
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());
186 if (m_mimeType != other.m_mimeType || m_locale != other.m_locale || m_flags != other.m_flags) {
197 const auto utfEncodingToUse = pickUtfEncoding(m_descEncoding, other.m_descEncoding);
198 StringData str1, str2;
199 const char *data1, *data2;
201 if (m_descEncoding != utfEncodingToUse) {
203 str1 = convertString(
204 inputParameter.first, outputParameter.first, m_desc.data(), m_desc.size(), outputParameter.second / inputParameter.second);
205 data1 = str1.first.get();
208 data1 = m_desc.data();
209 size1 = m_desc.size();
211 if (other.m_descEncoding != 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();
218 data2 = other.m_desc.data();
219 size2 = other.m_desc.size();
228 if (m_type == other.m_type) {
232 if (m_size != other.m_size && m_encoding == other.m_encoding) {
240 const auto utfEncodingToUse = pickUtfEncoding(m_encoding, other.m_encoding);
242 const char *data1, *data2;
244 if (m_encoding != utfEncodingToUse) {
252 if (other.m_encoding != utfEncodingToUse) {
253 str2 = other.
toString(utfEncodingToUse);
257 data2 = other.m_ptr.get();
258 size2 = other.m_size;
281 for (
const auto dataType : { m_type, other.m_type }) {
295 }
catch (
const ConversionException &) {
329 switch (m_encoding) {
332 auto u16str = u16string(
reinterpret_cast<char16_t *
>(m_ptr.get()), m_size / 2);
334 return stringToNumber<std::int32_t>(u16str);
337 return bufferToNumber<std::int32_t>(m_ptr.get(), m_size);
341 return *
reinterpret_cast<std::int32_t *
>(m_ptr.get());
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());
349 throw ConversionException(
"Can not convert assigned data to integer because the data size is not appropriate.");
351 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to integer."));
370 }
catch (
const ConversionException &) {
382 if (m_size !=
sizeof(std::int32_t)) {
383 throw ConversionException(
"The assigned index/integer is of unappropriate size.");
385 index =
static_cast<int>(*
reinterpret_cast<std::int32_t *
>(m_ptr.get()));
388 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to genre index."));
391 throw ConversionException(
"The assigned number is not a valid standard genre index.");
408 switch (m_encoding) {
411 auto u16str = u16string(
reinterpret_cast<char16_t *
>(m_ptr.get()), m_size / 2);
421 case sizeof(std::int32_t):
422 return PositionInSet(*(
reinterpret_cast<std::int32_t *
>(m_ptr.get())));
423 case 2 *
sizeof(std::int32_t):
425 *(
reinterpret_cast<std::int32_t *
>(m_ptr.get())), *(
reinterpret_cast<std::int32_t *
>(m_ptr.get() +
sizeof(std::int32_t))));
427 throw ConversionException(
"The size of the assigned data is not appropriate.");
430 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to position in set."));
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())));
455 throw ConversionException(
"The size of the assigned integer is not appropriate for conversion to time span.");
458 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to time span."));
476 return DateTime::fromIsoStringGmt(str.data());
477 }
catch (
const ConversionException &) {
478 return DateTime::fromString(str);
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())));
488 throw ConversionException(
"The size of the assigned integer is not appropriate for conversion to date time.");
491 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to date time."));
506 if (m_encoding == encoding) {
510 StringData encodedData;
516 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
519 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
522 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
532 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
536 m_ptr = make_unique<char[]>(m_size = encodedData.second);
537 copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
539 m_encoding = encoding;
558 if (encoding == m_descEncoding) {
561 if (m_desc.empty()) {
562 m_descEncoding = encoding;
565 StringData encodedData;
571 encodedData = convertLatin1ToUtf8(m_desc.data(), m_desc.size());
574 encodedData = convertUtf16LEToUtf8(m_desc.data(), m_desc.size());
577 encodedData = convertUtf16BEToUtf8(m_desc.data(), m_desc.size());
586 encodedData = convertString(
587 inputParameter.first, outputParameter.first, m_desc.data(), m_desc.size(), outputParameter.second / inputParameter.second);
590 m_desc.assign(encodedData.first.get(), encodedData.second);
591 m_descEncoding = encoding;
616 result.assign(m_ptr.get(), m_size);
618 StringData encodedData;
624 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
627 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
630 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
640 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
643 result.assign(encodedData.first.get(), encodedData.second);
657 result.assign(genreName);
659 throw ConversionException(
"No string representation for the assigned standard genre index available.");
667 result =
toDateTime().toString(DateTimeOutputFormat::IsoOmittingDefaultComponents);
670 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to string."));
674 : convertUtf8ToUtf16BE(result.data(), result.size());
675 result.assign(encodedData.first.get(), encodedData.second);
696 string regularStrRes;
700 result.assign(
reinterpret_cast<const char16_t *
>(m_ptr.get()), m_size /
sizeof(char16_t));
702 StringData encodedData;
708 encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
711 encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
714 encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
724 = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
727 result.assign(
reinterpret_cast<const char16_t *
>(encodedData.first.get()), encodedData.second /
sizeof(char16_t));
731 regularStrRes = numberToString(
toInteger());
739 regularStrRes.clear();
741 regularStrRes.assign(genreName);
743 throw ConversionException(
"No string representation for the assigned standard genre index available.");
751 throw ConversionException(argsToString(
"Can not convert ",
tagDataTypeString(m_type),
" to string."));
755 : convertUtf8ToUtf16BE(regularStrRes.data(), result.size());
756 result.assign(
reinterpret_cast<const char16_t *
>(encodedData.first.get()), encodedData.second /
sizeof(
const char16_t));
775 stripBom(text, textSize, textEncoding);
783 m_ptr = make_unique<char[]>(m_size = textSize);
784 copy(text, text + textSize, m_ptr.get());
788 StringData encodedData;
789 switch (textEncoding) {
794 encodedData = convertUtf8ToLatin1(text, textSize);
797 encodedData = convertUtf8ToUtf16LE(text, textSize);
800 encodedData = convertUtf8ToUtf16BE(text, textSize);
809 encodedData = convertString(inputParameter.first, outputParameter.first, text, textSize, outputParameter.second / inputParameter.second);
813 m_ptr = make_unique<char[]>(m_size = encodedData.second);
814 copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
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());
843 if (length > m_size) {
844 m_ptr = make_unique<char[]>(length);
847 std::copy(
data,
data + length, m_ptr.get());
853 m_encoding = encoding;
872 m_encoding = encoding;
883 if ((length >= 3) && (BE::toUInt24(text) == 0x00EFBBBF)) {
889 if ((length >= 2) && (LE::toUInt16(text) == 0xFEFF)) {
895 if ((length >= 2) && (BE::toUInt16(text) == 0xFEFF)) {
910 if (currentEncoding !=
911 #
if defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN)
913 #elif defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN)
916 #error
"Host byte order not supported"
919 for (
auto &c : u16str) {
920 c = swapOrder(
static_cast<std::uint16_t
>(c));
928 bool TagValue::compareData(
const char *data1, std::size_t size1,
const char *data2, std::size_t size2,
bool ignoreCase)
930 if (size1 != size2) {
937 for (
auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
944 for (
auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
961 return emptyTagValue;
static constexpr bool isEmptyGenre(int index)
Returns whether the genre index indicates the genre field is not set at all.
static constexpr bool isIndexSupported(int index)
Returns an indication whether the specified numerical denotation is supported by this class.
static constexpr int emptyGenreIndex()
Returns the preferred genre index to indicate that no genre is set at all.
static int indexFromString(std::string_view genre)
Returns the numerical denotation of the specified genre or -1 if genre is unknown.
static std::string_view stringFromIndex(int index)
Returns the genre name for the specified numerical denotation as C-style string.
The PositionInSet class describes the position of an element in a set which consists of a certain num...
StringType toString() const
Returns the string representation of the current PositionInSet.
The TagValue class wraps values of different types.
bool compareData(const TagValue &other, bool ignoreCase=false) const
Returns whether the raw data of the current instance equals the raw data of other.
void clearMetadata()
Wipes assigned meta data.
void assignText(const char *text, std::size_t textSize, TagTextEncoding textEncoding=TagTextEncoding::Latin1, TagTextEncoding convertTo=TagTextEncoding::Unspecified)
Assigns a copy of the given text.
void assignInteger(int value)
Assigns the given integer value.
bool compareTo(const TagValue &other, TagValueComparisionFlags options=TagValueComparisionFlags::None) const
Returns whether both instances are equal.
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.
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
TagTextEncoding dataEncoding() const
Returns the data encoding.
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.
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
TagDataType type() const
Returns the type of the assigned value.
void convertDataEncodingForTag(const Tag *tag)
Ensures the encoding of the currently assigned text value is supported by the specified tag.
std::string_view data() const
Returns the currently assigned raw data.
std::u16string toWString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::wstring representation.
void convertDataEncoding(TagTextEncoding encoding)
Converts the currently assigned text value to the specified encoding.
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
TagValue & operator=(const TagValue &other)
Assigns the value of another TagValue to the current instance.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
static void stripBom(const char *&text, std::size_t &length, TagTextEncoding encoding)
Strips the byte order mask from the specified text.
bool isEmpty() const
Returns whether no or an empty value is assigned.
void convertDescriptionEncoding(TagTextEncoding encoding)
Converts the assigned description to use the specified encoding.
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
The Tag class is used to store, read and write tag information.
virtual TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
virtual bool canEncodingBeUsed(TagTextEncoding encoding) const
Returns an indication whether the specified encoding can be used to provide string values for the tag...
Contains all classes and functions of the TagInfo library.
std::string_view tagDataTypeString(TagDataType dataType)
Returns the string representation of the specified dataType.
TagTextEncoding
Specifies the text encoding.
TagValueComparisionFlags
The TagValueComparisionOption enum specifies options for TagValue::compareTo().
TagValueFlags
Specifies additional flags about the tag value.
TagDataType
Specifies the data type.
pair< const char *, float > encodingParameter(TagTextEncoding tagTextEncoding)
Returns the encoding parameter (name of the character set and bytes per character) for the specified ...
static constexpr unsigned char toLower(const unsigned char c)