1
0

frame_usertext.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "nsid3v2.h"
  2. #include "nsid3v2/header.h"
  3. #include "nsid3v2/tag.h"
  4. #include "nsid3v2/frame_utils.h"
  5. #include "nu/ByteReader.h"
  6. #include "nu/ByteWriter.h"
  7. #include "nx/nxstring.h"
  8. struct ParsedUserText
  9. {
  10. ParsedString description;
  11. ParsedString value;
  12. };
  13. static int ParseUserText(const void *data, size_t data_len, ParsedUserText &parsed)
  14. {
  15. int ret;
  16. if (data_len == 0)
  17. return NErr_Insufficient;
  18. bytereader_value_t byte_reader;
  19. bytereader_init(&byte_reader, data, data_len);
  20. uint8_t encoding = bytereader_read_u8(&byte_reader);
  21. ret = ParseNullTerminatedString(&byte_reader, encoding, parsed.description);
  22. if (ret != NErr_Success)
  23. return ret;
  24. return ParseFrameTerminatedString(&byte_reader, encoding, parsed.value);
  25. }
  26. int NSID3v2_Tag_TXXX_Find(const nsid3v2_tag_t t, const char *description, nsid3v2_frame_t *out_frame, int text_flags)
  27. {
  28. const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
  29. if (!tag)
  30. return NErr_Empty;
  31. const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_USER_TEXT);
  32. while (frame)
  33. {
  34. const void *data;
  35. size_t data_len;
  36. ParsedUserText parsed;
  37. if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParseUserText(data, data_len, parsed) == NErr_Success && DescriptionMatches(parsed.description, description, text_flags))
  38. {
  39. *out_frame = (nsid3v2_frame_t)frame;
  40. return NErr_Success;
  41. }
  42. frame = tag->FindNextFrame(frame);
  43. }
  44. return NErr_Empty;
  45. }
  46. int NSID3v2_Tag_TXXX_Get(const nsid3v2_tag_t t, const char *description, nx_string_t *value, int text_flags)
  47. {
  48. const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
  49. if (!tag)
  50. return NErr_Empty;
  51. const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_USER_TEXT);
  52. while (frame)
  53. {
  54. const void *data;
  55. size_t data_len;
  56. ParsedUserText parsed;
  57. if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParseUserText(data, data_len, parsed) == NErr_Success && DescriptionMatches(parsed.description, description, text_flags))
  58. {
  59. return NXStringCreateFromParsedString(value, parsed.value, text_flags);
  60. }
  61. frame = tag->FindNextFrame(frame);
  62. }
  63. return NErr_Empty;
  64. }
  65. int NSID3v2_Frame_UserText_Get(const nsid3v2_frame_t f, nx_string_t *description, nx_string_t *value, int text_flags)
  66. {
  67. const ID3v2::Frame *frame = (const ID3v2::Frame *)f;
  68. if (frame)
  69. {
  70. const void *data;
  71. size_t data_len;
  72. ParsedUserText parsed;
  73. if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParseUserText(data, data_len, parsed) == NErr_Success)
  74. {
  75. int ret = NXStringCreateFromParsedString(value, parsed.value, text_flags);
  76. if (ret != NErr_Success)
  77. return ret;
  78. if (description)
  79. return NXStringCreateFromParsedString(description, parsed.description, text_flags);
  80. else
  81. return NErr_Success;
  82. }
  83. }
  84. return NErr_Error;
  85. }
  86. /* ---------------- Setters ---------------- */
  87. int NSID3v2_Frame_UserText_Set(nsid3v2_frame_t f, const char *description, nx_string_t value, int text_flags)
  88. {
  89. ID3v2::Frame *frame = (ID3v2::Frame *)f;
  90. if (frame)
  91. {
  92. /* benski> for now, we're going to store UTF-16LE always. in the future, we'll add functions to NXString to determine a 'best' encoding */
  93. size_t description_length=strlen(description);
  94. size_t byte_count_value=0;
  95. int ret = NXStringGetBytesSize(&byte_count_value, value, nx_charset_utf16le, 0);
  96. if (ret != NErr_DirectPointer && ret != NErr_Success)
  97. return ret;
  98. /* TODO: overflow check */
  99. size_t total_size = 1 /* encoding */ + 2 /* BOM for description */ + description_length*2 + 2 /* null separator */ + 2 /* BOM for value */ + byte_count_value;
  100. void *data;
  101. size_t data_len;
  102. ret = frame->NewData(total_size, &data, &data_len);
  103. if (ret != NErr_Success)
  104. return ret;
  105. size_t bytes_copied;
  106. bytewriter_s byte_writer;
  107. bytewriter_init(&byte_writer, data, data_len);
  108. bytewriter_write_u8(&byte_writer, 1); /* mark as UTF-16LE */
  109. bytewriter_write_u16_le(&byte_writer, 0xFEFF); /* BOM for description */
  110. for (size_t i=0;i<description_length;i++)
  111. bytewriter_write_u16_le(&byte_writer, description[i]);
  112. bytewriter_write_u16_le(&byte_writer, 0); /* NULL separator*/
  113. bytewriter_write_u16_le(&byte_writer, 0xFEFF); /* BOM for value */
  114. NXStringGetBytes(&bytes_copied, value, bytewriter_pointer(&byte_writer), bytewriter_size(&byte_writer), nx_charset_utf16le, 0);
  115. return NErr_Success;
  116. }
  117. return NErr_Error;
  118. }
  119. int NSID3v2_Tag_TXXX_Set(nsid3v2_tag_t t, const char *description, nx_string_t value, int text_flags)
  120. {
  121. ID3v2::Tag *tag = (ID3v2::Tag *)t;
  122. if (!tag)
  123. return NErr_Empty;
  124. ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_USER_TEXT);
  125. while (frame)
  126. {
  127. const void *data;
  128. size_t data_len;
  129. ParsedUserText parsed;
  130. if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParseUserText(data, data_len, parsed) == NErr_Success && DescriptionMatches(parsed.description, description, text_flags))
  131. {
  132. break;
  133. }
  134. frame = tag->FindNextFrame(frame);
  135. }
  136. if (!frame)
  137. {
  138. frame = tag->NewFrame(NSID3V2_FRAME_USER_TEXT, 0);
  139. if (!frame)
  140. return NErr_OutOfMemory;
  141. tag->AddFrame(frame);
  142. }
  143. return NSID3v2_Frame_UserText_Set((nsid3v2_frame_t)frame, description, value, text_flags);
  144. }