Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions

View File

@ -0,0 +1 @@
1.2

View File

@ -0,0 +1,20 @@
#pragma once
#include "foundation/error.h"
namespace APEv2
{
/*
http://wiki.hydrogenaudio.org/index.php?title=Ape_Tags_Flags
*/
enum
{
/* flags for header or item */
FLAG_READONLY = 1,
/* header/footer specific flags */
FLAG_HEADER_HAS_HEADER = (1 << 31),
FLAG_HEADER_NO_FOOTER = (1 << 30),
FLAG_HEADER_IS_HEADER = (1 << 29),
FLAG_HEADER_ENCODE_MASK = FLAG_READONLY|FLAG_HEADER_HAS_HEADER|FLAG_HEADER_NO_FOOTER,
};
}

View File

@ -0,0 +1,91 @@
#include "header.h"
#include "flags.h"
#include "util.h"
#include "nu/ByteReader.h"
#include "nu/ByteWriter.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
static char apev2_preamble[] = { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' };
APEv2::Header::Header()
{
memcpy(preamble, apev2_preamble, 8);
version=2000;
size=0;
items=0;
flags=0;
reserved=0;
}
APEv2::Header::Header(const void *data)
{
bytereader_value_t byte_reader;
bytereader_init(&byte_reader, data, Header::SIZE);
bytereader_read_n(&byte_reader, preamble, 8);
version=bytereader_read_u32_le(&byte_reader);
size=bytereader_read_u32_le(&byte_reader);
items=bytereader_read_u32_le(&byte_reader);
flags=bytereader_read_u32_le(&byte_reader);
bytereader_read_n(&byte_reader, &reserved, 8);
}
uint32_t APEv2::Header::GetFlags() const
{
return flags;
}
bool APEv2::Header::Valid() const
{
return !memcmp(preamble, apev2_preamble, 8) && reserved == 0;
}
uint32_t APEv2::Header::TagSize() const
{
size_t size = this->size;
if (IsHeader() && HasFooter())
size+=SIZE;
if (IsFooter() && HasHeader())
size+=SIZE;
if (size > ULONG_MAX)
return 0;
return (uint32_t)size;
}
bool APEv2::Header::HasHeader() const
{
return !!(flags & FLAG_HEADER_HAS_HEADER);
}
bool APEv2::Header::HasFooter() const
{
return !(flags & FLAG_HEADER_NO_FOOTER);
}
bool APEv2::Header::IsFooter() const
{
return !(flags & FLAG_HEADER_IS_HEADER);
}
bool APEv2::Header::IsHeader() const
{
return !!(flags & FLAG_HEADER_IS_HEADER);
}
int APEv2::Header::Encode(bytewriter_t byte_writer) const
{
if (bytewriter_size(byte_writer) < 32)
return NErr_Insufficient;
bytewriter_write_n(byte_writer, apev2_preamble, 8);
bytewriter_write_u32_le(byte_writer, version);
bytewriter_write_u32_le(byte_writer, size);
bytewriter_write_u32_le(byte_writer, items);
bytewriter_write_u32_le(byte_writer, flags);
bytewriter_write_zero_n(byte_writer, 8);
return NErr_Success;
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "foundation/types.h"
#include "nu/ByteWriter.h"
class nstest;
namespace APEv2
{
class Header
{
friend class ::nstest;
public:
Header();
Header(const void *data);
void SetSize(uint32_t size) { this->size = size; }
void SetFlags(uint32_t flags) { this->flags = flags; }
void SetItems(uint32_t items) { this->items = items; }
bool Valid() const;
uint32_t TagSize() const;
bool HasHeader() const;
bool HasFooter() const;
bool IsFooter() const;
bool IsHeader() const;
int Encode(bytewriter_t byte_writer) const;
uint32_t GetFlags() const;
enum
{
SIZE=32,
};
private:
uint8_t preamble[8];
uint32_t version;
uint32_t size;
uint32_t items;
uint32_t flags;
uint64_t reserved;
};
}

View File

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

View File

@ -0,0 +1,43 @@
#pragma once
#include "foundation/types.h"
#include "nx/nxstring.h"
#include "nu/PtrDeque.h"
#include "nu/ByteWriter.h"
#include "nu/ByteReader.h"
namespace APEv2
{
enum
{
ITEM_KEY_COMPARE_CASE_INSENSITIVE = 0,
ITEM_KEY_COMPARE_CASE_SENSITIVE = 1,
};
class Item : public nu::PtrDequeNode
{
public:
Item();
~Item();
/* If successful, puts incremented data pointer in new_data, and new data size remaining in new_len */
int Read(bytereader_t byte_reader);
int Encode(bytewriter_t byte_writer) const;
size_t EncodeSize() const;
bool IsReadOnly();
bool KeyMatch(const char *key, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE);
int Get(const void **data, size_t *len) const;
int GetKey(const char **tag) const;
int Set(nx_string_t value);
int Set(const void *data, size_t len, int dataType);
int SetKey(const char *tag);
int New(size_t datalen, int data_type, void **bytes);
uint32_t GetFlags() const;
private:
uint32_t flags;
char *key;
void *value;
uint32_t len;
};
}

View File

@ -0,0 +1,75 @@
#pragma once
#include "foundation/types.h"
#include "nx/nxstring.h"
#ifdef __ANDROID__
#include "android/nsapev2.h"
#elif defined(_WIN32)
#include "windows/nsapev2.h"
#elif defined(__linux__)
#include "linux/nsapev2.h"
#elif defined (__APPLE__)
#include "osx/nsapev2.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct nsapev2_header_struct_t { } *nsapev2_header_t;
typedef struct nsapev2_tag_struct_t { } *nsapev2_tag_t;
typedef struct nsapev2_item_struct_t { } *nsapev2_item_t;
// must be exactly 32 bytes
NSAPEV2_EXPORT int NSAPEv2_Header_Valid(const void *header_data);
NSAPEV2_EXPORT int NSAPEv2_Header_Create(nsapev2_header_t *header, const void *header_data, size_t header_len);
NSAPEV2_EXPORT int NSAPEv2_Header_TagSize(const nsapev2_header_t header, uint32_t *tag_size);
NSAPEV2_EXPORT int NSAPEv2_Header_HasHeader(nsapev2_header_t header);
NSAPEV2_EXPORT int NSAPEv2_Header_Destroy(nsapev2_header_t header);
// currently, this function makes a copy of any necessary data. in the future, it would be better
// to make another version of this function that "borrows" your data
// if you can guarantee that the memory will outlive the nsapev2_tag_t object
NSAPEV2_EXPORT int NSAPEv2_Tag_Create(nsapev2_tag_t *tag, const nsapev2_header_t header, const void *bytes, size_t bytes_len);
NSAPEV2_EXPORT int NSAPEv2_Tag_New(nsapev2_tag_t *tag);
NSAPEV2_EXPORT int NSAPEv2_Tag_SerializedSize(const nsapev2_tag_t tag, size_t *bytes);
NSAPEV2_EXPORT int NSAPEv2_Tag_Serialize(const nsapev2_tag_t t, void *data, size_t bytes);
NSAPEV2_EXPORT int NSAPEv2_Tag_Destroy(nsapev2_tag_t tag);
NSAPEV2_EXPORT int NSAPEv2_Tag_GetFlags(nsapev2_tag_t tag, uint32_t *flags);
NSAPEV2_EXPORT int NSAPEv2_Tag_SetFlags(nsapev2_tag_t tag, uint32_t flags, uint32_t mask);
NSAPEV2_EXPORT int NSAPEv2_Tag_GetString(const nsapev2_tag_t tag, const char *key, unsigned int index, nx_string_t *value);
NSAPEV2_EXPORT int NSAPEv2_Tag_SetString(nsapev2_tag_t tag, const char *key, unsigned int index, nx_string_t value);
NSAPEV2_EXPORT int NSAPEv2_Tag_GetBinary(const nsapev2_tag_t tag, const char *key, unsigned int index, const void **bytes, size_t *length);
NSAPEV2_EXPORT int NSAPEv2_Tag_SetBinary(nsapev2_tag_t tag, const char *key, unsigned int index, const void *bytes, size_t length);
NSAPEV2_EXPORT int NSAPEv2_Tag_SetArtwork(nsapev2_tag_t t, const char *key, unsigned int index, const char *filename, const void *bytes, size_t length);
/* Items */
// flags
static const uint32_t nsapev2_item_read_write = 0;
static const uint32_t nsapev2_item_read_only = 1;
static const uint32_t nsapev2_item_type_utf8 = 0;
static const uint32_t nsapev2_item_type_binary = 1 << 1;
static const uint32_t nsapev2_item_type_locator = 2 << 1;
// mask flags with these to check the different fields
static const uint32_t nsapev2_item_type_mask = (1 << 2) | (1 << 1);
static const uint32_t nsapev2_item_read_mask = 1 << 0;
NSAPEV2_EXPORT int NSAPEv2_Tag_EnumerateItems(const nsapev2_tag_t tag, const nsapev2_item_t start, nsapev2_item_t *next);
NSAPEV2_EXPORT int NSAPEv2_Tag_GetItemCount(const nsapev2_tag_t t, size_t *count);
NSAPEV2_EXPORT int NSAPEv2_Tag_GetItemAtIndex(const nsapev2_tag_t t, unsigned int index, nsapev2_item_t *item);
NSAPEV2_EXPORT int NSAPEv2_Item_GetInformation(const nsapev2_item_t item, const char **key, uint32_t *flags);
NSAPEV2_EXPORT int NSAPEv2_Item_GetString(const nsapev2_item_t item, nx_string_t *value);
NSAPEV2_EXPORT int NSAPEv2_Item_GetBinary(const nsapev2_item_t item, const void **bytes, size_t *length);
NSAPEV2_EXPORT int NSAPEv2_Item_SetKey(nsapev2_item_t item, const char *key);
NSAPEV2_EXPORT int NSAPEv2_Item_SetString(nsapev2_item_t item, nx_string_t value);
NSAPEV2_EXPORT int NSAPEv2_Tag_RemoveItem(nsapev2_tag_t tag, nsapev2_item_t item);
NSAPEV2_EXPORT int NSAPEv2_Tag_AddItem(nsapev2_tag_t tag, nsapev2_item_t *item);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,81 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29509.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsapev2", "nsapev2.vcxproj", "{BF92BB16-012A-43F4-BC67-30D6D5187598}"
ProjectSection(ProjectDependencies) = postProject
{57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27}
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
{E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
ProjectSection(ProjectDependencies) = postProject
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
ProjectSection(ProjectDependencies) = postProject
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Debug|Win32.ActiveCfg = Debug|Win32
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Debug|Win32.Build.0 = Debug|Win32
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Debug|x64.ActiveCfg = Debug|x64
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Debug|x64.Build.0 = Debug|x64
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Release|Win32.ActiveCfg = Release|Win32
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Release|Win32.Build.0 = Release|Win32
{BF92BB16-012A-43F4-BC67-30D6D5187598}.Release|x64.ActiveCfg = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BF92BB16-012A-43F4-BC67-30D6D5187598}</ProjectGuid>
<RootNamespace>nsapev2</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>x86_Debug\</OutDir>
<IntDir>x86_Debug\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>x64_Debug\</OutDir>
<IntDir>x64_Debug\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>x86_Release\</OutDir>
<IntDir>x86_Release\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>x64_Release\</OutDir>
<IntDir>x64_Release\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Lib>
<OutputFile>$(ProjectDir)x86_Debug\$(ProjectName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Lib>
<OutputFile>$(ProjectDir)x64_Debug\$(ProjectName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Lib>
<OutputFile>$(ProjectDir)x86_Release\$(ProjectName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Lib>
<OutputFile>$(ProjectDir)x64_Release\$(ProjectName).lib</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="header.cpp" />
<ClCompile Include="item.cpp" />
<ClCompile Include="nsapev2_common.cpp" />
<ClCompile Include="tag.cpp" />
<ClCompile Include="windows\nsapev2.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="flags.h" />
<ClInclude Include="header.h" />
<ClInclude Include="item.h" />
<ClInclude Include="nsapev2.h" />
<ClInclude Include="precomp.h" />
<ClInclude Include="tag.h" />
<ClInclude Include="util.h" />
<ClInclude Include="windows\nsapev2.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,465 @@
#include "nsapev2.h"
#include "nsapev2/header.h"
#include "nsapev2/tag.h"
#include <new>
int NSAPEv2_Header_Valid(const void *header_data)
{
if (APEv2::Header(header_data).Valid())
return NErr_Success;
else
return NErr_False;
}
int NSAPEv2_Header_Create(nsapev2_header_t *header, const void *header_data, size_t header_len)
{
if (header_len < 10 || NSAPEv2_Header_Valid(header_data) != NErr_Success)
return NErr_Error;
nsapev2_header_t new_header = (nsapev2_header_t)new (std::nothrow) APEv2::Header(header_data);
if (!new_header)
return NErr_OutOfMemory;
*header = new_header;
return NErr_Success;
}
int NSAPEv2_Header_TagSize(const nsapev2_header_t h, uint32_t *tag_size)
{
const APEv2::Header *header = (const APEv2::Header *)h;
if (!header)
return NErr_NullPointer;
*tag_size = header->TagSize();
return NErr_Success;
}
int NSAPEv2_Header_HasHeader(nsapev2_header_t h)
{
const APEv2::Header *header = (const APEv2::Header *)h;
if (!header)
return NErr_NullPointer;
if (header->HasHeader())
return NErr_Success;
else
return NErr_False;
}
int NSAPEv2_Header_Destroy(nsapev2_header_t h)
{
const APEv2::Header *header = (const APEv2::Header *)h;
if (!header)
return NErr_NullPointer;
delete header;
return NErr_Success;
}
int NSAPEv2_Tag_Create(nsapev2_tag_t *t, const nsapev2_header_t h, const void *bytes, size_t bytes_len)
{
const APEv2::Header *header = (const APEv2::Header *)h;
if (!header)
return NErr_NullPointer;
APEv2::Tag *tag = new (std::nothrow) APEv2::Tag;
if (!tag)
return NErr_OutOfMemory;
int ret = tag->Parse(header, bytes, bytes_len);
if (ret != NErr_Success)
{
delete tag;
return ret;
}
*t = (nsapev2_tag_t)tag;
return ret;
}
int NSAPEv2_Tag_New(nsapev2_tag_t *t)
{
APEv2::Header *new_header = new (std::nothrow) APEv2::Header();
if (!new_header)
return NErr_OutOfMemory;
APEv2::Tag *tag = new (std::nothrow) APEv2::Tag;
if (!tag)
{
delete new_header;
return NErr_OutOfMemory;
}
*t = (nsapev2_tag_t)tag;
return NErr_Success;
}
int NSAPEv2_Tag_SerializedSize(const nsapev2_tag_t t, size_t *bytes)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
*bytes = tag->EncodeSize();
return NErr_Success;
}
int NSAPEv2_Tag_Serialize(const nsapev2_tag_t t, void *data, size_t bytes)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
return tag->Encode(data, bytes);
}
int NSAPEv2_Tag_Destroy(nsapev2_tag_t t)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_NullPointer;
delete tag;
return NErr_Success;
}
int NSAPEv2_Tag_GetFlags(nsapev2_tag_t t, uint32_t *flags)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
return tag->GetFlags(flags);
}
int NSAPEv2_Tag_SetFlags(nsapev2_tag_t t, uint32_t flags, uint32_t mask)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
return tag->SetFlags(flags, mask);
}
int NSAPEv2_Tag_GetString(const nsapev2_tag_t t, const char *key, unsigned int index, nx_string_t *value)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_Empty;
const void *data;
size_t data_len;
int ret = tag->GetData(key, index, &data, &data_len);
if (ret != NErr_Success)
return ret;
return NXStringCreateWithBytes(value, data, data_len, nx_charset_utf8);
}
int NSAPEv2_Tag_SetString(nsapev2_tag_t t, const char *key, unsigned int index, nx_string_t value)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
if (value)
{
APEv2::Item *item;
int ret = tag->GetItem(key, index, &item);
if (ret == NErr_Success)
{
return item->Set(value);
}
else
{
/* no such item, need to make a new one */
item = new (std::nothrow) APEv2::Item;
if (!item)
return NErr_OutOfMemory;
ret = item->SetKey(key);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = item->Set(value);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = tag->AddItem(item);
if (ret != NErr_Success)
{
delete item;
return ret;
}
return NErr_Success;
}
}
else
{
tag->Remove(key, index);
return NErr_Success;
}
}
int NSAPEv2_Tag_GetBinary(const nsapev2_tag_t t, const char *key, unsigned int index, const void **bytes, size_t *length)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_Empty;
return tag->GetData(key, index, bytes, length);
}
int NSAPEv2_Tag_SetBinary(nsapev2_tag_t t, const char *key, unsigned int index, const void *bytes, size_t length)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
if (bytes)
{
APEv2::Item *item;
int ret = tag->GetItem(key, index, &item);
if (ret == NErr_Success)
{
return item->Set(bytes, length, nsapev2_item_type_binary);
}
else
{
/* no such item, need to make a new one */
item = new (std::nothrow) APEv2::Item;
if (!item)
return NErr_OutOfMemory;
ret = item->SetKey(key);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = item->Set(bytes, length, nsapev2_item_type_binary);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = tag->AddItem(item);
if (ret != NErr_Success)
{
delete item;
return ret;
}
return NErr_Success;
}
}
else
{
tag->Remove(key, index);
return NErr_Success;
}
}
static int SetArtwork(APEv2::Item *item, const char *filename, const void *bytes, size_t length)
{
size_t filename_length = filename?strlen(filename):0;
size_t total_length = filename_length
+ 1 /* null separator */
+ length;
void *item_data;
int ret = item->New(total_length, nsapev2_item_type_binary, &item_data);
if (ret != NErr_Success)
return ret;
bytewriter_s byte_writer;
bytewriter_init(&byte_writer, item_data, total_length);
bytewriter_write_n(&byte_writer, filename, filename_length);
bytewriter_write_u8(&byte_writer, 0);
bytewriter_write_n(&byte_writer, bytes, length);
return NErr_Success;
}
int NSAPEv2_Tag_SetArtwork(nsapev2_tag_t t, const char *key, unsigned int index, const char *filename, const void *bytes, size_t length)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
if (bytes)
{
APEv2::Item *item;
int ret = tag->GetItem(key, index, &item);
if (ret == NErr_Success)
{
return SetArtwork(item, filename, bytes, length);
}
else
{
/* no such item, need to make a new one */
item = new (std::nothrow) APEv2::Item;
if (!item)
return NErr_OutOfMemory;
ret = item->SetKey(key);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = SetArtwork(item, filename, bytes, length);
if (ret != NErr_Success)
{
delete item;
return ret;
}
ret = tag->AddItem(item);
if (ret != NErr_Success)
{
delete item;
return ret;
}
return NErr_Success;
}
}
else
{
tag->Remove(key, index);
return NErr_Success;
}
}
int NSAPEv2_Tag_EnumerateItems(const nsapev2_tag_t t, const nsapev2_item_t s, nsapev2_item_t *next)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_NullPointer;
const APEv2::Item *start = (const APEv2::Item *)s;
return tag->EnumerateItems(start, (APEv2::Item **)next);
}
int NSAPEv2_Tag_GetItemCount(const nsapev2_tag_t t, size_t *count)
{
const APEv2::Tag *tag = (const APEv2::Tag *)t;
if (!tag)
return NErr_NullPointer;
return tag->GetItemCount(count);
}
int NSAPEv2_Tag_GetItemAtIndex(const nsapev2_tag_t t, unsigned int index, nsapev2_item_t *item)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_NullPointer;
return tag->GetItemAtIndex(index, (APEv2::Item **)item);
}
int NSAPEv2_Item_GetInformation(const nsapev2_item_t i, const char **key, uint32_t *flags)
{
const APEv2::Item *item = (const APEv2::Item *)i;
if (!item)
return NErr_NullPointer;
if (key)
{
int ret = item->GetKey(key);
if (ret != NErr_Success)
return ret;
}
if (flags)
*flags = item->GetFlags();
return NErr_Success;
}
int NSAPEv2_Item_GetString(const nsapev2_item_t i, nx_string_t *value)
{
const APEv2::Item *item = (const APEv2::Item *)i;
if (!item)
return NErr_BadParameter;
const void *data;
size_t data_len;
int ret = item->Get(&data, &data_len);
if (ret != NErr_Success)
return ret;
return NXStringCreateWithBytes(value, data, data_len, nx_charset_utf8);
}
int NSAPEv2_Item_GetBinary(const nsapev2_item_t i, const void **bytes, size_t *length)
{
const APEv2::Item *item = (const APEv2::Item *)i;
if (!item)
return NErr_BadParameter;
return item->Get(bytes, length);
}
int NSAPEv2_Item_SetKey(nsapev2_item_t i, const char *key)
{
APEv2::Item *item = (APEv2::Item *)i;
if (!item)
return NErr_BadParameter;
return item->SetKey(key);
}
int NSAPEv2_Item_SetString(nsapev2_item_t i, nx_string_t value)
{
APEv2::Item *item = (APEv2::Item *)i;
if (!item)
return NErr_BadParameter;
return item->Set(value);
}
int NSAPEv2_Tag_RemoveItem(nsapev2_tag_t t, nsapev2_item_t i)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
APEv2::Item *item = (APEv2::Item *)i;
if (!item)
return NErr_BadParameter;
tag->RemoveItem(item);
return NErr_Success;
}
int NSAPEv2_Tag_AddItem(nsapev2_tag_t t, nsapev2_item_t *i)
{
APEv2::Tag *tag = (APEv2::Tag *)t;
if (!tag)
return NErr_BadParameter;
APEv2::Item **item = (APEv2::Item **)i;
if (!item)
return NErr_NullPointer;
*item = new (std::nothrow) APEv2::Item;
if (!*item)
return NErr_OutOfMemory;
return tag->AddItem(*item);
}

View File

@ -0,0 +1,26 @@
//
// precomp.h
// nsapev2
//
#include "foundation/error.h"
#include "foundation/types.h"
#include "nu/ByteReader.h"
#include "nu/ByteWriter.h"
#include "nu/strsafe.h"
#ifdef __cplusplus
#include "nu/PtrDeque.h"
#endif
#include "nx/nxstring.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
#include "header.h"
#include "new"
#endif

View File

@ -0,0 +1,285 @@
#include "tag.h"
#include "header.h"
#include "flags.h"
#ifdef _WIN32
#include "../nu/ns_wc.h"
#include "nu/strsafe.h"
#endif
#include <limits.h>
#include <new>
#include "nu/ByteWriter.h"
/*
http://wiki.hydrogenaudio.org/index.php?title=APEv2_specification
*/
APEv2::Tag::Tag()
{
flags = 0; // default to writing just a footer
}
APEv2::Tag::~Tag()
{
items.deleteAll();
}
/* Parsing */
int APEv2::Tag::Parse(const APEv2::Header *header, const void *_data, size_t len)
{
flags = header->GetFlags();
if (header->IsFooter())
{
flags &= ~FLAG_HEADER_NO_FOOTER; // winamp 5.54 had this flag reversed, so let's correct it
if (header->HasHeader())
{
// TODO: validate header
_data = (const uint8_t *)_data + 32;
len -= 32;
}
len -= 32; /* footer is counted in the size */
return ParseData(_data, len);
}
else /* IsHeader() */
{
if (header->HasFooter())
{
// TODO: validate footer
len -= 32;
}
return ParseData(_data, len);
}
}
int APEv2::Tag::ParseData(const void *data, size_t len)
{
bytereader_s byte_reader;
bytereader_init(&byte_reader, data, len);
while (bytereader_size(&byte_reader))
{
Item *item = new (std::nothrow) Item;
if (!item)
return NErr_OutOfMemory;
int ret = item->Read(&byte_reader);
if (ret == NErr_Success)
{
items.push_back(item);
}
else
{
delete item;
return ret;
}
}
return NErr_Success;
}
/* Retrieving Data */
int APEv2::Tag::GetItem(const char *key, unsigned int index, Item **item, int compare) const
{
unsigned int i=0;
for (ItemList::iterator itr=items.begin();itr!=items.end();itr++)
{
/* check if it's a string first, and then match the key next (will be faster) */
if (itr->KeyMatch(key, compare))
{
if (i++ < index)
continue;
*item = *itr;
return NErr_Success;
}
}
if (i > index) /* if we found the key once, but the index was too high */
return NErr_EndOfEnumeration;
return NErr_Empty;
}
int APEv2::Tag::GetItemAtIndex(unsigned int index, Item **item) const
{
unsigned int i=0;
for (ItemList::iterator itr=items.begin();itr!=items.end();itr++)
{
if (i++ < index)
continue;
*item = *itr;
return NErr_Success;
}
return NErr_EndOfEnumeration;
}
int APEv2::Tag::GetData(const char *key, unsigned int index, const void **data, size_t *data_len, int compare) const
{
Item *item=0;
int ret = GetItem(key, index, &item, compare);
if (ret != NErr_Success)
return ret;
return item->Get(data, data_len);
}
int APEv2::Tag::EnumerateItems(const Item *start, Item **item) const
{
Item *next_item = 0;
if (!start)
{
next_item = items.front();
}
else
{
next_item = static_cast<APEv2::Item *>(start->next);
}
*item = next_item;
if (next_item)
return NErr_Success;
else if (start)
return NErr_EndOfEnumeration;
else
return NErr_Empty;
}
int APEv2::Tag::FindItemByKey(const char *key, Item **item, int compare) const
{
for (ItemList::iterator itr=items.begin();itr!=items.end();itr++)
{
if (itr->KeyMatch(key, compare))
{
*item = *itr;
return NErr_Success;
}
}
return NErr_Unknown;
}
bool APEv2::Tag::IsReadOnly() const
{
return flags & FLAG_READONLY;
}
int APEv2::Tag::GetItemCount(size_t *count) const
{
*count = items.size();
return NErr_Success;
}
int APEv2::Tag::GetFlags(uint32_t *flags) const
{
*flags = this->flags;
return NErr_Success;
}
/* Setting Data */
int APEv2::Tag::AddItem(APEv2::Item *new_item)
{
items.push_back(new_item);
return NErr_Success;
}
int APEv2::Tag::SetFlags(uint32_t newflags, uint32_t mask)
{
flags = (flags & ~mask) | newflags;
return NErr_Success;
}
/* Removing Data */
void APEv2::Tag::Clear()
{
items.deleteAll();
}
void APEv2::Tag::Remove(const char *key, unsigned int starting_index, int compare)
{
for (ItemList::iterator itr=items.begin();itr!=items.end();)
{
ItemList::iterator next = itr;
next++;
APEv2::Item *item = *itr;
if (item->KeyMatch(key, compare))
{
if (starting_index)
{
starting_index--;
}
else
{
items.erase(item);
delete item;
}
}
itr=next;
}
}
void APEv2::Tag::RemoveItem(Item *item)
{
items.erase(item);
delete item;
}
/* Serializing */
size_t APEv2::Tag::EncodeSize() const
{
size_t total_size=0;
if (flags & FLAG_HEADER_HAS_HEADER)
total_size+=Header::SIZE;
for (ItemList::iterator itr=items.begin();itr!=items.end();itr++)
{
total_size += itr->EncodeSize();
}
if (!(flags & FLAG_HEADER_NO_FOOTER))
total_size+=Header::SIZE;
return total_size;
}
int APEv2::Tag::Encode(void *data, size_t len) const
{
bytewriter_s byte_writer;
bytewriter_init(&byte_writer, data, len);
if (flags & FLAG_HEADER_HAS_HEADER)
{
Header header;
header.SetSize((uint32_t)len - Header::SIZE);
header.SetItems((uint32_t)items.size());
header.SetFlags((flags & FLAG_HEADER_ENCODE_MASK)|FLAG_HEADER_IS_HEADER);
int ret = header.Encode(&byte_writer);
if (ret != NErr_Success)
return ret;
}
for (ItemList::iterator itr=items.begin();itr!=items.end();itr++)
{
int ret = itr->Encode(&byte_writer);
if (ret!= NErr_Success)
return ret;
}
if (!(flags & FLAG_HEADER_NO_FOOTER))
{
Header footer;
if (flags & FLAG_HEADER_HAS_HEADER)
footer.SetSize((uint32_t)len - Header::SIZE);
else
footer.SetSize((uint32_t)len);
footer.SetItems((uint32_t)items.size());
footer.SetFlags((flags & FLAG_HEADER_ENCODE_MASK));
int ret = footer.Encode(&byte_writer);
if (ret != NErr_Success)
return ret;
}
return NErr_Success;
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "foundation/types.h"
#include "nu/PtrDeque.h"
#include "item.h"
#include "flags.h"
#include "header.h"
namespace APEv2
{
class Tag
{
public:
Tag();
~Tag();
/* Parsing */
int Parse(const APEv2::Header *header, const void *data, size_t len);
/* Retrieving Data */
int GetItem(const char *key, unsigned int index, Item **item, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE) const;
int GetItemAtIndex(unsigned int index, Item **) const;
int GetData(const char *tag, unsigned int index, const void **data, size_t *data_len, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE) const;
int EnumerateItems(const Item *start, Item **item) const;
int FindItemByKey(const char *key, Item **item, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE) const;
bool IsReadOnly() const;
int GetItemCount(size_t *count) const;
int GetFlags(uint32_t *flags) const;
/* Setting Data */
int AddItem(APEv2::Item *new_item);
int SetFlags(uint32_t flags, uint32_t mask);
/* Removing Data */
void Clear();
void Remove(const char *key, unsigned int starting_index, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE); // removes all items matching a key, but skips the first 'starting_index' items
void RemoveItem(Item *item);
/* Serializing */
size_t EncodeSize() const;
int Encode(void *data, size_t len) const;
private: /* methods */
int ParseData(const void *data, size_t len); /* helper function, call with data pointing to beginning of items block (skip header), and length without footer. */
private: /* data */
typedef nu::PtrDeque<Item> ItemList;
ItemList items;
uint32_t flags;
};
}

View File

@ -0,0 +1 @@
#pragma once

View File

@ -0,0 +1 @@
#include "nsapev2/nsapev2.h"

View File

@ -0,0 +1,20 @@
#pragma once
#include "foundation/export.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
#ifdef NSID3V2_EXPORTS
#define NSAPEV2_EXPORT __declspec(dllexport)
#else
#define NSAPEV2_EXPORT __declspec(dllimport)
#endif
*/
#define NSAPEV2_EXPORT
#ifdef __cplusplus
}
#endif