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

236 lines
4.4 KiB
C++

#include "item.h"
#include "flags.h"
#include "util.h"
#include "nu/ByteWriter.h"
#include "nu/strsafe.h"
#include "nu/ByteReader.h"
#include "nsapev2/nsapev2.h"
#include <stdlib.h>
/*
http://wiki.hydrogenaudio.org/index.php?title=APE_Tag_Item
Item layout:
[0-3] length of value field (little endian)
[4-7] flags (little endian)
[null terminated] key
[length] value
*/
APEv2::Item::Item()
{
len=0;
flags=0;
key=0;
value=0;
}
APEv2::Item::~Item()
{
free(key);
free(value);
}
int APEv2::Item::Read(bytereader_t byte_reader)
{
if (bytereader_size(byte_reader) < 8)
return NErr_NeedMoreData;
/* read fixed-size fields */
len = bytereader_read_u32_le(byte_reader);
flags = bytereader_read_u32_le(byte_reader);
/* find the null terminator */
size_t key_len = bytereader_find_zero(byte_reader);
/* make sure we didn't hit the end of our buffer */
if (key_len == bytereader_size(byte_reader))
return NErr_Insufficient;
/* check for empty key and also check for integer overflow */
if (key_len == 0 || key_len+1 == 0)
return NErr_Error;
key = (char *)malloc(key_len+1);
if (key)
{
bytereader_read_n(byte_reader, key, key_len+1); /* read key and terminator*/
if (bytereader_size(byte_reader) < len) /* make sure we have room for the value! */
{
free(key);
key=0;
return NErr_NeedMoreData;
}
value = (char *)malloc(len);
if (value)
{
bytereader_read_n(byte_reader, value, len); /* read value */
return NErr_Success;
}
else
{
free(key);
key=0;
return NErr_OutOfMemory;
}
}
else
return NErr_OutOfMemory;
}
bool APEv2::Item::IsReadOnly()
{
return flags & FLAG_READONLY;
}
bool APEv2::Item::KeyMatch(const char *key_to_compare, int compare)
{
if (!key || !*key)
return false;
switch (compare)
{
case ITEM_KEY_COMPARE_CASE_INSENSITIVE:
#ifdef _WIN32
return !_stricmp(key_to_compare, key);
#else
return !strcasecmp(key_to_compare, key);
#endif
case ITEM_KEY_COMPARE_CASE_SENSITIVE:
return !strcmp(key_to_compare, key);
default:
return false;
}
}
int APEv2::Item::Get(const void **data, size_t *datalen) const
{
if (!value || !len)
return NErr_Empty;
*data = value;
*datalen = len;
return NErr_Success;
}
int APEv2::Item::Set(nx_string_t string)
{
if (!value)
return NErr_BadParameter;
flags &= ~nsapev2_item_type_mask;
flags |= nsapev2_item_type_utf8;
size_t bytes;
int ret = NXStringGetBytesSize(&bytes, string, nx_charset_utf8, 0);
if (ret != NErr_DirectPointer && ret != NErr_Success)
return ret;
void *new_value = malloc(bytes);
if (!new_value)
return NErr_OutOfMemory;
size_t bytes_copied;
ret = NXStringGetBytes(&bytes_copied, string, new_value, bytes, nx_charset_utf8, 0);
if (ret != NErr_Success)
{
free(new_value);
return ret;
}
free(value);
value=new_value;
len=(uint32_t)bytes_copied;
return NErr_Success;
}
int APEv2::Item::Set(const void *data, size_t datalen, int data_type)
{
if (!data || !datalen)
return NErr_Error;
// set data type for this item
flags &= ~nsapev2_item_type_mask;
flags |= data_type;
void *new_value = realloc(value, datalen);
if (!new_value)
return NErr_OutOfMemory;
value=new_value;
len=(uint32_t)datalen;
memcpy(value, data, len);
return NErr_Success;
}
int APEv2::Item::New(size_t datalen, int data_type, void **bytes)
{
if (!datalen)
return NErr_Error;
// set data type for this item
flags &= ~nsapev2_item_type_mask;
flags |= data_type;
void *new_value = realloc(value, datalen);
if (!new_value)
return NErr_OutOfMemory;
value=new_value;
len=(uint32_t)datalen;
*bytes = value;
return NErr_Success;
}
int APEv2::Item::SetKey(const char *tag)
{
if (!tag || !*tag)
return NErr_Error;
char *new_key = strdup(tag);
if (!new_key)
return NErr_OutOfMemory;
free(key);
key = new_key;
return NErr_Success;
}
int APEv2::Item::GetKey(const char **tag) const
{
if (!key)
return NErr_Error;
*tag = key;
return NErr_Success;
}
size_t APEv2::Item::EncodeSize() const
{
return 4 /* size */ + 4 /* flags */ + strlen(key) + 1 /* NULL separator */ + len;
}
uint32_t APEv2::Item::GetFlags() const
{
return flags;
}
int APEv2::Item::Encode(bytewriter_t byte_writer) const
{
if (!key || !value || !len)
return NErr_Error;
if (bytewriter_size(byte_writer) < EncodeSize())
return NErr_Insufficient;
bytewriter_write_u32_le(byte_writer, len);
bytewriter_write_u32_le(byte_writer, flags);
bytewriter_write_n(byte_writer, key, strlen(key) + 1);
bytewriter_write_n(byte_writer, value, len);
return NErr_Success;
}