diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nsid3v1 | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nsid3v1')
-rw-r--r-- | Src/replicant/nsid3v1/VERSION | 1 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/nsid3v1.cpp | 350 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/nsid3v1.h | 67 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/nsid3v1.sln | 44 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/nsid3v1.vcxproj | 171 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/precomp.h | 18 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/tag.cpp | 177 | ||||
-rw-r--r-- | Src/replicant/nsid3v1/tag.h | 54 |
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; + }; +} |