item.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #include "item.h"
  2. #include "flags.h"
  3. #include "util.h"
  4. #include <strsafe.h>
  5. #include <stdint.h>
  6. /*
  7. http://wiki.hydrogenaudio.org/index.php?title=APE_Tag_Item
  8. */
  9. APEv2::Item::Item()
  10. {
  11. refCount=1;
  12. len=0;
  13. flags=0;
  14. key=0;
  15. value=0;
  16. }
  17. APEv2::Item::~Item()
  18. {
  19. free(key);
  20. free(value);
  21. }
  22. void APEv2::Item::Retain()
  23. {
  24. refCount++;
  25. }
  26. void APEv2::Item::Release()
  27. {
  28. if (--refCount == 0)
  29. delete this;
  30. }
  31. int APEv2::Item::Read(void *_data, size_t datalen, void **new_data, size_t *new_len)
  32. {
  33. char *data = (char *)_data;
  34. if (datalen < 4)
  35. return APEV2_TOO_SMALL;
  36. memcpy(&len, data, 4);
  37. len = ATON32(len);
  38. data+=4;
  39. datalen-=4;
  40. if (datalen < 4)
  41. return APEV2_TOO_SMALL;
  42. memcpy(&flags, data, 4);
  43. flags = ATON32(flags);
  44. data+=4;
  45. datalen-=4;
  46. uint32_t key_len=0;
  47. for (uint32_t i=0;i<datalen;i++)
  48. {
  49. if (data[i] == 0)
  50. {
  51. key_len=i;
  52. break;
  53. }
  54. }
  55. if (key_len == datalen)
  56. return APEV2_TOO_SMALL;
  57. if (key_len == 0)
  58. return APEV2_FAILURE;
  59. if (key)
  60. {
  61. free(key);
  62. key = 0;
  63. }
  64. key = (char *)calloc(key_len+1, sizeof(char));
  65. if (key)
  66. {
  67. StringCchCopyA(key, key_len+1, data);
  68. datalen-=(key_len+1);
  69. data+=(key_len+1);
  70. if (datalen < len)
  71. {
  72. free(key);
  73. key = 0;
  74. return APEV2_TOO_SMALL;
  75. }
  76. if (value)
  77. {
  78. free(value);
  79. value = 0;
  80. }
  81. value = (char *)calloc(len, sizeof(char));
  82. if (value)
  83. {
  84. memcpy(value, data, len);
  85. datalen-=len;
  86. data+=len;
  87. *new_len = datalen;
  88. *new_data=data;
  89. return APEV2_SUCCESS;
  90. }
  91. else
  92. {
  93. free(key);
  94. return APEV2_FAILURE;
  95. }
  96. }
  97. else
  98. return APEV2_FAILURE;
  99. }
  100. bool APEv2::Item::IsReadOnly()
  101. {
  102. return flags & FLAG_READONLY;
  103. }
  104. bool APEv2::Item::IsString()
  105. {
  106. return (flags & MASK_ITEM_TYPE) == FLAG_ITEM_TEXT;
  107. }
  108. bool APEv2::Item::KeyMatch(const char *key_to_compare, int compare)
  109. {
  110. if (!key || !*key)
  111. return false;
  112. switch (compare)
  113. {
  114. case ITEM_KEY_COMPARE_CASE_INSENSITIVE:
  115. return !_stricmp(key_to_compare, key);
  116. case ITEM_KEY_COMPARE_CASE_SENSITIVE:
  117. return !strcmp(key_to_compare, key);
  118. default:
  119. return false;
  120. }
  121. }
  122. int APEv2::Item::Get(void **data, size_t *datalen)
  123. {
  124. if (!value || !len)
  125. return APEV2_FAILURE;
  126. *data = value;
  127. *datalen = len;
  128. return APEV2_SUCCESS;
  129. }
  130. int APEv2::Item::Set(const void *data, size_t datalen, int dataType)
  131. {
  132. if (!data || !datalen)
  133. return APEV2_FAILURE;
  134. // set data type for this item
  135. flags &= ~MASK_ITEM_TYPE;
  136. flags |= dataType;
  137. free(value);
  138. value = malloc(datalen);
  139. len=(uint32_t)datalen;
  140. memcpy(value, data, len);
  141. return APEV2_SUCCESS;
  142. }
  143. int APEv2::Item::SetKey(const char *tag)
  144. {
  145. if (!tag || !*tag)
  146. return APEV2_FAILURE;
  147. free(key);
  148. key = _strdup(tag);
  149. return APEV2_SUCCESS;
  150. }
  151. int APEv2::Item::GetKey(const char **tag)
  152. {
  153. if (!key)
  154. return APEV2_FAILURE;
  155. *tag = key;
  156. return APEV2_SUCCESS;
  157. }
  158. size_t APEv2::Item::EncodeSize()
  159. {
  160. return 4 /* size */ + 4 /* flags */ + (key && *key ? strlen(key) : 0) + 1 /* NULL separator */ + len;
  161. }
  162. int APEv2::Item::Encode(void *data, size_t datalen)
  163. {
  164. if (!key || !value || !len)
  165. return APEV2_FAILURE;
  166. if (datalen < EncodeSize())
  167. return APEV2_TOO_SMALL;
  168. int8_t *ptr = (int8_t *)data;
  169. // write data length
  170. int32_t _len = NTOA32(len);
  171. memcpy(ptr, &_len, sizeof(_len));
  172. ptr+=sizeof(_len);
  173. datalen-=sizeof(_len);
  174. // write flags
  175. int32_t _flags = NTOA32(flags);
  176. memcpy(ptr, &_flags, sizeof(_flags));
  177. ptr+=sizeof(_flags);
  178. datalen-=sizeof(_flags);
  179. // write key and null terminator
  180. if (StringCchCopyExA((char *)ptr, datalen, key, (char **) &ptr, &datalen, 0) != S_OK)
  181. return APEV2_FAILURE;
  182. // account for null separator
  183. ptr++;
  184. datalen--;
  185. // write data
  186. memcpy(ptr, value, len);
  187. return APEV2_SUCCESS;
  188. }