aboutsummaryrefslogtreecommitdiff
path: root/Src/replicant/nsid3v1
diff options
context:
space:
mode:
Diffstat (limited to 'Src/replicant/nsid3v1')
-rw-r--r--Src/replicant/nsid3v1/VERSION1
-rw-r--r--Src/replicant/nsid3v1/nsid3v1.cpp350
-rw-r--r--Src/replicant/nsid3v1/nsid3v1.h67
-rw-r--r--Src/replicant/nsid3v1/nsid3v1.sln44
-rw-r--r--Src/replicant/nsid3v1/nsid3v1.vcxproj171
-rw-r--r--Src/replicant/nsid3v1/precomp.h18
-rw-r--r--Src/replicant/nsid3v1/tag.cpp177
-rw-r--r--Src/replicant/nsid3v1/tag.h54
8 files changed, 882 insertions, 0 deletions
diff --git a/Src/replicant/nsid3v1/VERSION b/Src/replicant/nsid3v1/VERSION
new file mode 100644
index 00000000..ea710abb
--- /dev/null
+++ b/Src/replicant/nsid3v1/VERSION
@@ -0,0 +1 @@
+1.2 \ No newline at end of file
diff --git a/Src/replicant/nsid3v1/nsid3v1.cpp b/Src/replicant/nsid3v1/nsid3v1.cpp
new file mode 100644
index 00000000..b96c095f
--- /dev/null
+++ b/Src/replicant/nsid3v1/nsid3v1.cpp
@@ -0,0 +1,350 @@
+#include "nsid3v1.h"
+#include "tag.h"
+
+#include "foundation/error.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <new>
+
+
+int NSID3v1_Header_Valid(const void *data, size_t len)
+{
+ // return NErr_True or NErr_False depending on whether or not you detect that it's valid ID3v1
+ if (memcmp(data, "TAG", 3) == 0)
+ {
+ return NErr_True;
+ }
+
+ return NErr_False;
+}
+
+int NSID3v1_Tag_Create(const void *data, size_t len, nsid3v1_tag_t *out_tag)
+{
+ ID3v1::Tag *tag = new (std::nothrow) ID3v1::Tag();
+ if (!tag)
+ return NErr_OutOfMemory;
+
+ int ret = tag->Parse(data, len);
+ if (ret != NErr_Success)
+ return ret;
+
+ *out_tag = (nsid3v1_tag_t)tag;
+
+ return NErr_Success;
+}
+
+int NSID3v1_Tag_New(nsid3v1_tag_t *out_tag)
+{
+ ID3v1::Tag *tag = new (std::nothrow) ID3v1::Tag();
+ if (!tag)
+ return NErr_OutOfMemory;
+
+ tag->New();
+
+ *out_tag = (nsid3v1_tag_t)tag;
+
+ return NErr_Success;
+}
+
+int NSID3v1_Tag_Serialize(const nsid3v1_tag_t t, void *data, size_t len)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!tag)
+ return NErr_BadParameter;
+
+ return tag->Serialize(data, len);
+}
+
+int NSID3v1_Tag_Destroy(nsid3v1_tag_t t)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!tag)
+ return NErr_BadParameter;
+ delete tag;
+ return NErr_Success;
+}
+
+
+// Field getters
+int NSID3v1_Field_Text_Get(const nsid3v1_tag_t t, const int field, nx_string_t *out_value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ char track_num[4] = { 0, 0, 0 };
+
+ if (tag)
+ {
+ switch (field)
+ {
+ case NSID3V1_TITLE:
+ return NSID3v1_Get_Title(t, out_value);
+ case NSID3V1_ARTIST:
+ return NSID3v1_Get_Artist(t, out_value);
+ case NSID3V1_ALBUM:
+ return NSID3v1_Get_Album(t, out_value);
+ case NSID3V1_YEAR:
+ return NSID3v1_Get_Year(t, out_value);
+ case NSID3V1_COMMENT:
+ return NSID3v1_Get_Comment(t, out_value);
+ case NSID3V1_TRACK:
+ return NSID3v1_Get_Track(t, out_value);
+ //case NSID3V1_GENRE:
+ //return NSID3v1_Get_Genre(t, out_value);
+ default:
+ return NErr_Unknown;
+ }
+ }
+ else
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Title(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ size_t value_length = tag->GetTitleLength();
+ if (value_length > 0)
+ return NXStringCreateWithBytes(value, tag->GetTitle(), value_length, nx_charset_latin1);
+ else
+ return NErr_Empty;
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Artist(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ size_t value_length = tag->GetArtistLength();
+ if (value_length > 0)
+ return NXStringCreateWithBytes(value, tag->GetArtist(), value_length, nx_charset_latin1);
+ else
+ return NErr_Empty;
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Album(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ size_t value_length = tag->GetAlbumLength();
+ if (value_length > 0)
+ return NXStringCreateWithBytes(value, tag->GetAlbum(), value_length, nx_charset_latin1);
+ else
+ return NErr_Empty;
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Year(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ size_t value_length = tag->GetYearLength();
+ if (value_length > 0)
+ return NXStringCreateWithBytes(value, tag->GetYear(), value_length, nx_charset_latin1);
+ else
+ return NErr_Empty;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Comment(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ size_t value_length = tag->GetCommentLength();
+ if (value_length > 0)
+ return NXStringCreateWithBytes(value, tag->GetComment(), value_length, nx_charset_latin1);
+ else
+ return NErr_Empty;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Get_Track(nsid3v1_tag_t t, nx_string_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+
+
+ if (tag)
+ {
+ unsigned char track = tag->GetTrack();
+ if (track > 0)
+ return NXStringCreateWithUInt64(value, track);
+ else
+ return NErr_Empty;
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Int_Get_Year(nsid3v1_tag_t t, unsigned int *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ char year[5];
+ memcpy(year, tag->GetYear(), 4);
+ year[4]=0;
+ *value = strtoul(year, 0, 10);
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Int_Get_Track(nsid3v1_tag_t t, uint8_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ *value = tag->GetTrack();
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+int NSID3v1_Int_Get_Genre(nsid3v1_tag_t t, uint8_t *value)
+{
+ const ID3v1::Tag *tag = (const ID3v1::Tag *)t;
+ if (tag)
+ {
+ *value = tag->GetGenre();
+ return NErr_Success;
+ }
+ return NErr_Empty;
+}
+
+/* ================= setters ================= */
+typedef void (ID3v1::Tag::*Setter)(const char *, size_t length);
+template <size_t limit>
+static int SetFromString(ID3v1::Tag *tag, Setter setter, nx_string_t value)
+{
+ if (!value)
+ {
+ (tag->*setter)(0, 0);
+ return NErr_Success;
+ }
+
+ char temp[limit];
+ size_t bytes_copied;
+ int ret = NXStringGetBytes(&bytes_copied, value, temp, limit, nx_charset_latin1, 0);
+ if (ret != NErr_Success)
+ return ret;
+
+ (tag->*setter)(temp, bytes_copied);
+ return NErr_Success;
+}
+
+int NSID3v1_Set_Title(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+ return SetFromString<30>(tag, &ID3v1::Tag::SetTitle, value);
+}
+
+int NSID3v1_Set_Artist(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+ return SetFromString<30>(tag, &ID3v1::Tag::SetArtist, value);
+}
+
+int NSID3v1_Set_Album(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ return SetFromString<30>(tag, &ID3v1::Tag::SetAlbum, value);
+}
+
+int NSID3v1_Set_Year(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ return SetFromString<4>(tag, &ID3v1::Tag::SetYear, value);
+}
+
+int NSID3v1_Set_Comment(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ return SetFromString<28>(tag, &ID3v1::Tag::SetComment, value);
+}
+
+int NSID3v1_Set_Track(nsid3v1_tag_t t, nx_string_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ if (!value)
+ {
+ tag->SetTrack(0);
+ return NErr_Success;
+ }
+
+ int temp=0;
+ int ret = NXStringGetIntegerValue(value, &temp);
+ if (ret != NErr_Success)
+ return ret;
+
+ if (temp < 0 || temp > 255)
+ return NErr_ParameterOutOfRange;
+
+ tag->SetTrack((uint8_t)temp);
+ return NErr_Success;
+}
+
+int NSID3v1_Int_Set_Year(nsid3v1_tag_t t, unsigned int value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ if (value > 9999)
+ return NErr_ParameterOutOfRange;
+
+ char temp[5];
+ sprintf(temp, "%u", value);
+ tag->SetYear(temp, 4);
+
+ return NErr_Success;
+}
+
+int NSID3v1_Int_Set_Track(nsid3v1_tag_t t, uint8_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ tag->SetTrack(value);
+ return NErr_Success;
+}
+
+
+int NSID3v1_Int_Set_Genre(nsid3v1_tag_t t, uint8_t value)
+{
+ ID3v1::Tag *tag = (ID3v1::Tag *)t;
+ if (!t)
+ return NErr_BadParameter;
+
+ tag->SetGenre(value);
+ return NErr_Success;
+}
diff --git a/Src/replicant/nsid3v1/nsid3v1.h b/Src/replicant/nsid3v1/nsid3v1.h
new file mode 100644
index 00000000..dcd6e155
--- /dev/null
+++ b/Src/replicant/nsid3v1/nsid3v1.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "nx/nxstring.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NSID3V1_EXPORT
+ typedef struct nsid3v1_tag_struct_t { } *nsid3v1_tag_t;
+
+
+
+ // Basic methods
+ NSID3V1_EXPORT int NSID3v1_Header_Valid(const void *data, size_t len);
+ NSID3V1_EXPORT int NSID3v1_Tag_Create(const void *data, size_t len, nsid3v1_tag_t *out_tag);
+ NSID3V1_EXPORT int NSID3v1_Tag_New(nsid3v1_tag_t *out_tag);
+ // len must be >= 128. ALWAYS writes 128 bytes if successful
+ NSID3V1_EXPORT int NSID3v1_Tag_Serialize(const nsid3v1_tag_t t, void *data, size_t len);
+ NSID3V1_EXPORT int NSID3v1_Tag_Destroy(nsid3v1_tag_t t);
+
+ // Generic getters
+ //NSID3V1_EXPORT int NSID3v1_Field_Text_Get(const nsid3v1_tag_t *t, const int field, nx_string_t *out_value);
+ NSID3V1_EXPORT int NSID3v1_Field_Text_Get(const nsid3v1_tag_t t, const int field, nx_string_t *out_value);
+
+ // Specific field getters as text
+ NSID3V1_EXPORT int NSID3v1_Get_Title(const nsid3v1_tag_t t, nx_string_t *value);
+ NSID3V1_EXPORT int NSID3v1_Get_Artist(const nsid3v1_tag_t t, nx_string_t *value);
+ NSID3V1_EXPORT int NSID3v1_Get_Album(const nsid3v1_tag_t t, nx_string_t *value);
+ NSID3V1_EXPORT int NSID3v1_Get_Year(const nsid3v1_tag_t t, nx_string_t *value);
+ NSID3V1_EXPORT int NSID3v1_Get_Comment(const nsid3v1_tag_t t, nx_string_t *value);
+ NSID3V1_EXPORT int NSID3v1_Get_Track(const nsid3v1_tag_t t, nx_string_t *value);
+
+ // Specific field getters as integers
+ NSID3V1_EXPORT int NSID3v1_Int_Get_Year(const nsid3v1_tag_t t, unsigned int *value);
+ NSID3V1_EXPORT int NSID3v1_Int_Get_Track(const nsid3v1_tag_t t, uint8_t *value);
+ NSID3V1_EXPORT int NSID3v1_Int_Get_Genre(const nsid3v1_tag_t t, uint8_t *value);
+
+ // Specific field setters as text
+ NSID3V1_EXPORT int NSID3v1_Set_Title(nsid3v1_tag_t t, nx_string_t value);
+ NSID3V1_EXPORT int NSID3v1_Set_Artist(nsid3v1_tag_t t, nx_string_t value);
+ NSID3V1_EXPORT int NSID3v1_Set_Album(nsid3v1_tag_t t, nx_string_t value);
+ NSID3V1_EXPORT int NSID3v1_Set_Year(nsid3v1_tag_t t, nx_string_t value);
+ NSID3V1_EXPORT int NSID3v1_Set_Comment(nsid3v1_tag_t t, nx_string_t value);
+ NSID3V1_EXPORT int NSID3v1_Set_Track(nsid3v1_tag_t t, nx_string_t value);
+
+ // Specific field setters as integers
+ NSID3V1_EXPORT int NSID3v1_Int_Set_Year(nsid3v1_tag_t t, unsigned int value);
+ NSID3V1_EXPORT int NSID3v1_Int_Set_Track(nsid3v1_tag_t t, uint8_t value);
+ NSID3V1_EXPORT int NSID3v1_Int_Set_Genre(nsid3v1_tag_t t, uint8_t value);
+
+ // field types for ID3V1.0
+ enum
+ {
+ NSID3V1_TAG,
+ NSID3V1_TITLE,
+ NSID3V1_ARTIST,
+ NSID3V1_ALBUM,
+ NSID3V1_YEAR,
+ NSID3V1_COMMENT,
+ NSID3V1_TRACK, // ID3V1.1
+ NSID3V1_GENRE,
+ };
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Src/replicant/nsid3v1/nsid3v1.sln b/Src/replicant/nsid3v1/nsid3v1.sln
new file mode 100644
index 00000000..8bf831f5
--- /dev/null
+++ b/Src/replicant/nsid3v1/nsid3v1.sln
@@ -0,0 +1,44 @@
+
+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}") = "nsid3v1", "nsid3v1.vcxproj", "{1BF331E2-00BE-4ACC-B491-8C5DA35FA716}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
+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
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Debug|Win32.Build.0 = Debug|Win32
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Debug|x64.ActiveCfg = Debug|x64
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Debug|x64.Build.0 = Debug|x64
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Release|Win32.ActiveCfg = Release|Win32
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Release|Win32.Build.0 = Release|Win32
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Release|x64.ActiveCfg = Release|x64
+ {1BF331E2-00BE-4ACC-B491-8C5DA35FA716}.Release|x64.Build.0 = 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}.Debug|x64.Build.0 = 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
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B1F650AF-5553-4512-9413-CCE4ACF1FB2F}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/replicant/nsid3v1/nsid3v1.vcxproj b/Src/replicant/nsid3v1/nsid3v1.vcxproj
new file mode 100644
index 00000000..9e8b6721
--- /dev/null
+++ b/Src/replicant/nsid3v1/nsid3v1.vcxproj
@@ -0,0 +1,171 @@
+<?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>{1BF331E2-00BE-4ACC-B491-8C5DA35FA716}</ProjectGuid>
+ <RootNamespace>nsid3v1</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>
+ <ProjectReference Include="..\nu\nu.vcxproj">
+ <Project>{efc75a79-269f-44fc-bac5-d7d4fd4ec92c}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="nsid3v1.cpp" />
+ <ClCompile Include="tag.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="nsid3v1.h" />
+ <ClInclude Include="precomp.h" />
+ <ClInclude Include="tag.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/replicant/nsid3v1/precomp.h b/Src/replicant/nsid3v1/precomp.h
new file mode 100644
index 00000000..ccbf5115
--- /dev/null
+++ b/Src/replicant/nsid3v1/precomp.h
@@ -0,0 +1,18 @@
+//
+// precomp.h
+// nsid3v1
+//
+
+#include "foundation/error.h"
+#include "foundation/types.h"
+
+#include "nu/ByteReader.h"
+#include "nu/ByteWriter.h"
+
+#include "nx/nxstring.h"
+
+#include <limits.h>
+#include <new>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
diff --git a/Src/replicant/nsid3v1/tag.cpp b/Src/replicant/nsid3v1/tag.cpp
new file mode 100644
index 00000000..fd0fc163
--- /dev/null
+++ b/Src/replicant/nsid3v1/tag.cpp
@@ -0,0 +1,177 @@
+#include "tag.h"
+#include <string.h> // for strnlen
+
+#include "nsid3v1.h"
+
+#include "foundation/error.h"
+#include "nu/ByteReader.h"
+#include "nu/ByteWriter.h"
+
+#ifdef __APPLE__
+
+inline static size_t id3v1_strnlen(const char *s, size_t n)
+{
+ const char *p=(const char *)memchr(s, 0, n);
+ return p?p-s:n;
+}
+
+#else // __APPLE__
+
+inline static size_t id3v1_strnlen(const char *s, size_t n)
+{
+ return strnlen(s, n);
+}
+
+#endif
+
+
+ID3v1::Tag::Tag()
+{
+}
+
+void ID3v1::Tag::New()
+{
+ header[0]='T';
+ header[1]='A';
+ header[2]='G';
+ memset(title, 0, 30);
+ memset(artist, 0, 30);
+ memset(album, 0, 30);
+ memset(year, 0, 30);
+ memset(comment, 0, 30);
+ track=0;
+ genre=0;
+}
+
+// Deprecated, bytereader class can now handle n-number of bytes
+static void GetAndFillNumberOfBytes(bytereader_value_t byte_reader, int bytes, const void *data, char *destination)
+{
+ for (int i = 0; i < bytes; i++)
+ {
+ destination[i] = bytereader_read_u8(&byte_reader);
+ }
+}
+
+const char *ID3v1::Tag::GetHeader(void) const { return header; }
+const char *ID3v1::Tag::GetTitle(void) const { return title; }
+const char *ID3v1::Tag::GetArtist(void) const { return artist; }
+const char *ID3v1::Tag::GetAlbum(void) const { return album; }
+const char *ID3v1::Tag::GetYear(void) const { return year; }
+const char *ID3v1::Tag::GetComment(void) const { return comment; }
+uint8_t ID3v1::Tag::GetTrack(void) const { return track; }
+uint8_t ID3v1::Tag::GetGenre(void) const { return genre; }
+
+//unsigned int ID3v1::Tag::GetTitleLength(void) { return ( strlen(title) <= 30 ) ? strlen(title) : 30; }
+size_t ID3v1::Tag::GetHeaderLength(void) const { return id3v1_strnlen(header, 3); }
+size_t ID3v1::Tag::GetTitleLength(void) const { return id3v1_strnlen(title, 30); }
+size_t ID3v1::Tag::GetArtistLength(void) const { return id3v1_strnlen(artist, 30); }
+size_t ID3v1::Tag::GetAlbumLength(void) const { return id3v1_strnlen(album, 30); }
+size_t ID3v1::Tag::GetYearLength(void) const { return id3v1_strnlen(year, 4); }
+size_t ID3v1::Tag::GetCommentLength(void) const { return id3v1_strnlen(comment, 30); }
+
+int ID3v1::Tag::Parse(const void *data, size_t len)
+{
+ if (len < 128)
+ return NErr_NeedMoreData;
+
+ bytereader_value_t byte_reader;
+ bytereader_init(&byte_reader, data, len);
+
+ // Get header
+ bytereader_read_n(&byte_reader, header, 3);
+
+ // Get title
+ bytereader_read_n(&byte_reader, title, 30);
+
+ // Get artist
+ bytereader_read_n(&byte_reader, artist, 30);
+
+ // Get album
+ bytereader_read_n(&byte_reader, album, 30);
+
+ // Get year
+ bytereader_read_n(&byte_reader, year, 4);
+
+ // Get comments
+ bytereader_read_n(&byte_reader, comment, 30);
+
+ // Get genre
+ genre = bytereader_read_u8(&byte_reader);
+
+ // Check for the presence of track # inside of the comments field at offset position 29 & 30
+ if (comment[28] == 0 && comment[29] != 0)
+ {
+ track = comment[29];
+ }
+ else
+ track = 0;
+
+ return NErr_Success;
+}
+
+/* copies source_bytes characters to destination, and fills up the remaining (up to destination_length) with null */
+static void id3v1_strncpyn(char *destination, size_t destination_length, const char *source, size_t source_bytes)
+{
+ // make sure we don't write too much
+ if (source_bytes > destination_length)
+ source_bytes = destination_length;
+
+ memcpy(destination, source, source_bytes);
+ memset(destination+source_bytes, 0, destination_length-source_bytes); // zero remainder of string
+}
+
+void ID3v1::Tag::SetTitle(const char *new_title, size_t length)
+{
+ id3v1_strncpyn(title, 30, new_title, length);
+}
+
+void ID3v1::Tag::SetArtist(const char *new_artist, size_t length)
+{
+ id3v1_strncpyn(artist, 30, new_artist, length);
+}
+
+void ID3v1::Tag::SetAlbum(const char *new_album, size_t length)
+{
+ id3v1_strncpyn(album, 30, new_album, length);
+}
+
+void ID3v1::Tag::SetYear(const char *new_year, size_t length)
+{
+ id3v1_strncpyn(year, 4, new_year, length);
+}
+
+void ID3v1::Tag::SetComment(const char *new_comment, size_t length)
+{
+ id3v1_strncpyn(comment, 28, new_comment, length);
+}
+
+void ID3v1::Tag::SetTrack(uint8_t new_track)
+{
+ track = new_track;
+}
+
+void ID3v1::Tag::SetGenre(uint8_t new_genre)
+{
+ genre = new_genre;
+}
+
+int ID3v1::Tag::Serialize(void *data, size_t len)
+{
+ if (len < 128)
+ return NErr_Insufficient;
+
+ bytewriter_s byte_writer;
+ bytewriter_init(&byte_writer, data, len);
+
+ bytewriter_write_n(&byte_writer, header, 3);
+ bytewriter_write_n(&byte_writer, title, 30);
+ bytewriter_write_n(&byte_writer, artist, 30);
+ bytewriter_write_n(&byte_writer, album, 30);
+ bytewriter_write_n(&byte_writer, year, 4);
+ bytewriter_write_n(&byte_writer, comment, 28);
+ bytewriter_write_u8(&byte_writer, 0);
+ bytewriter_write_u8(&byte_writer, track);
+ bytewriter_write_u8(&byte_writer, genre);
+
+ return NErr_Success;
+}
diff --git a/Src/replicant/nsid3v1/tag.h b/Src/replicant/nsid3v1/tag.h
new file mode 100644
index 00000000..d54bdd03
--- /dev/null
+++ b/Src/replicant/nsid3v1/tag.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "nsid3v1.h"
+
+class nstest;
+
+namespace ID3v1
+{
+ class Tag
+ {
+ friend class nstest;
+ public:
+ Tag();
+ int Parse(const void *data, size_t len);
+ void New(); // creates an empty (but valid) tag
+
+ // Member value getters
+ const char *GetHeader(void) const;
+ const char *GetTitle(void) const;
+ const char *GetArtist(void) const;
+ const char *GetAlbum(void) const;
+ const char *GetYear(void) const;
+ const char *GetComment(void) const;
+ uint8_t GetTrack(void) const;
+ uint8_t GetGenre(void) const;
+
+ // Member length getters
+ size_t GetHeaderLength(void) const;
+ size_t GetTitleLength(void) const;
+ size_t GetArtistLength(void) const;
+ size_t GetAlbumLength(void) const;
+ size_t GetYearLength(void) const;
+ size_t GetCommentLength(void) const;
+
+ void SetTitle(const char *title, size_t length);
+ void SetArtist(const char *artist, size_t length);
+ void SetAlbum(const char *album, size_t length);
+ void SetYear(const char *year, size_t length);
+ void SetComment(const char *comment, size_t length);
+ void SetTrack(uint8_t track);
+ void SetGenre(uint8_t genre);
+
+ int Serialize(void *data, size_t len);
+ protected:
+ char header[3];
+ char title[30];
+ char artist[30];
+ char album[30];
+ char year[4];
+ char comment[30]; // Bytes 29 & 30 can contain 0 & genre respectivly, ID3V1.1
+ uint8_t track;
+ uint8_t genre;
+ };
+}