mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 20:55:45 -04:00
Initial community commit
This commit is contained in:
30
Src/apev2/apev2.sln
Normal file
30
Src/apev2/apev2.sln
Normal file
@ -0,0 +1,30 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29424.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apev2", "apev2.vcxproj", "{48387E27-2666-4ACF-9C21-AE508C529580}"
|
||||
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
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|Win32.Build.0 = Release|Win32
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|x64.Build.0 = Debug|x64
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|x64.ActiveCfg = Release|x64
|
||||
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5A83B542-4B24-4F95-B752-B5D7567B4F54}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
195
Src/apev2/apev2.vcxproj
Normal file
195
Src/apev2/apev2.vcxproj
Normal file
@ -0,0 +1,195 @@
|
||||
<?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>{48387E27-2666-4ACF-9C21-AE508C529580}</ProjectGuid>
|
||||
<RootNamespace>apev2</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</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>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnabled>false</VcpkgEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>../;../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<ForcedIncludeFiles>tag.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>../;../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<ForcedIncludeFiles>tag.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="flags.h" />
|
||||
<ClInclude Include="header.h" />
|
||||
<ClInclude Include="item.h" />
|
||||
<ClInclude Include="tag.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="header.cpp" />
|
||||
<ClCompile Include="item.cpp" />
|
||||
<ClCompile Include="tag.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
42
Src/apev2/apev2.vcxproj.filters
Normal file
42
Src/apev2/apev2.vcxproj.filters
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="header.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="item.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tag.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="flags.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="header.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="item.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tag.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{6cf90466-6c89-4be4-83c3-e7872a927708}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{eaaa2f1a-68ef-4456-8bfa-47b0c6183c31}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{6cd9a1b4-b2a9-412e-a920-a163ab8e3cf5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
40
Src/apev2/flags.h
Normal file
40
Src/apev2/flags.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef NULLSOFT_APEV2_FLAGS_H
|
||||
#define NULLSOFT_APEV2_FLAGS_H
|
||||
|
||||
namespace APEv2
|
||||
{
|
||||
enum
|
||||
{
|
||||
APEV2_SUCCESS = 0,
|
||||
APEV2_FAILURE = 1,
|
||||
APEV2_TOO_SMALL = 2,
|
||||
APEV2_KEY_NOT_FOUND=3,
|
||||
APEV2_NO_DATA = 4, /* Key found, but data is empty or corrupt */
|
||||
APEV2_END_OF_ITEMS=5,
|
||||
};
|
||||
/*
|
||||
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,
|
||||
|
||||
/* item specific flags */
|
||||
MASK_ITEM_TYPE = ((1 << 2) | (1 << 1)),
|
||||
|
||||
FLAG_ITEM_TEXT = 0,
|
||||
FLAG_ITEM_BINARY = (1 << 1), /* We compare WITHOUT SHIFTING so all flag values are << 1 */
|
||||
FLAG_ITEM_LOCATOR = (2 << 1),
|
||||
FLAG_ITEM_RESERVED = (3 << 1),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
88
Src/apev2/header.cpp
Normal file
88
Src/apev2/header.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "header.h"
|
||||
#include "flags.h"
|
||||
#include "util.h"
|
||||
#include <limits.h>
|
||||
|
||||
static char preamble[] = { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' };
|
||||
|
||||
APEv2::Header::Header(void *data)
|
||||
{
|
||||
memcpy(&headerData, data, sizeof(headerData));
|
||||
|
||||
// covert to host endian
|
||||
//headerData.preamble=htons(headerData.preamble);
|
||||
headerData.version=ATON16(headerData.version);
|
||||
headerData.size=ATON32(headerData.size);
|
||||
headerData.items=ATON32(headerData.items);
|
||||
headerData.flags=ATON32(headerData.flags);
|
||||
}
|
||||
|
||||
APEv2::Header::Header(const HeaderData *data)
|
||||
{
|
||||
memcpy(&headerData.preamble, preamble, sizeof(headerData.preamble));
|
||||
headerData.version = NTOA32(2000);
|
||||
headerData.size = data->size;
|
||||
headerData.items = data->items;
|
||||
headerData.flags = data->flags;
|
||||
headerData.reserved = 0;
|
||||
}
|
||||
|
||||
uint32_t APEv2::Header::GetFlags()
|
||||
{
|
||||
return headerData.flags;
|
||||
}
|
||||
|
||||
bool APEv2::Header::Valid()
|
||||
{
|
||||
return !memcmp(&headerData.preamble, preamble, 8) && headerData.reserved == 0;
|
||||
}
|
||||
|
||||
uint32_t APEv2::Header::TagSize()
|
||||
{
|
||||
size_t size = headerData.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()
|
||||
{
|
||||
return !!(headerData.flags & FLAG_HEADER_HAS_HEADER);
|
||||
}
|
||||
|
||||
bool APEv2::Header::HasFooter()
|
||||
{
|
||||
return !(headerData.flags & FLAG_HEADER_NO_FOOTER);
|
||||
}
|
||||
|
||||
bool APEv2::Header::IsFooter()
|
||||
{
|
||||
return !(headerData.flags & FLAG_HEADER_IS_HEADER);
|
||||
}
|
||||
|
||||
bool APEv2::Header::IsHeader()
|
||||
{
|
||||
return !!(headerData.flags & FLAG_HEADER_IS_HEADER);
|
||||
}
|
||||
|
||||
int APEv2::Header::Encode(void *data, size_t len)
|
||||
{
|
||||
if (len < 32)
|
||||
return APEV2_TOO_SMALL;
|
||||
|
||||
HeaderData endianCorrectData = headerData;
|
||||
|
||||
endianCorrectData.version=NTOA16(endianCorrectData.version);
|
||||
endianCorrectData.size=NTOA32(endianCorrectData.size);
|
||||
endianCorrectData.items=NTOA32(endianCorrectData.items);
|
||||
endianCorrectData.flags=NTOA32(endianCorrectData.flags);
|
||||
|
||||
memcpy(data, &endianCorrectData, sizeof(endianCorrectData));
|
||||
return APEV2_SUCCESS;
|
||||
}
|
44
Src/apev2/header.h
Normal file
44
Src/apev2/header.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef NULLSOFT_APEV2_HEADER_H
|
||||
#define NULLSOFT_APEV2_HEADER_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
namespace APEv2
|
||||
{
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct HeaderData
|
||||
{
|
||||
uint64_t preamble;
|
||||
uint32_t version;
|
||||
uint32_t size;
|
||||
uint32_t items;
|
||||
uint32_t flags;
|
||||
uint16_t reserved;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class Header
|
||||
{
|
||||
public:
|
||||
Header(void *data);
|
||||
Header(const HeaderData *data);
|
||||
bool Valid();
|
||||
uint32_t TagSize();
|
||||
bool HasHeader();
|
||||
bool HasFooter();
|
||||
bool IsFooter();
|
||||
bool IsHeader();
|
||||
int Encode(void *data, size_t len);
|
||||
uint32_t GetFlags();
|
||||
enum
|
||||
{
|
||||
SIZE=32,
|
||||
};
|
||||
private:
|
||||
HeaderData headerData;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
221
Src/apev2/item.cpp
Normal file
221
Src/apev2/item.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
#include "item.h"
|
||||
#include "flags.h"
|
||||
#include "util.h"
|
||||
#include <strsafe.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
http://wiki.hydrogenaudio.org/index.php?title=APE_Tag_Item
|
||||
*/
|
||||
|
||||
APEv2::Item::Item()
|
||||
{
|
||||
refCount=1;
|
||||
len=0;
|
||||
flags=0;
|
||||
key=0;
|
||||
value=0;
|
||||
}
|
||||
|
||||
APEv2::Item::~Item()
|
||||
{
|
||||
free(key);
|
||||
free(value);
|
||||
}
|
||||
|
||||
void APEv2::Item::Retain()
|
||||
{
|
||||
refCount++;
|
||||
}
|
||||
|
||||
void APEv2::Item::Release()
|
||||
{
|
||||
if (--refCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
int APEv2::Item::Read(void *_data, size_t datalen, void **new_data, size_t *new_len)
|
||||
{
|
||||
char *data = (char *)_data;
|
||||
|
||||
if (datalen < 4)
|
||||
return APEV2_TOO_SMALL;
|
||||
memcpy(&len, data, 4);
|
||||
len = ATON32(len);
|
||||
data+=4;
|
||||
datalen-=4;
|
||||
|
||||
if (datalen < 4)
|
||||
return APEV2_TOO_SMALL;
|
||||
memcpy(&flags, data, 4);
|
||||
flags = ATON32(flags);
|
||||
data+=4;
|
||||
datalen-=4;
|
||||
|
||||
uint32_t key_len=0;
|
||||
for (uint32_t i=0;i<datalen;i++)
|
||||
{
|
||||
if (data[i] == 0)
|
||||
{
|
||||
key_len=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_len == datalen)
|
||||
return APEV2_TOO_SMALL;
|
||||
|
||||
if (key_len == 0)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
if (key)
|
||||
{
|
||||
free(key);
|
||||
key = 0;
|
||||
}
|
||||
key = (char *)calloc(key_len+1, sizeof(char));
|
||||
if (key)
|
||||
{
|
||||
StringCchCopyA(key, key_len+1, data);
|
||||
datalen-=(key_len+1);
|
||||
data+=(key_len+1);
|
||||
|
||||
if (datalen < len)
|
||||
{
|
||||
free(key);
|
||||
key = 0;
|
||||
return APEV2_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
free(value);
|
||||
value = 0;
|
||||
}
|
||||
value = (char *)calloc(len, sizeof(char));
|
||||
if (value)
|
||||
{
|
||||
memcpy(value, data, len);
|
||||
datalen-=len;
|
||||
data+=len;
|
||||
*new_len = datalen;
|
||||
*new_data=data;
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(key);
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
|
||||
bool APEv2::Item::IsReadOnly()
|
||||
{
|
||||
return flags & FLAG_READONLY;
|
||||
}
|
||||
|
||||
bool APEv2::Item::IsString()
|
||||
{
|
||||
return (flags & MASK_ITEM_TYPE) == FLAG_ITEM_TEXT;
|
||||
}
|
||||
|
||||
bool APEv2::Item::KeyMatch(const char *key_to_compare, int compare)
|
||||
{
|
||||
if (!key || !*key)
|
||||
return false;
|
||||
|
||||
switch (compare)
|
||||
{
|
||||
case ITEM_KEY_COMPARE_CASE_INSENSITIVE:
|
||||
return !_stricmp(key_to_compare, key);
|
||||
case ITEM_KEY_COMPARE_CASE_SENSITIVE:
|
||||
return !strcmp(key_to_compare, key);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int APEv2::Item::Get(void **data, size_t *datalen)
|
||||
{
|
||||
if (!value || !len)
|
||||
return APEV2_FAILURE;
|
||||
*data = value;
|
||||
*datalen = len;
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Item::Set(const void *data, size_t datalen, int dataType)
|
||||
{
|
||||
if (!data || !datalen)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
// set data type for this item
|
||||
flags &= ~MASK_ITEM_TYPE;
|
||||
flags |= dataType;
|
||||
|
||||
free(value);
|
||||
value = malloc(datalen);
|
||||
len=(uint32_t)datalen;
|
||||
memcpy(value, data, len);
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Item::SetKey(const char *tag)
|
||||
{
|
||||
if (!tag || !*tag)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
free(key);
|
||||
key = _strdup(tag);
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Item::GetKey(const char **tag)
|
||||
{
|
||||
if (!key)
|
||||
return APEV2_FAILURE;
|
||||
*tag = key;
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
size_t APEv2::Item::EncodeSize()
|
||||
{
|
||||
return 4 /* size */ + 4 /* flags */ + (key && *key ? strlen(key) : 0) + 1 /* NULL separator */ + len;
|
||||
}
|
||||
|
||||
int APEv2::Item::Encode(void *data, size_t datalen)
|
||||
{
|
||||
if (!key || !value || !len)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
if (datalen < EncodeSize())
|
||||
return APEV2_TOO_SMALL;
|
||||
|
||||
int8_t *ptr = (int8_t *)data;
|
||||
|
||||
// write data length
|
||||
int32_t _len = NTOA32(len);
|
||||
memcpy(ptr, &_len, sizeof(_len));
|
||||
ptr+=sizeof(_len);
|
||||
datalen-=sizeof(_len);
|
||||
|
||||
// write flags
|
||||
int32_t _flags = NTOA32(flags);
|
||||
memcpy(ptr, &_flags, sizeof(_flags));
|
||||
ptr+=sizeof(_flags);
|
||||
datalen-=sizeof(_flags);
|
||||
|
||||
// write key and null terminator
|
||||
if (StringCchCopyExA((char *)ptr, datalen, key, (char **) &ptr, &datalen, 0) != S_OK)
|
||||
return APEV2_FAILURE;
|
||||
// account for null separator
|
||||
ptr++;
|
||||
datalen--;
|
||||
|
||||
// write data
|
||||
memcpy(ptr, value, len);
|
||||
return APEV2_SUCCESS;
|
||||
}
|
43
Src/apev2/item.h
Normal file
43
Src/apev2/item.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef NULLSOFT_APEV2_ITEM_H
|
||||
#define NULLSOFT_APEV2_ITEM_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
namespace APEv2
|
||||
{
|
||||
enum
|
||||
{
|
||||
ITEM_KEY_COMPARE_CASE_INSENSITIVE = 0,
|
||||
ITEM_KEY_COMPARE_CASE_SENSITIVE = 1,
|
||||
};
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item();
|
||||
~Item();
|
||||
void Retain();
|
||||
void Release();
|
||||
|
||||
/* If successful, puts incremented data pointer in new_data, and new data size remaining in new_len */
|
||||
int Read(void *data, size_t len, void **new_data, size_t *new_len);
|
||||
|
||||
int Encode(void *data, size_t len);
|
||||
size_t EncodeSize();
|
||||
|
||||
bool IsReadOnly();
|
||||
bool IsString();
|
||||
bool KeyMatch(const char *key, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE);
|
||||
int Get(void **data, size_t *len);
|
||||
int GetKey(const char **tag);
|
||||
int Set(const void *data, size_t len, int dataType);
|
||||
int SetKey(const char *tag);
|
||||
|
||||
private:
|
||||
size_t refCount;
|
||||
uint32_t flags;
|
||||
char *key;
|
||||
void *value;
|
||||
uint32_t len;
|
||||
};
|
||||
}
|
||||
#endif
|
353
Src/apev2/tag.cpp
Normal file
353
Src/apev2/tag.cpp
Normal file
@ -0,0 +1,353 @@
|
||||
#include "tag.h"
|
||||
#include "header.h"
|
||||
#include "flags.h"
|
||||
#include "nu/ns_wc.h"
|
||||
#include <limits.h>
|
||||
#include <strsafe.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
http://wiki.hydrogenaudio.org/index.php?title=APEv2_specification
|
||||
*/
|
||||
|
||||
APEv2::Tag::Tag()
|
||||
{
|
||||
flags = 0; // default to writing just a footer
|
||||
}
|
||||
|
||||
int APEv2::Tag::Parse(const void *_data, size_t len)
|
||||
{
|
||||
char *data = (char *)_data;
|
||||
|
||||
if (len < Header::SIZE)
|
||||
return APEV2_TOO_SMALL;
|
||||
|
||||
char *headerStart = data+(len-Header::SIZE);
|
||||
|
||||
Header footer(headerStart);
|
||||
if (footer.Valid()
|
||||
&& !(len == Header::SIZE && footer.IsHeader())) // if all we have is this footer, we should check that it's not really a header
|
||||
{
|
||||
len -= Header::SIZE;
|
||||
char *dataStart = data;
|
||||
if (footer.HasHeader())
|
||||
{
|
||||
// TODO: validate header
|
||||
dataStart+= Header::SIZE;
|
||||
len-=Header::SIZE;
|
||||
}
|
||||
flags = footer.GetFlags();
|
||||
flags &= ~FLAG_HEADER_NO_FOOTER; // winamp 5.54 had this flag reversed, so let's correct it
|
||||
return ParseData(dataStart, len);
|
||||
}
|
||||
|
||||
// ok, we didn't have a footer, so let's see if we have a header
|
||||
headerStart = data;
|
||||
Header header(headerStart);
|
||||
if (header.Valid())
|
||||
{
|
||||
len -= Header::SIZE;
|
||||
char *dataStart = data + Header::SIZE;
|
||||
if (header.HasFooter())
|
||||
{
|
||||
// TODO: validate footer
|
||||
// benski> cut... we got here because we didn't have a footer.
|
||||
//len-=Header::SIZE;
|
||||
}
|
||||
flags = header.GetFlags();
|
||||
flags |= FLAG_HEADER_NO_FOOTER; // winamp 5.54 had this flag reversed, so let's correct it
|
||||
return ParseData(dataStart, len);
|
||||
}
|
||||
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
|
||||
int APEv2::Tag::ParseData(const void *data, size_t len)
|
||||
{
|
||||
char *dataStart = (char *)data;
|
||||
while (len)
|
||||
{
|
||||
Item *item = new Item;
|
||||
size_t new_len = 0;
|
||||
void *new_data = 0;
|
||||
int ret = item->Read(dataStart, len, &new_data, &new_len);
|
||||
if (ret == APEV2_SUCCESS)
|
||||
{
|
||||
len = new_len;
|
||||
dataStart = (char *)new_data;
|
||||
items.push_back(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Release();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Tag::GetString(const char *tag, wchar_t *data, size_t dataLen)
|
||||
{
|
||||
/* our UTF-8 to wchar_t conversion function wants an int for size, so we should explicitly check the size */
|
||||
if (dataLen > INT_MAX)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
for ( APEv2::Item *l_item : items )
|
||||
{
|
||||
/* check if it's a string first, and then match the key next (will be faster) */
|
||||
if ( l_item->IsString() && l_item->KeyMatch(tag, ITEM_KEY_COMPARE_CASE_INSENSITIVE))
|
||||
{
|
||||
void *item_data = 0;
|
||||
size_t item_dataLen = 0;
|
||||
if ( l_item->Get(&item_data, &item_dataLen) == APEV2_SUCCESS && item_dataLen < INT_MAX)
|
||||
{
|
||||
int signed_len = static_cast<int>(item_dataLen); // we checked against INT_MAX above so this conversion is safe
|
||||
if (MultiByteToWideCharSZ(CP_UTF8, 0, (LPCSTR)item_data, signed_len, data, (int)dataLen) != 0)
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
return APEV2_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
return APEV2_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
int APEv2::Tag::SetItemData(APEv2::Item *item, const wchar_t *data)
|
||||
{
|
||||
int utf16_data_cch = (int)wcslen(data);
|
||||
int item_dataLen = WideCharToMultiByte(CP_UTF8, 0, data, utf16_data_cch, 0, 0, NULL, NULL);
|
||||
if (!item_dataLen)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
char *item_data = (char *)calloc(item_dataLen, sizeof(char));
|
||||
if (item_data)
|
||||
{
|
||||
if (!WideCharToMultiByte(CP_UTF8, 0, data, utf16_data_cch, item_data, item_dataLen, NULL, NULL))
|
||||
{
|
||||
free(item_data);
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
|
||||
item->Set(item_data, item_dataLen, FLAG_ITEM_TEXT);
|
||||
free(item_data);
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
|
||||
int APEv2::Tag::SetString(const char *tag, const wchar_t *data)
|
||||
{
|
||||
for (auto it = items.begin(); it != items.end(); it++)
|
||||
{
|
||||
APEv2::Item* item = *it;
|
||||
if (item->KeyMatch(tag, ITEM_KEY_COMPARE_CASE_INSENSITIVE))
|
||||
{
|
||||
if (data && *data)
|
||||
{
|
||||
return SetItemData(item, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Release();
|
||||
it = items.erase(it);
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data && *data)
|
||||
{
|
||||
/* Not already in the list, so we need to add it */
|
||||
Item *newItem = new Item;
|
||||
|
||||
if (newItem->SetKey(tag) == APEV2_SUCCESS && SetItemData(newItem, data) == APEV2_SUCCESS)
|
||||
{
|
||||
items.push_back(newItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem->Release();
|
||||
return APEV2_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Tag::EnumValue(size_t i, const char **tag, wchar_t *data, size_t dataLen)
|
||||
{
|
||||
/* our UTF-8 to wchar_t conversion function wants an int for size, so we should explicitly check the size */
|
||||
if (dataLen > INT_MAX)
|
||||
return APEV2_FAILURE;
|
||||
|
||||
if (i >= items.size())
|
||||
return APEV2_END_OF_ITEMS;
|
||||
|
||||
APEv2::Item *item = items[i];
|
||||
item->GetKey(tag);
|
||||
|
||||
if (!data || !dataLen) // if they don't want the data, go ahead and return now
|
||||
return APEV2_SUCCESS;
|
||||
|
||||
data[0]=0;
|
||||
void *item_data = 0;
|
||||
size_t item_dataLen = 0;
|
||||
if (item->IsString())
|
||||
{
|
||||
if (item->Get(&item_data, &item_dataLen) == APEV2_SUCCESS && item_dataLen < INT_MAX)
|
||||
{
|
||||
int signed_len = static_cast<int>(item_dataLen); // we checked against INT_MAX above so this conversion is safe
|
||||
if (MultiByteToWideCharSZ(CP_UTF8, 0, (LPCSTR)item_data, signed_len, data, (int)dataLen) == 0)
|
||||
*data=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: benski> hmmm
|
||||
StringCchCopyW(data, dataLen, L"[TODO: deal with binary]");
|
||||
}
|
||||
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
void APEv2::Tag::Clear()
|
||||
{
|
||||
for ( APEv2::Item *l_item : items )
|
||||
{
|
||||
l_item->Release();
|
||||
}
|
||||
|
||||
items.clear();
|
||||
}
|
||||
|
||||
int APEv2::Tag::RemoveItem(size_t index)
|
||||
{
|
||||
if (index >= items.size())
|
||||
return APEV2_END_OF_ITEMS;
|
||||
|
||||
APEv2::Item *item = items[index];
|
||||
items.erase(items.begin() + index);
|
||||
item->Release();
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
size_t APEv2::Tag::EncodeSize()
|
||||
{
|
||||
size_t totalSize=0;
|
||||
|
||||
if (flags & FLAG_HEADER_HAS_HEADER)
|
||||
totalSize+=Header::SIZE;
|
||||
|
||||
for ( APEv2::Item *l_item : items )
|
||||
{
|
||||
totalSize += l_item->EncodeSize();
|
||||
}
|
||||
|
||||
if (!(flags & FLAG_HEADER_NO_FOOTER))
|
||||
totalSize+=Header::SIZE;
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int APEv2::Tag::Encode(void *data, size_t len)
|
||||
{
|
||||
size_t totalSize=0;
|
||||
int8_t *ptr = (int8_t *)data;
|
||||
|
||||
if (flags & FLAG_HEADER_HAS_HEADER)
|
||||
{
|
||||
HeaderData headerData = {0};
|
||||
headerData.size= (uint32_t)totalSize;
|
||||
if (!(flags & FLAG_HEADER_NO_FOOTER))
|
||||
headerData.size += Header::SIZE;
|
||||
headerData.items = (uint32_t)items.size();
|
||||
|
||||
headerData.flags = (flags & FLAG_HEADER_ENCODE_MASK)|FLAG_HEADER_IS_HEADER;
|
||||
|
||||
Header header(&headerData);
|
||||
int ret = header.Encode(ptr, len);
|
||||
if (ret != APEV2_SUCCESS)
|
||||
return ret;
|
||||
ptr += Header::SIZE;
|
||||
len -= Header::SIZE;
|
||||
}
|
||||
|
||||
for ( APEv2::Item *l_item : items )
|
||||
{
|
||||
int ret = l_item->Encode(ptr, len);
|
||||
if (ret!= APEV2_SUCCESS)
|
||||
return ret;
|
||||
size_t itemSize = l_item->EncodeSize();
|
||||
len-=itemSize;
|
||||
ptr+=itemSize;
|
||||
totalSize+=itemSize;
|
||||
}
|
||||
|
||||
if (!(flags & FLAG_HEADER_NO_FOOTER))
|
||||
{
|
||||
HeaderData footerData = {0};
|
||||
footerData.size= (uint32_t)totalSize + Header::SIZE;
|
||||
footerData.items = (uint32_t)items.size();
|
||||
footerData.flags = (flags & FLAG_HEADER_ENCODE_MASK);
|
||||
|
||||
Header footer(&footerData);
|
||||
int ret = footer.Encode(ptr, len);
|
||||
if (ret != APEV2_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Tag::SetKeyValueByIndex(size_t index, const char *key, const wchar_t *data)
|
||||
{
|
||||
if (index >= items.size())
|
||||
return APEV2_END_OF_ITEMS;
|
||||
|
||||
// TODO: check for duplicate key
|
||||
|
||||
items[index]->SetKey(key);
|
||||
return SetItemData(items[index], data);
|
||||
}
|
||||
|
||||
APEv2::Item *APEv2::Tag::AddItem()
|
||||
{
|
||||
Item *newItem = new Item;
|
||||
items.push_back(newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
int APEv2::Tag::SetFlags(uint32_t newflags, uint32_t mask)
|
||||
{
|
||||
flags = (flags & ~mask) | newflags;
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
|
||||
int APEv2::Tag::FindItemByKey(const char *key, size_t *index, int compare)
|
||||
{
|
||||
for (size_t i=0;i!=items.size();i++)
|
||||
{
|
||||
if (items[i]->KeyMatch(key, compare))
|
||||
{
|
||||
*index = i;
|
||||
return APEV2_SUCCESS;
|
||||
}
|
||||
}
|
||||
return APEV2_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t APEv2::Tag::GetNumItems()
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
bool APEv2::Tag::IsReadOnly()
|
||||
{
|
||||
return flags & FLAG_READONLY;
|
||||
}
|
||||
|
||||
bool APEv2::Tag::IsItemReadOnly(size_t index)
|
||||
{
|
||||
if (index >= items.size())
|
||||
return true;
|
||||
return items[index]->IsReadOnly();
|
||||
}
|
55
Src/apev2/tag.h
Normal file
55
Src/apev2/tag.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef NULLSOFT_APEV2_TAG_H
|
||||
#define NULLSOFT_APEV2_TAG_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
#include <vector>
|
||||
#include "item.h"
|
||||
#include "flags.h"
|
||||
|
||||
namespace APEv2
|
||||
{
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
|
||||
/* Parsing */
|
||||
int Parse(const void *data, size_t len);
|
||||
|
||||
/* Retrieving Data */
|
||||
int GetString(const char *tag, wchar_t *data, size_t dataLen);
|
||||
int EnumValue(size_t i, const char **tag, wchar_t *data, size_t dataLen);
|
||||
int FindItemByKey(const char *key, size_t *index, int compare=ITEM_KEY_COMPARE_CASE_INSENSITIVE);
|
||||
size_t GetNumItems();
|
||||
bool IsReadOnly();
|
||||
bool IsItemReadOnly(size_t index);
|
||||
|
||||
/* Setting Data */
|
||||
Item *AddItem();
|
||||
int SetString(const char *tag, const wchar_t *data);
|
||||
int SetKeyValueByIndex(size_t index, const char *key, const wchar_t *data);
|
||||
int SetFlags(uint32_t flags, uint32_t mask);
|
||||
|
||||
/* Removing Data */
|
||||
void Clear();
|
||||
int RemoveItem(size_t index);
|
||||
int RemoveItem(const char *tag);
|
||||
|
||||
/* Serializing */
|
||||
size_t EncodeSize();
|
||||
int Encode(void *data, size_t len);
|
||||
|
||||
|
||||
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. */
|
||||
|
||||
protected:
|
||||
int SetItemData(APEv2::Item *item, const wchar_t *data);
|
||||
|
||||
private: /* data */
|
||||
std::vector<APEv2::Item*> items;
|
||||
uint32_t flags;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
22
Src/apev2/util.h
Normal file
22
Src/apev2/util.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NULLSOFT_APEV2_UTIL_H
|
||||
#define NULLSOFT_APEV2_UTIL_H
|
||||
|
||||
#if defined(BIG_ENDIAN)
|
||||
#define ATON16(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
|
||||
(((uint16_t)(A) & 0x00ff) << 8))
|
||||
#define ATON32(A) ((((uint32_t)(A) & 0xff000000) >> 25) | \
|
||||
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
|
||||
(((uint32_t)(A) & 0x0000ff00) << 8) | \
|
||||
(((uint32_t)(A) & 0x000000ff) << 24))
|
||||
|
||||
#elif defined(LITTLE_ENDIAN) || defined(_M_IX86) || defined(_M_X64) || defined(_WIN64)
|
||||
#define ATON16(A) (A)
|
||||
#define ATON32(A) (A)
|
||||
#else
|
||||
#error neither BIG_ENDIAN nor LITTLE_ENDIAN defined!
|
||||
#endif
|
||||
|
||||
#define NTOA32(N) ATON32(N)
|
||||
#define NTOA16(N) ATON16(N)
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user