diff options
Diffstat (limited to 'Src/replicant/nsapev2/item.cpp')
-rw-r--r-- | Src/replicant/nsapev2/item.cpp | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/Src/replicant/nsapev2/item.cpp b/Src/replicant/nsapev2/item.cpp new file mode 100644 index 00000000..2d5184ea --- /dev/null +++ b/Src/replicant/nsapev2/item.cpp @@ -0,0 +1,235 @@ +#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; +} + |