id3_field_string_unicode.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // The authors have released ID3Lib as Public Domain (PD) and claim no copyright,
  2. // patent or other intellectual property protection in this work. This means that
  3. // it may be modified, redistributed and used in commercial and non-commercial
  4. // software and hardware without restrictions. ID3Lib is distributed on an "AS IS"
  5. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  6. //
  7. // The ID3Lib authors encourage improvements and optimisations to be sent to the
  8. // ID3Lib coordinator, currently Dirk Mahoney ([email protected]). Approved
  9. // submissions may be altered, and will be included and released under these terms.
  10. //
  11. // Mon Nov 23 18:34:01 1998
  12. // improved/optimized/whatever 10/30/00 JF
  13. // improved/optimized/whatEVER jan-08-2006 benski
  14. #include <wchar.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include "id3_field.h"
  18. #include <windows.h>
  19. #include "../Plugins/Input/in_mp3/config.h" // TODO: cut
  20. #include "id3_misc_support.h"
  21. // this function is another way of using Set()
  22. #if 0
  23. ID3_Field &ID3_Field::operator=(wchar_t *string)
  24. {
  25. Set(string);
  26. return *this;
  27. }
  28. #endif
  29. // this is Set()
  30. void ID3_Field::SetUnicode(const wchar_t *string)
  31. {
  32. luint bytesUsed = lstrlenW(string);
  33. // we can simply increment the
  34. // bytesUsed count here because
  35. // we just pilfer the NULL which is
  36. // present in the string which was
  37. // passed to us
  38. if (flags & ID3FF_NULL)
  39. bytesUsed++;
  40. // doubling the bytesUsed because
  41. // Unicode is twice the size of ASCII
  42. bytesUsed *= sizeof (wchar_t);
  43. Set ((uchar *) string, bytesUsed);
  44. type = ID3FTY_UNICODESTRING;
  45. hasChanged = true;
  46. }
  47. void ID3_Field::AddUnicode(const wchar_t *string)
  48. {
  49. if (!data)
  50. SetUnicode(string);
  51. else
  52. {
  53. wchar_t *temp;
  54. luint newLen;
  55. lsint nullOffset = 0;
  56. // if there is a NULL in this string, set this offset
  57. // so that we ignore it in string size calculations
  58. if (flags & ID3FF_NULL)
  59. nullOffset = -1;
  60. // +1 is for the NULL at the end and the
  61. // other +1 is for the list divider
  62. newLen = 1 + (size / sizeof (wchar_t)) + lstrlenW(string) + 1 + nullOffset;
  63. // I use the value 1 as a divider because then I
  64. // can change it to either a '/' or a NULL at render
  65. // time. This allows easy use of these functions
  66. // for text lists or in the IPLS frame
  67. if (temp = (wchar_t*)calloc(newLen, sizeof(wchar_t)))
  68. {
  69. lstrcpyW(temp, (wchar_t *) data);
  70. temp[(size / sizeof (wchar_t)) + nullOffset] = L'\001';
  71. lstrcpyW (&temp[(size / sizeof (wchar_t)) + 1 + nullOffset], string);
  72. SetUnicode(temp);
  73. free(temp);
  74. }
  75. else
  76. ID3_THROW (ID3E_NoMemory);
  77. }
  78. return;
  79. }
  80. // this is Get()
  81. luint ID3_Field::GetUnicode(wchar_t *buffer, luint maxChars, luint itemNum)
  82. {
  83. luint charsUsed = 0;
  84. // check to see if there is a string in the frame
  85. // to copy before we even try
  86. if (data)
  87. {
  88. lsint nullOffset = 0;
  89. if (flags & ID3FF_NULL)
  90. nullOffset = -1;
  91. // first we must find which element
  92. // is being sought to make sure it
  93. // exists before we try to get it
  94. if (itemNum <= GetNumTextItems() && itemNum > 0)
  95. {
  96. wchar_t *source = (wchar_t *) data;
  97. luint posn = 0;
  98. luint sourceLen = 0;
  99. luint curItemNum = 1;
  100. luint mx= (size / sizeof (wchar_t)) + nullOffset;
  101. // now we find that element and set the souvre pointer
  102. while (posn<mx && curItemNum < itemNum)
  103. {
  104. while (posn<mx && *source != L'\001' && *source != L'\0')
  105. {
  106. source++;
  107. posn++;
  108. }
  109. source++;
  110. posn++;
  111. curItemNum++;
  112. }
  113. if(posn>=mx) return 0;
  114. // now that we are positioned at the first character
  115. // of the string we want, find the end of it
  116. while (posn<mx && source[sourceLen] != L'\001' && source[sourceLen] != L'\0')
  117. {
  118. sourceLen++;
  119. posn++;
  120. }
  121. if (maxChars) // JF
  122. {
  123. // we subtract 1 here so we have
  124. // room for the NULL terminator
  125. //maxChars--; // CT
  126. if (buffer)
  127. {
  128. luint actualChars = MIN (maxChars-1, sourceLen);
  129. wcsncpy (buffer, source, actualChars);
  130. buffer[actualChars] = L'\0';
  131. charsUsed = actualChars;
  132. }
  133. else
  134. ID3_THROW (ID3E_NoBuffer);
  135. }
  136. }
  137. }
  138. return charsUsed;
  139. }
  140. luint ID3_Field::GetNumTextItems (void)
  141. {
  142. luint numItems = 0;
  143. if (data)
  144. {
  145. luint posn = 0;
  146. numItems++;
  147. while (posn < size)
  148. if (data[posn++] == L'\001')
  149. numItems++;
  150. }
  151. return numItems;
  152. }
  153. luint ID3_Field::ParseUnicodeString (uchar *buffer, luint posn, luint buffSize)
  154. {
  155. luint bytesUsed = 0;
  156. wchar_t *temp = NULL;
  157. if (fixedLength != -1)
  158. bytesUsed = fixedLength;
  159. else
  160. {
  161. if (flags & ID3FF_NULL)
  162. while ((posn + bytesUsed) < buffSize &&
  163. ! (buffer[posn + bytesUsed] == 0 && buffer[posn + bytesUsed + 1] == 0))
  164. bytesUsed += 2;
  165. else
  166. bytesUsed = buffSize - posn;
  167. }
  168. if (bytesUsed > 0x8ffff)
  169. {
  170. hasChanged = false;
  171. return 0;
  172. }
  173. if (bytesUsed)
  174. {
  175. if (temp = (wchar_t*)calloc(((bytesUsed / sizeof (wchar_t)) + 1), sizeof(wchar_t)))
  176. {
  177. luint loc = 0;
  178. memcpy (temp, &buffer[posn], bytesUsed);
  179. temp[bytesUsed / sizeof (wchar_t)] = 0;
  180. // if there is a BOM, skip past it and check to see if we
  181. // need to swap the byte order around
  182. if (temp[0] == 0xFEFF || temp[0] == 0xFFFE)
  183. {
  184. loc++;
  185. // if we need to swap the byte order
  186. if (temp[0] != 0xFEFF)
  187. {
  188. int mylen=(int) lstrlenW(temp);
  189. for (int i = loc; i < mylen; i++)
  190. temp[i] = ((temp[i] >> 8) & 0xFF) | (((temp[i]) & 0xFF) << 8);
  191. }
  192. }
  193. SetUnicode(&temp[loc]);
  194. free(temp);
  195. }
  196. else
  197. ID3_THROW (ID3E_NoMemory);
  198. }
  199. if (flags & ID3FF_NULL)
  200. bytesUsed += 2;
  201. hasChanged = false;
  202. return bytesUsed;
  203. }
  204. luint ID3_Field::RenderUnicodeString(uchar *buffer)
  205. {
  206. luint bytesUsed = 0;
  207. bytesUsed = BinSize();
  208. if (data && size && bytesUsed >= sizeof (wchar_t))
  209. {
  210. wchar_t *ourString = (wchar_t *) &buffer[sizeof(wchar_t)];
  211. // we render at sizeof (wchar_t) bytes into the buffer
  212. // because we make room for the Unicode BOM
  213. memcpy (&buffer[sizeof (wchar_t)], (uchar *) data, bytesUsed - sizeof (wchar_t));
  214. // now we convert the internal dividers to what they
  215. // are supposed to be
  216. size_t numChars = bytesUsed / sizeof (wchar_t);
  217. for (size_t i = 0; i != numChars-1; i++)
  218. if (ourString[i] == 1)
  219. {
  220. wchar_t sub = L'/';
  221. if (flags & ID3FF_NULLDIVIDE)
  222. sub = L'\0';
  223. ourString[i] = sub;
  224. }
  225. }
  226. if (bytesUsed)
  227. {
  228. // render the BOM
  229. wchar_t *BOM = (wchar_t *) buffer;
  230. BOM[0] = 0xFEFF;
  231. }
  232. if (bytesUsed == 2 && (flags & ID3FF_NULL))
  233. buffer[0] = buffer[1] = 0;
  234. hasChanged = false;
  235. return bytesUsed;
  236. }
  237. luint ID3_Field::RenderUTF8String(uchar *buffer)
  238. {
  239. luint bytesUsed = 0;
  240. buffer[0] = 0;
  241. bytesUsed = BinSize();
  242. if (data && size)
  243. {
  244. luint i;
  245. ID3_UnicodeToUTF8( (char*)buffer, (const wchar_t *) data, bytesUsed, bytesUsed);
  246. for (i = 0;i < bytesUsed; i++)
  247. {
  248. if (buffer[i] == 1)
  249. {
  250. char sub = '/';
  251. if (flags & ID3FF_NULLDIVIDE)
  252. sub = '\0';
  253. buffer[i] = sub;
  254. }
  255. }
  256. }
  257. if (bytesUsed == 1 && flags & ID3FF_NULL)
  258. buffer[0] = 0;
  259. hasChanged = false;
  260. return bytesUsed;
  261. }