aboutsummaryrefslogtreecommitdiff
path: root/Src/apev2/item.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/apev2/item.cpp')
-rw-r--r--Src/apev2/item.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/Src/apev2/item.cpp b/Src/apev2/item.cpp
new file mode 100644
index 00000000..c757620f
--- /dev/null
+++ b/Src/apev2/item.cpp
@@ -0,0 +1,221 @@
+#include "item.h"
+#include "flags.h"
+#include "util.h"
+#include <strsafe.h>
+#include <stdint.h>
+
+/*
+http://wiki.hydrogenaudio.org/index.php?title=APE_Tag_Item
+*/
+
+APEv2::Item::Item()
+{
+ refCount=1;
+ len=0;
+ flags=0;
+ key=0;
+ value=0;
+}
+
+APEv2::Item::~Item()
+{
+ free(key);
+ free(value);
+}
+
+void APEv2::Item::Retain()
+{
+ refCount++;
+}
+
+void APEv2::Item::Release()
+{
+ if (--refCount == 0)
+ delete this;
+}
+
+int APEv2::Item::Read(void *_data, size_t datalen, void **new_data, size_t *new_len)
+{
+ char *data = (char *)_data;
+
+ if (datalen < 4)
+ return APEV2_TOO_SMALL;
+ memcpy(&len, data, 4);
+ len = ATON32(len);
+ data+=4;
+ datalen-=4;
+
+ if (datalen < 4)
+ return APEV2_TOO_SMALL;
+ memcpy(&flags, data, 4);
+ flags = ATON32(flags);
+ data+=4;
+ datalen-=4;
+
+ uint32_t key_len=0;
+ for (uint32_t i=0;i<datalen;i++)
+ {
+ if (data[i] == 0)
+ {
+ key_len=i;
+ break;
+ }
+ }
+
+ if (key_len == datalen)
+ return APEV2_TOO_SMALL;
+
+ if (key_len == 0)
+ return APEV2_FAILURE;
+
+ if (key)
+ {
+ free(key);
+ key = 0;
+ }
+ key = (char *)calloc(key_len+1, sizeof(char));
+ if (key)
+ {
+ StringCchCopyA(key, key_len+1, data);
+ datalen-=(key_len+1);
+ data+=(key_len+1);
+
+ if (datalen < len)
+ {
+ free(key);
+ key = 0;
+ return APEV2_TOO_SMALL;
+ }
+
+ if (value)
+ {
+ free(value);
+ value = 0;
+ }
+ value = (char *)calloc(len, sizeof(char));
+ if (value)
+ {
+ memcpy(value, data, len);
+ datalen-=len;
+ data+=len;
+ *new_len = datalen;
+ *new_data=data;
+ return APEV2_SUCCESS;
+ }
+ else
+ {
+ free(key);
+ return APEV2_FAILURE;
+ }
+ }
+ else
+ return APEV2_FAILURE;
+}
+
+bool APEv2::Item::IsReadOnly()
+{
+ return flags & FLAG_READONLY;
+}
+
+bool APEv2::Item::IsString()
+{
+ return (flags & MASK_ITEM_TYPE) == FLAG_ITEM_TEXT;
+}
+
+bool APEv2::Item::KeyMatch(const char *key_to_compare, int compare)
+{
+ if (!key || !*key)
+ return false;
+
+ switch (compare)
+ {
+ case ITEM_KEY_COMPARE_CASE_INSENSITIVE:
+ return !_stricmp(key_to_compare, key);
+ case ITEM_KEY_COMPARE_CASE_SENSITIVE:
+ return !strcmp(key_to_compare, key);
+ default:
+ return false;
+ }
+}
+
+int APEv2::Item::Get(void **data, size_t *datalen)
+{
+ if (!value || !len)
+ return APEV2_FAILURE;
+ *data = value;
+ *datalen = len;
+ return APEV2_SUCCESS;
+}
+
+int APEv2::Item::Set(const void *data, size_t datalen, int dataType)
+{
+ if (!data || !datalen)
+ return APEV2_FAILURE;
+
+ // set data type for this item
+ flags &= ~MASK_ITEM_TYPE;
+ flags |= dataType;
+
+ free(value);
+ value = malloc(datalen);
+ len=(uint32_t)datalen;
+ memcpy(value, data, len);
+ return APEV2_SUCCESS;
+}
+
+int APEv2::Item::SetKey(const char *tag)
+{
+ if (!tag || !*tag)
+ return APEV2_FAILURE;
+
+ free(key);
+ key = _strdup(tag);
+ return APEV2_SUCCESS;
+}
+
+int APEv2::Item::GetKey(const char **tag)
+{
+ if (!key)
+ return APEV2_FAILURE;
+ *tag = key;
+ return APEV2_SUCCESS;
+}
+
+size_t APEv2::Item::EncodeSize()
+{
+ return 4 /* size */ + 4 /* flags */ + (key && *key ? strlen(key) : 0) + 1 /* NULL separator */ + len;
+}
+
+int APEv2::Item::Encode(void *data, size_t datalen)
+{
+ if (!key || !value || !len)
+ return APEV2_FAILURE;
+
+ if (datalen < EncodeSize())
+ return APEV2_TOO_SMALL;
+
+ int8_t *ptr = (int8_t *)data;
+
+ // write data length
+ int32_t _len = NTOA32(len);
+ memcpy(ptr, &_len, sizeof(_len));
+ ptr+=sizeof(_len);
+ datalen-=sizeof(_len);
+
+ // write flags
+ int32_t _flags = NTOA32(flags);
+ memcpy(ptr, &_flags, sizeof(_flags));
+ ptr+=sizeof(_flags);
+ datalen-=sizeof(_flags);
+
+ // write key and null terminator
+ if (StringCchCopyExA((char *)ptr, datalen, key, (char **) &ptr, &datalen, 0) != S_OK)
+ return APEV2_FAILURE;
+ // account for null separator
+ ptr++;
+ datalen--;
+
+ // write data
+ memcpy(ptr, value, len);
+ return APEV2_SUCCESS;
+} \ No newline at end of file