221 lines
3.6 KiB
C++
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;
|
||
|
}
|