winamp/Src/apev2/item.cpp
2024-09-24 14:54:57 +02:00

221 lines
3.6 KiB
C++

#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;
}