Tag Parser  9.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 
17 using namespace std;
18 using namespace CppUtilities;
19 
20 namespace TagParser {
21 
25 const char *tagDataTypeString(TagDataType dataType)
26 {
27  switch (dataType) {
28  case TagDataType::Text:
29  return "text";
30  case TagDataType::Integer:
31  return "integer";
32  case TagDataType::PositionInSet:
33  return "position in set";
34  case TagDataType::StandardGenreIndex:
35  return "genre index";
36  case TagDataType::TimeSpan:
37  return "time span";
39  return "date time";
40  case TagDataType::Picture:
41  return "picture";
42  case TagDataType::Binary:
43  return "binary";
44  default:
45  return "undefined";
46  }
47 }
48 
52 pair<const char *, float> encodingParameter(TagTextEncoding tagTextEncoding)
53 {
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);
63  default:
64  return make_pair(nullptr, 0.0f);
65  }
66 }
67 
96 TagValue::TagValue(const TagValue &other)
97  : m_size(other.m_size)
98  , m_desc(other.m_desc)
99  , m_mimeType(other.m_mimeType)
100  , m_language(other.m_language)
101  , m_type(other.m_type)
102  , m_encoding(other.m_encoding)
103  , m_descEncoding(other.m_descEncoding)
104  , m_labeledAsReadonly(other.m_labeledAsReadonly)
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_language = other.m_language;
125  m_labeledAsReadonly = other.m_labeledAsReadonly;
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 
138 TagTextEncoding pickUtfEncoding(TagTextEncoding encoding1, TagTextEncoding encoding2)
139 {
140  switch (encoding1) {
144  return encoding1;
145  default:
146  switch (encoding2) {
150  return encoding2;
151  default:;
152  }
153  }
154  return TagTextEncoding::Utf8;
155 }
157 
181 bool TagValue::compareTo(const TagValue &other, TagValueComparisionFlags options) const
182 {
183  // check whether meta-data is equal (except description)
184  if (!(options & TagValueComparisionFlags::IgnoreMetaData)) {
185  // check meta-data which always uses UTF-8 (everything but description)
186  if (m_mimeType != other.m_mimeType || m_language != other.m_language || m_labeledAsReadonly != other.m_labeledAsReadonly) {
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();
273  case TagDataType::Binary:
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) {
286  case TagDataType::Binary:
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 
308 {
309  m_desc.clear();
310  m_mimeType.clear();
311  m_language.clear();
312  m_labeledAsReadonly = false;
313  m_encoding = TagTextEncoding::Latin1;
314  m_descEncoding = TagTextEncoding::Latin1;
315  m_type = TagDataType::Undefined;
316 }
317 
323 std::int32_t TagValue::toInteger() const
324 {
325  if (isEmpty()) {
326  return 0;
327  }
328  switch (m_type) {
329  case TagDataType::Text:
330  switch (m_encoding) {
334  return bufferToNumber<std::int32_t>(m_ptr.get(), m_size);
337  u16string u16str(reinterpret_cast<char16_t *>(m_ptr.get()), m_size / 2);
338  ensureHostByteOrder(u16str, m_encoding);
339  return stringToNumber<std::int32_t>(u16str);
340  }
342  if (m_size == sizeof(PositionInSet)) {
343  return *reinterpret_cast<std::int32_t *>(m_ptr.get());
344  }
345  throw ConversionException("Can not convert assigned data to integer because the data size is not appropriate.");
348  if (m_size == sizeof(std::int32_t)) {
349  return *reinterpret_cast<std::int32_t *>(m_ptr.get());
350  }
351  throw ConversionException("Can not convert assigned data to integer because the data size is not appropriate.");
352  default:
353  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to integer."));
354  }
355 }
356 
363 {
364  if (isEmpty()) {
366  }
367  int index = 0;
368  switch (m_type) {
369  case TagDataType::Text: {
370  try {
371  index = toInteger();
372  } catch (const ConversionException &) {
374  if (m_encoding == TagTextEncoding::Latin1) {
375  // no need to convert Latin-1 to UTF-8 (makes no difference in case of genre strings)
376  encoding = TagTextEncoding::Unspecified;
377  }
378  index = Id3Genres::indexFromString(toString(encoding));
379  }
380  break;
381  }
384  if (m_size != sizeof(std::int32_t)) {
385  throw ConversionException("The assigned index/integer is of unappropriate size.");
386  }
387  index = static_cast<int>(*reinterpret_cast<std::int32_t *>(m_ptr.get()));
388  break;
389  default:
390  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to genre index."));
391  }
392  if (!Id3Genres::isEmptyGenre(index) && !Id3Genres::isIndexSupported(index)) {
393  throw ConversionException("The assigned number is not a valid standard genre index.");
394  }
395  return index;
396 }
397 
404 {
405  if (isEmpty()) {
406  return PositionInSet();
407  }
408  switch (m_type) {
409  case TagDataType::Text:
410  switch (m_encoding) {
414  return PositionInSet(string(m_ptr.get(), m_size));
417  u16string u16str(reinterpret_cast<char16_t *>(m_ptr.get()), m_size / 2);
418  ensureHostByteOrder(u16str, m_encoding);
419  return PositionInSet(u16str);
420  }
423  switch (m_size) {
424  case sizeof(std::int32_t):
425  return PositionInSet(*(reinterpret_cast<std::int32_t *>(m_ptr.get())));
426  case 2 * sizeof(std::int32_t):
427  return PositionInSet(
428  *(reinterpret_cast<std::int32_t *>(m_ptr.get())), *(reinterpret_cast<std::int32_t *>(m_ptr.get() + sizeof(std::int32_t))));
429  default:
430  throw ConversionException("The size of the assigned data is not appropriate.");
431  }
432  default:
433  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to position in set."));
434  }
435 }
436 
443 {
444  if (isEmpty()) {
445  return TimeSpan();
446  }
447  switch (m_type) {
448  case TagDataType::Text:
449  return TimeSpan::fromString(toString(m_encoding == TagTextEncoding::Utf8 ? TagTextEncoding::Utf8 : TagTextEncoding::Latin1));
452  switch (m_size) {
453  case sizeof(std::int32_t):
454  return TimeSpan(*(reinterpret_cast<std::int32_t *>(m_ptr.get())));
455  case sizeof(std::int64_t):
456  return TimeSpan(*(reinterpret_cast<std::int64_t *>(m_ptr.get())));
457  default:
458  throw ConversionException("The size of the assigned integer is not appropriate for conversion to time span.");
459  }
460  default:
461  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to time span."));
462  }
463 }
464 
470 DateTime TagValue::toDateTime() const
471 {
472  if (isEmpty()) {
473  return DateTime();
474  }
475  switch (m_type) {
476  case TagDataType::Text:
477  return DateTime::fromString(toString(m_encoding == TagTextEncoding::Utf8 ? TagTextEncoding::Utf8 : TagTextEncoding::Latin1));
480  if (m_size == sizeof(std::int32_t)) {
481  return DateTime(*(reinterpret_cast<std::uint32_t *>(m_ptr.get())));
482  } else if (m_size == sizeof(std::int64_t)) {
483  return DateTime(*(reinterpret_cast<std::uint64_t *>(m_ptr.get())));
484  } else {
485  throw ConversionException("The size of the assigned integer is not appropriate for conversion to date time.");
486  }
487  default:
488  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to date time."));
489  }
490 }
491 
502 {
503  if (m_encoding == encoding) {
504  return;
505  }
506  if (type() == TagDataType::Text) {
507  StringData encodedData;
508  switch (encoding) {
510  // use pre-defined methods when encoding to UTF-8
511  switch (dataEncoding()) {
513  encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
514  break;
516  encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
517  break;
519  encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
520  break;
521  default:;
522  }
523  break;
524  default: {
525  // otherwise, determine input and output parameter to use general covertString method
526  const auto inputParameter = encodingParameter(dataEncoding());
527  const auto outputParameter = encodingParameter(encoding);
528  encodedData
529  = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
530  }
531  }
532  // can't just move the encoded data because it needs to be deleted with free
533  m_ptr = make_unique<char[]>(m_size = encodedData.second);
534  copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
535  }
536  m_encoding = encoding;
537 }
538 
544 {
545  if (type() == TagDataType::Text && !tag->canEncodingBeUsed(dataEncoding())) {
547  }
548 }
549 
554 {
555  if (encoding == m_descEncoding) {
556  return;
557  }
558  if (m_desc.empty()) {
559  m_descEncoding = encoding;
560  return;
561  }
562  StringData encodedData;
563  switch (encoding) {
565  // use pre-defined methods when encoding to UTF-8
566  switch (dataEncoding()) {
568  encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
569  break;
571  encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
572  break;
574  encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
575  break;
576  default:;
577  }
578  break;
579  default: {
580  // otherwise, determine input and output parameter to use general covertString method
581  const auto inputParameter = encodingParameter(m_descEncoding);
582  const auto outputParameter = encodingParameter(encoding);
583  encodedData = convertString(
584  inputParameter.first, outputParameter.first, m_desc.data(), m_desc.size(), outputParameter.second / inputParameter.second);
585  }
586  }
587  m_desc.assign(encodedData.first.get(), encodedData.second);
588  m_descEncoding = encoding;
589 }
590 
603 void TagValue::toString(string &result, TagTextEncoding encoding) const
604 {
605  if (isEmpty()) {
606  result.clear();
607  return;
608  }
609 
610  switch (m_type) {
611  case TagDataType::Text:
612  if (encoding == TagTextEncoding::Unspecified || dataEncoding() == TagTextEncoding::Unspecified || encoding == dataEncoding()) {
613  result.assign(m_ptr.get(), m_size);
614  } else {
615  StringData encodedData;
616  switch (encoding) {
618  // use pre-defined methods when encoding to UTF-8
619  switch (dataEncoding()) {
621  encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
622  break;
624  encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
625  break;
627  encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
628  break;
629  default:;
630  }
631  break;
632  default: {
633  // otherwise, determine input and output parameter to use general covertString method
634  const auto inputParameter = encodingParameter(dataEncoding());
635  const auto outputParameter = encodingParameter(encoding);
636  encodedData
637  = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
638  }
639  }
640  result.assign(encodedData.first.get(), encodedData.second);
641  }
642  return;
644  result = numberToString(toInteger());
645  break;
647  result = toPositionInSet().toString();
648  break;
650  const auto genreIndex = toInteger();
651  if (Id3Genres::isEmptyGenre(genreIndex)) {
652  result.clear();
653  } else if (const char *genreName = Id3Genres::stringFromIndex(genreIndex)) {
654  result.assign(genreName);
655  } else {
656  throw ConversionException("No string representation for the assigned standard genre index available.");
657  }
658  break;
659  }
661  result = toTimeSpan().toString();
662  break;
664  result = toDateTime().toString();
665  break;
666  default:
667  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to string."));
668  }
670  auto encodedData = encoding == TagTextEncoding::Utf16LittleEndian ? convertUtf8ToUtf16LE(result.data(), result.size())
671  : convertUtf8ToUtf16BE(result.data(), result.size());
672  result.assign(encodedData.first.get(), encodedData.second);
673  }
674 }
675 
686 void TagValue::toWString(std::u16string &result, TagTextEncoding encoding) const
687 {
688  if (isEmpty()) {
689  result.clear();
690  return;
691  }
692 
693  string regularStrRes;
694  switch (m_type) {
695  case TagDataType::Text:
696  if (encoding == TagTextEncoding::Unspecified || encoding == dataEncoding()) {
697  result.assign(reinterpret_cast<const char16_t *>(m_ptr.get()), m_size / sizeof(char16_t));
698  } else {
699  StringData encodedData;
700  switch (encoding) {
702  // use pre-defined methods when encoding to UTF-8
703  switch (dataEncoding()) {
705  encodedData = convertLatin1ToUtf8(m_ptr.get(), m_size);
706  break;
708  encodedData = convertUtf16LEToUtf8(m_ptr.get(), m_size);
709  break;
711  encodedData = convertUtf16BEToUtf8(m_ptr.get(), m_size);
712  break;
713  default:;
714  }
715  break;
716  default: {
717  // otherwise, determine input and output parameter to use general covertString method
718  const auto inputParameter = encodingParameter(dataEncoding());
719  const auto outputParameter = encodingParameter(encoding);
720  encodedData
721  = convertString(inputParameter.first, outputParameter.first, m_ptr.get(), m_size, outputParameter.second / inputParameter.second);
722  }
723  }
724  result.assign(reinterpret_cast<const char16_t *>(encodedData.first.get()), encodedData.second / sizeof(char16_t));
725  }
726  return;
728  regularStrRes = numberToString(toInteger());
729  break;
731  regularStrRes = toPositionInSet().toString();
732  break;
734  const auto genreIndex = toInteger();
735  if (Id3Genres::isEmptyGenre(genreIndex)) {
736  regularStrRes.clear();
737  } else if (const char *genreName = Id3Genres::stringFromIndex(genreIndex)) {
738  regularStrRes.assign(genreName);
739  } else {
740  throw ConversionException("No string representation for the assigned standard genre index available.");
741  }
742  break;
743  }
745  regularStrRes = toTimeSpan().toString();
746  break;
747  default:
748  throw ConversionException(argsToString("Can not convert ", tagDataTypeString(m_type), " to string."));
749  }
751  auto encodedData = encoding == TagTextEncoding::Utf16LittleEndian ? convertUtf8ToUtf16LE(regularStrRes.data(), result.size())
752  : convertUtf8ToUtf16BE(regularStrRes.data(), result.size());
753  result.assign(reinterpret_cast<const char16_t *>(encodedData.first.get()), encodedData.second / sizeof(const char16_t));
754  }
755 }
756 
767 void TagValue::assignText(const char *text, std::size_t textSize, TagTextEncoding textEncoding, TagTextEncoding convertTo)
768 {
769  m_type = TagDataType::Text;
770  m_encoding = convertTo == TagTextEncoding::Unspecified ? textEncoding : convertTo;
771 
772  stripBom(text, textSize, textEncoding);
773  if (!textSize) {
774  m_size = 0;
775  m_ptr.reset();
776  return;
777  }
778 
779  if (convertTo == TagTextEncoding::Unspecified || textEncoding == convertTo) {
780  m_ptr = make_unique<char[]>(m_size = textSize);
781  copy(text, text + textSize, m_ptr.get());
782  return;
783  }
784 
785  StringData encodedData;
786  switch (textEncoding) {
788  // use pre-defined methods when encoding to UTF-8
789  switch (convertTo) {
791  encodedData = convertUtf8ToLatin1(text, textSize);
792  break;
794  encodedData = convertUtf8ToUtf16LE(text, textSize);
795  break;
797  encodedData = convertUtf8ToUtf16BE(text, textSize);
798  break;
799  default:;
800  }
801  break;
802  default: {
803  // otherwise, determine input and output parameter to use general covertString method
804  const auto inputParameter = encodingParameter(textEncoding);
805  const auto outputParameter = encodingParameter(convertTo);
806  encodedData = convertString(inputParameter.first, outputParameter.first, text, textSize, outputParameter.second / inputParameter.second);
807  }
808  }
809  // can't just move the encoded data because it needs to be deleted with free
810  m_ptr = make_unique<char[]>(m_size = encodedData.second);
811  copy(encodedData.first.get(), encodedData.first.get() + encodedData.second, m_ptr.get());
812 }
813 
818 void TagValue::assignInteger(int value)
819 {
820  m_size = sizeof(value);
821  m_ptr = make_unique<char[]>(m_size);
822  std::copy(reinterpret_cast<const char *>(&value), reinterpret_cast<const char *>(&value) + m_size, m_ptr.get());
823  m_type = TagDataType::Integer;
824  m_encoding = TagTextEncoding::Latin1;
825 }
826 
835 void TagValue::assignData(const char *data, size_t length, TagDataType type, TagTextEncoding encoding)
836 {
837  if (type == TagDataType::Text) {
838  stripBom(data, length, encoding);
839  }
840  if (length > m_size) {
841  m_ptr = make_unique<char[]>(length);
842  }
843  if (length) {
844  std::copy(data, data + length, m_ptr.get());
845  } else {
846  m_ptr.reset();
847  }
848  m_size = length;
849  m_type = type;
850  m_encoding = encoding;
851 }
852 
865 void TagValue::assignData(unique_ptr<char[]> &&data, size_t length, TagDataType type, TagTextEncoding encoding)
866 {
867  m_size = length;
868  m_type = type;
869  m_encoding = encoding;
870  m_ptr = move(data);
871 }
872 
876 void TagValue::stripBom(const char *&text, size_t &length, TagTextEncoding encoding)
877 {
878  switch (encoding) {
880  if ((length >= 3) && (BE::toUInt24(text) == 0x00EFBBBF)) {
881  text += 3;
882  length -= 3;
883  }
884  break;
886  if ((length >= 2) && (LE::toUInt16(text) == 0xFEFF)) {
887  text += 2;
888  length -= 2;
889  }
890  break;
892  if ((length >= 2) && (BE::toUInt16(text) == 0xFEFF)) {
893  text += 2;
894  length -= 2;
895  }
896  break;
897  default:;
898  }
899 }
900 
905 void TagValue::ensureHostByteOrder(u16string &u16str, TagTextEncoding currentEncoding)
906 {
907  if (currentEncoding !=
908 #if defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN)
910 #elif defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN)
912 #else
913 #error "Host byte order not supported"
914 #endif
915  ) {
916  for (auto &c : u16str) {
917  c = swapOrder(static_cast<std::uint16_t>(c));
918  }
919  }
920 }
921 
925 bool TagValue::compareData(const char *data1, std::size_t size1, const char *data2, std::size_t size2, bool ignoreCase)
926 {
927  if (size1 != size2) {
928  return false;
929  }
930  if (!size1) {
931  return true;
932  }
933  if (ignoreCase) {
934  for (auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
935  if (CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i1))
936  != CaseInsensitiveCharComparer::toLower(static_cast<unsigned char>(*i2))) {
937  return false;
938  }
939  }
940  } else {
941  for (auto i1 = data1, i2 = data2, end = data1 + size1; i1 != end; ++i1, ++i2) {
942  if (*i1 != *i2) {
943  return false;
944  }
945  }
946  }
947  return true;
948 }
949 
956 {
957  static TagValue emptyTagValue;
958  return emptyTagValue;
959 }
960 
961 } // namespace TagParser
TagParser::MediaType::Text
TagParser::TagValueComparisionFlags::IgnoreMetaData
TagParser::TagDataType::TimeSpan
TagParser::TagTextEncoding::Utf8
TagParser::RawDataType::Utf8
Definition: mp4tagfield.h:21
caseinsensitivecomparer.h
TagParser::TagTextEncoding
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:25
TagParser::TagValue::convertDataEncoding
void convertDataEncoding(TagTextEncoding encoding)
Converts the currently assigned text value to the specified encoding.
Definition: tagvalue.cpp:501
TagParser::TagValue::toStandardGenreIndex
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Definition: tagvalue.cpp:362
TagParser::tagDataTypeString
const char * tagDataTypeString(TagDataType dataType)
Returns the string representation of the specified dataType.
Definition: tagvalue.cpp:25
TagParser::TagValue::operator=
TagValue & operator=(const TagValue &other)
Assigns the value of another TagValue to the current instance.
Definition: tagvalue.cpp:115
TagParser::TagTextEncoding::Utf16BigEndian
TagParser::TagValue::toPositionInSet
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition: tagvalue.cpp:403
TagParser::TagValue::compareData
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:639
tagvalue.h
TagParser::TagValue::ensureHostByteOrder
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:905
TagParser::Tag
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
TagParser::TagValue::stripBom
static void stripBom(const char *&text, std::size_t &length, TagTextEncoding encoding)
Strips the byte order mask from the specified text.
Definition: tagvalue.cpp:876
TagParser::TagDataType::PositionInSet
TagParser::TagDataType::StandardGenreIndex
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::TagValue::assignText
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:767
TagParser::TagValue::assignInteger
void assignInteger(int value)
Assigns the given integer value.
Definition: tagvalue.cpp:818
TagParser::TagDataType
TagDataType
Specifies the data type.
Definition: tagvalue.h:54
TagParser::FlacMetaDataBlockType::Picture
TagParser::TagValue::compareTo
bool compareTo(const TagValue &other, TagValueComparisionFlags options=TagValueComparisionFlags::None) const
Returns whether both instances are equal.
Definition: tagvalue.cpp:181
TagParser::Id3Genres::indexFromString
static int indexFromString(const std::string &genre)
Returns the numerical denotation of the specified genre or -1 if genre is unknown.
Definition: id3genres.cpp:42
TagParser::TagValue::isEmpty
bool isEmpty() const
Returns whether an empty value is assigned.
Definition: tagvalue.h:449
TagParser::Id3Genres::emptyGenreIndex
static constexpr int emptyGenreIndex()
Returns the preferred genre index to indicate that no genre is set at all.
Definition: id3genres.h:45
TagParser::Id3Genres::isEmptyGenre
static constexpr bool isEmptyGenre(int index)
Returns whether the genre index indicates the genre field is not set at all.
Definition: id3genres.h:53
TagParser::TagTextEncoding::Latin1
TagParser::Tag::proposedTextEncoding
virtual TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
Definition: tag.h:149
TagParser::TagValue::toWString
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:420
id3genres.h
TagParser::TagValue::toDateTime
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
Definition: tagvalue.cpp:470
CppUtilities
Definition: abstractcontainer.h:15
TagParser::Tag::canEncodingBeUsed
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:154
TagParser::TagValue::clearMetadata
void clearMetadata()
Wipes assigned meta data.
Definition: tagvalue.cpp:307
TagParser::TagValue::convertDescriptionEncoding
void convertDescriptionEncoding(TagTextEncoding encoding)
Converts the assigned description to use the specified encoding.
Definition: tagvalue.cpp:553
TagParser::TagValue::toTimeSpan
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition: tagvalue.cpp:442
TagParser::TagDataType::Binary
TagParser::Id3Genres::isIndexSupported
static constexpr bool isIndexSupported(int index)
Returns an indication whether the specified numerical denotation is supported by this class.
Definition: id3genres.h:62
TagParser::RawDataType::DateTime
Definition: mp4tagfield.h:36
TagParser::TagValue
The TagValue class wraps values of different types. It is meant to be assigned to a tag field.
Definition: tagvalue.h:75
TagParser::TagTextEncoding::Utf16LittleEndian
TagParser::TagDataType::DateTime
TagParser::encodingParameter
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
TagParser::TagValue::convertDataEncodingForTag
void convertDataEncodingForTag(const Tag *tag)
Ensures the encoding of the currently assigned text value is supported by the specified tag.
Definition: tagvalue.cpp:543
TagParser::TagValueComparisionFlags::CaseInsensitive
TagParser::TagValue::toString
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:407
TagParser::PositionInSet
The PositionInSet class describes the position of an element in a set which consists of a certain num...
Definition: positioninset.h:21
tag.h
TagParser::TagValueComparisionFlags
TagValueComparisionFlags
The TagValueComparisionOption enum specifies options for TagValue::compareTo().
Definition: tagvalue.h:69
TagParser::TagValue::type
TagDataType type() const
Returns the type of the assigned value.
Definition: tagvalue.h:395
TagParser::TagValue::empty
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition: tagvalue.cpp:955
TagParser::TagValue::dataEncoding
TagTextEncoding dataEncoding() const
Returns the data encoding.
Definition: tagvalue.h:603
TagParser::TagValue::assignData
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
TagParser::TagValue::toInteger
std::int32_t toInteger() const
Converts the value of the current TagValue object to its equivalent integer representation.
Definition: tagvalue.cpp:323
TagParser::Id3Genres::stringFromIndex
static const char * stringFromIndex(int index)
Returns the genre name for the specified numerical denotation as C-style string.
Definition: id3genres.h:27
TagParser::CaseInsensitiveCharComparer::toLower
static constexpr unsigned char toLower(const unsigned char c)
Definition: caseinsensitivecomparer.h:16
TagParser::AccountType::Undefined
TagParser::TagDataType::Integer
TagParser::PositionInSet::toString
StringType toString() const
Returns the string representation of the current PositionInSet.
Definition: positioninset.h:111
TagParser::TrackType::Unspecified