Split out sized buffer type and added tests. Modified reader to better utilise sized buffer. Debugged and working at least as well as previous.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,7 +3,7 @@
|
|||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
NavmeshList/Skyrim.esm
|
*.esm
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
|
|||||||
@@ -409,7 +409,8 @@
|
|||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>../ESPReader</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SizedBuffer;..\ESPReader</AdditionalIncludeDirectories>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@@ -427,7 +428,7 @@
|
|||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>../ESPReader</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SizedBuffer;..\ESPReader</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ESPReader", "espReader\espR
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavmeshList", "NavmeshList\NavmeshList.vcxproj", "{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavmeshList", "NavmeshList\NavmeshList.vcxproj", "{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mph_gen", "mph_gen\mph_gen.vcxproj", "{385E9D8D-F3F4-4FD4-B182-D06F877CB090}"
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libz-static", "zlib-win-build\build-VS2022\libz-static\libz-static.vcxproj", "{B56D17BC-072B-42F3-844A-870A07AFBAAA}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libz-static", "zlib-win-build\build-VS2022\libz-static\libz-static.vcxproj", "{B56D17BC-072B-42F3-844A-870A07AFBAAA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F2B93142-BC5A-4D28-8AAA-24D52FA59514}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F2B93142-BC5A-4D28-8AAA-24D52FA59514}"
|
||||||
@@ -16,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SizedBuffer", "SizedBuffer\SizedBuffer.vcxproj", "{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Itanium = Debug|Itanium
|
Debug|Itanium = Debug|Itanium
|
||||||
@@ -65,24 +65,6 @@ Global
|
|||||||
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
||||||
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|Itanium.ActiveCfg = Debug|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|Itanium.Build.0 = Debug|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|Itanium.ActiveCfg = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|Itanium.Build.0 = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x64.Build.0 = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x86.Build.0 = Release|Win32
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|Itanium.Build.0 = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
|
||||||
{385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
|
||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.ActiveCfg = Debug|x64
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.Build.0 = Debug|x64
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.Build.0 = Debug|x64
|
||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|x64.ActiveCfg = Debug|x64
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
@@ -101,6 +83,24 @@ Global
|
|||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
||||||
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|Itanium.Build.0 = Debug|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|Itanium.Build.0 = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x64.Build.0 = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|Itanium.Build.0 = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
|
||||||
|
{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
81
SizedBuffer/SizedBuffer.h
Normal file
81
SizedBuffer/SizedBuffer.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Guards for C++ usage
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* A sized buffer abstraction.
|
||||||
|
*
|
||||||
|
* Functions that return int's will return 0 on success and nonzero otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct sized_buf SizedBuf;
|
||||||
|
|
||||||
|
struct sized_buf
|
||||||
|
{
|
||||||
|
char *data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns 0 if the given buffer has at least size bytes available
|
||||||
|
inline int sb_check(const SizedBuf sb, const size_t size)
|
||||||
|
{
|
||||||
|
return !(sb.size >= size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves the buffer size bytes forward, makes no checks
|
||||||
|
inline void sb_update(SizedBuf *const sb, const size_t size)
|
||||||
|
{
|
||||||
|
sb->data += size;
|
||||||
|
sb->size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies size bytes of data from the source to the buffer
|
||||||
|
inline int sb_copyin(SizedBuf *const sb, const char *const source, const size_t size)
|
||||||
|
{
|
||||||
|
int ret = sb_check(*sb, size);
|
||||||
|
if (!ret) {
|
||||||
|
memcpy(sb->data, source, size);
|
||||||
|
sb_update(sb, size);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Recasts" size bytes of memory and returns a pointer to said memory in out
|
||||||
|
inline int sb_recast(SizedBuf *const sb, const size_t size, const void **const out)
|
||||||
|
{
|
||||||
|
int ret = sb_check(*sb, size);
|
||||||
|
if (!ret) {
|
||||||
|
*out = sb->data;
|
||||||
|
sb_update(sb, size);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Recasts" size bytes of memory without actually consuming the buffer
|
||||||
|
inline int sb_peek(const SizedBuf sb, const size_t size, const void **const out)
|
||||||
|
{
|
||||||
|
*out = sb.data;
|
||||||
|
return sb_check(sb, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a pointer just after the end of the sized buffer
|
||||||
|
inline char *sb_end(const SizedBuf sb)
|
||||||
|
{
|
||||||
|
return sb.data + sb.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool sb_empty(const SizedBuf sb)
|
||||||
|
{
|
||||||
|
return sb.size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End C++ guard
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
138
SizedBuffer/SizedBuffer.vcxproj
Normal file
138
SizedBuffer/SizedBuffer.vcxproj
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{cb1c8f66-5b90-4de7-890b-f6430daaf25f}</ProjectGuid>
|
||||||
|
<RootNamespace>SizedBuffer</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="SizedBuffer.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="SizedBufferTest.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
27
SizedBuffer/SizedBuffer.vcxproj.filters
Normal file
27
SizedBuffer/SizedBuffer.vcxproj.filters
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="SizedBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="SizedBufferTest.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
147
SizedBuffer/SizedBufferTest.c
Normal file
147
SizedBuffer/SizedBufferTest.c
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include "SizedBuffer.h"
|
||||||
|
|
||||||
|
#undef NDBEUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
|
void test_sb_check(void) {
|
||||||
|
SizedBuf t = { .size = 0 };
|
||||||
|
assert(sb_check(t, 0) == 0);
|
||||||
|
assert(sb_check(t, 1) != 0);
|
||||||
|
assert(sb_check(t, SIZE_MAX) != 0);
|
||||||
|
|
||||||
|
t.size = 100;
|
||||||
|
assert(sb_check(t, 99) == 0);
|
||||||
|
assert(sb_check(t, 100) == 0);
|
||||||
|
assert(sb_check(t, 101) != 0);
|
||||||
|
assert(sb_check(t, SIZE_MAX) != 0);
|
||||||
|
|
||||||
|
t.size = SIZE_MAX;
|
||||||
|
assert(sb_check(t, 0) == 0);
|
||||||
|
assert(sb_check(t, 1) == 0);
|
||||||
|
assert(sb_check(t, SIZE_MAX) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_update(void) {
|
||||||
|
SizedBuf t;
|
||||||
|
|
||||||
|
t = (SizedBuf){ .data = 0, .size = 0 };
|
||||||
|
sb_update(&t, 0);
|
||||||
|
assert(t.data == 0 && t.size == 0);
|
||||||
|
|
||||||
|
t.size = 100;
|
||||||
|
sb_update(&t, 25);
|
||||||
|
assert(t.data == (void *)25 && t.size == 75);
|
||||||
|
|
||||||
|
sb_update(&t, 75);
|
||||||
|
assert(t.data == (void *)100 && t.size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_copyin(void) {
|
||||||
|
#define TEST_SIZE 128
|
||||||
|
char buf[TEST_SIZE] = { 0 };
|
||||||
|
SizedBuf sb = { .data = buf, .size = TEST_SIZE };
|
||||||
|
|
||||||
|
char test_buf[TEST_SIZE] = { 0 };
|
||||||
|
memset(test_buf, 0xff, TEST_SIZE);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
assert(sb_copyin(&sb, NULL, SIZE_MAX) != 0);
|
||||||
|
assert(sb_copyin(&sb, NULL, TEST_SIZE + 1) != 0);
|
||||||
|
assert(sb_copyin(&sb, test_buf, TEST_SIZE) == 0);
|
||||||
|
assert(memcmp(buf, test_buf, TEST_SIZE) == 0);
|
||||||
|
assert(sb.size == 0);
|
||||||
|
assert(sb.data == buf + TEST_SIZE);
|
||||||
|
#undef TEST_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_recast(void) {
|
||||||
|
#define TEST_SIZE 33
|
||||||
|
char *const start = NULL;
|
||||||
|
SizedBuf t = { .data = start, .size = TEST_SIZE };
|
||||||
|
void *out = NULL;
|
||||||
|
|
||||||
|
assert(sb_recast(&t, SIZE_MAX, &out) != 0);
|
||||||
|
assert(sb_recast(&t, TEST_SIZE + 1, &out) != 0);
|
||||||
|
assert(sb_recast(&t, 13, &out) == 0);
|
||||||
|
assert(t.data == start + 13);
|
||||||
|
assert(t.size == TEST_SIZE - 13);
|
||||||
|
assert(out == NULL);
|
||||||
|
assert(sb_recast(&t, 8, &out) == 0);
|
||||||
|
assert(t.data == (void *)(13 + 8));
|
||||||
|
assert(t.size == TEST_SIZE - 13 - 8);
|
||||||
|
assert(out == (void *)13);
|
||||||
|
#undef TEST_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_end(void) {
|
||||||
|
SizedBuf sb = { .data = NULL, .size = SIZE_MAX };
|
||||||
|
assert(sb_end(sb) == (void *)SIZE_MAX);
|
||||||
|
|
||||||
|
sb = (SizedBuf){ .data = (void *)0xdeadbeefull, .size = 0x1337 };
|
||||||
|
assert(sb_end(sb) == (void *)(0xdeadbeefull + 0x1337ull));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_empty(void) {
|
||||||
|
SizedBuf sb = { .data = NULL, .size = SIZE_MAX };
|
||||||
|
assert(!sb_empty(sb));
|
||||||
|
sb.size = 1;
|
||||||
|
assert(!sb_empty(sb));
|
||||||
|
sb.size = 0;
|
||||||
|
assert(sb_empty(sb));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sb_peek(void) {
|
||||||
|
#define TEST_SIZE 128
|
||||||
|
SizedBuf sb = { .data = NULL, .size = TEST_SIZE };
|
||||||
|
void *test = (void *)0xdeadbeefull;
|
||||||
|
assert(sb_peek(sb, SIZE_MAX, &test) != 0);
|
||||||
|
assert(sb_peek(sb, TEST_SIZE + 1, &test) != 0);
|
||||||
|
assert(sb_peek(sb, TEST_SIZE, &test) == 0);
|
||||||
|
assert(sb.data == test);
|
||||||
|
assert(sb.size == TEST_SIZE);
|
||||||
|
test = (void *)'FOUR';
|
||||||
|
assert(sb_peek(sb, 0, &test) == 0);
|
||||||
|
assert(sb.data == test);
|
||||||
|
assert(sb.size == TEST_SIZE);
|
||||||
|
#undef TEST_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*test)(void);
|
||||||
|
const char *const name;
|
||||||
|
} Test;
|
||||||
|
|
||||||
|
#define TEST(x) { x, #x }
|
||||||
|
Test tests[] = {
|
||||||
|
TEST(test_sb_check),
|
||||||
|
TEST(test_sb_update),
|
||||||
|
TEST(test_sb_copyin),
|
||||||
|
TEST(test_sb_recast),
|
||||||
|
TEST(test_sb_end),
|
||||||
|
TEST(test_sb_empty),
|
||||||
|
TEST(test_sb_peek),
|
||||||
|
};
|
||||||
|
#undef TEST
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
#ifdef DISABLE_STDOUT
|
||||||
|
fclose(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// run all tests
|
||||||
|
size_t num_tests = sizeof(tests) / sizeof(tests[0]);
|
||||||
|
for (size_t i = 0; i < num_tests; i++) {
|
||||||
|
tests[i].test();
|
||||||
|
fprintf(stderr, "Test passed: %s\n", tests[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "All tests passed.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -24,10 +24,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
|
|
||||||
#include "msh.h"
|
#include "msh.h"
|
||||||
|
#include "SizedBuffer.h"
|
||||||
|
|
||||||
// Guards for C++ usage
|
// Guards for C++ usage
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -76,6 +79,7 @@ extern "C" {
|
|||||||
typedef struct field Field;
|
typedef struct field Field;
|
||||||
typedef struct meta_node MetaNode;
|
typedef struct meta_node MetaNode;
|
||||||
typedef struct meta_tree MetaTree;
|
typedef struct meta_tree MetaTree;
|
||||||
|
typedef struct esp_stats ESPStats;
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -113,11 +117,6 @@ extern "C" {
|
|||||||
char _pad[4];
|
char _pad[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sized_buf {
|
|
||||||
char *data;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// === ENUMS ===
|
// === ENUMS ===
|
||||||
//
|
//
|
||||||
@@ -334,13 +333,6 @@ extern "C" {
|
|||||||
return rth2rt[uint32_t_msh(type, RT_HASH_BITS, RT_HASH_SEED)];
|
return rth2rt[uint32_t_msh(type, RT_HASH_BITS, RT_HASH_SEED)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates a sized_buf after using `size` bytes
|
|
||||||
inline void sized_buf_update(struct sized_buf *sb, size_t size) {
|
|
||||||
assert(sb->size >= size);
|
|
||||||
sb->data += size;
|
|
||||||
sb->size -= size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* `espr_walk` walks through the tree structure of the esp/esm binary
|
/* `espr_walk` walks through the tree structure of the esp/esm binary
|
||||||
* data starting at `data` of `size` bytes.
|
* data starting at `data` of `size` bytes.
|
||||||
*
|
*
|
||||||
@@ -351,7 +343,7 @@ extern "C" {
|
|||||||
* increasing in terms of memory location within the buffer.
|
* increasing in terms of memory location within the buffer.
|
||||||
*/
|
*/
|
||||||
void espr_walk(
|
void espr_walk(
|
||||||
struct sized_buf esp,
|
SizedBuf esp,
|
||||||
struct walker_callbacks cb,
|
struct walker_callbacks cb,
|
||||||
void *from_parent
|
void *from_parent
|
||||||
);
|
);
|
||||||
@@ -359,13 +351,13 @@ extern "C" {
|
|||||||
/* `espr_print` prints the header of every group and record in the given
|
/* `espr_print` prints the header of every group and record in the given
|
||||||
* esp/esm binary data.
|
* esp/esm binary data.
|
||||||
*/
|
*/
|
||||||
void espr_print(struct sized_buf esp);
|
void espr_print(SizedBuf esp);
|
||||||
|
|
||||||
/* Calculates the number of groups and records in the esp/esm file and
|
/* Calculates the number of groups and records in the esp/esm file and
|
||||||
* the size of the esp/esm if all of the compressed records were
|
* the size of the esp/esm if all of the compressed records were
|
||||||
* decompressed.
|
* decompressed.
|
||||||
*/
|
*/
|
||||||
struct esp_stats espr_stats(struct sized_buf esp);
|
struct esp_stats espr_stats(SizedBuf esp);
|
||||||
|
|
||||||
// Calculates the number of formid's in an esm/esp from the stats
|
// Calculates the number of formid's in an esm/esp from the stats
|
||||||
inline uint32_t espr_formid_count(struct esp_stats stats) {
|
inline uint32_t espr_formid_count(struct esp_stats stats) {
|
||||||
@@ -387,10 +379,7 @@ extern "C" {
|
|||||||
* as it does so. buf_size should be the value returned from
|
* as it does so. buf_size should be the value returned from
|
||||||
* `espr_decompressed_size`, and `buf` should be at least of that size.
|
* `espr_decompressed_size`, and `buf` should be at least of that size.
|
||||||
*/
|
*/
|
||||||
void espr_decompress(
|
void espr_decompress(SizedBuf esp, SizedBuf decom);
|
||||||
struct sized_buf esp,
|
|
||||||
struct sized_buf decom
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Constructs a MetaNode tree in `tree` over the esp/esm data in `in`.
|
/* Constructs a MetaNode tree in `tree` over the esp/esm data in `in`.
|
||||||
*
|
*
|
||||||
@@ -398,13 +387,13 @@ extern "C" {
|
|||||||
* data, and also allow for modifications that add, remove, or change
|
* data, and also allow for modifications that add, remove, or change
|
||||||
* the size of groups/records/fields.
|
* the size of groups/records/fields.
|
||||||
*/
|
*/
|
||||||
MetaTree espr_create_tree(struct sized_buf in, struct sized_buf tree);
|
MetaTree espr_create_tree(SizedBuf in, SizedBuf tree);
|
||||||
|
|
||||||
void espr_meta_walk(MetaTree tree, struct meta_callbacks cb);
|
void espr_meta_walk(MetaTree tree, struct meta_callbacks cb);
|
||||||
|
|
||||||
void espr_meta_node_walk(MetaNode *m, struct meta_callbacks cb);
|
void espr_meta_node_walk(MetaNode *m, struct meta_callbacks cb);
|
||||||
|
|
||||||
void espr_serialize(MetaTree tree, struct sized_buf out);
|
void espr_serialize(MetaTree tree, SizedBuf out);
|
||||||
|
|
||||||
// End C++ guard
|
// End C++ guard
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -38,13 +38,9 @@ const int year_offset = 9;
|
|||||||
void asserts(void);
|
void asserts(void);
|
||||||
|
|
||||||
// Tree walkers
|
// Tree walkers
|
||||||
char *walk_concat(
|
void walk_concat(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
|
||||||
struct sized_buf tree,
|
void walk_group(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
|
||||||
struct walker_callbacks cb,
|
void walk_record(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
|
||||||
void *from_parent
|
|
||||||
);
|
|
||||||
char *walk_group(char *data, struct walker_callbacks cb, void *from_parent);
|
|
||||||
char *walk_record(char *data, struct walker_callbacks cb, void *from_parent);
|
|
||||||
|
|
||||||
// Header printers
|
// Header printers
|
||||||
void print_group_header(Group *header);
|
void print_group_header(Group *header);
|
||||||
@@ -118,21 +114,23 @@ void asserts(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void espr_walk(
|
void espr_walk(
|
||||||
struct sized_buf esp,
|
SizedBuf esp,
|
||||||
struct walker_callbacks cb,
|
struct walker_callbacks cb,
|
||||||
void *from_parent
|
void *from_parent
|
||||||
) {
|
) {
|
||||||
// check assertions that cannot be checked at compile time
|
// check assertions that cannot be checked at compile time
|
||||||
asserts();
|
asserts();
|
||||||
|
|
||||||
char *data_start = esp.data;
|
|
||||||
|
|
||||||
// check that we are at the start of the file
|
// check that we are at the start of the file
|
||||||
const Type4 type = *(const Type4 *)esp.data;
|
{
|
||||||
assert(type.uint == rt[TES4]);
|
Type4 *type = NULL;
|
||||||
|
int err = sb_peek(esp, sizeof(Type4), &type);
|
||||||
|
assert(err == 0);
|
||||||
|
assert(type->uint == rt[TES4]);
|
||||||
|
}
|
||||||
|
|
||||||
esp.data = walk_concat(esp, cb, from_parent);
|
walk_concat(&esp, cb, from_parent);
|
||||||
assert(esp.data == data_start + esp.size);
|
assert(sb_empty(esp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unknown data will be some concatenation of groups and records.
|
/* Unknown data will be some concatenation of groups and records.
|
||||||
@@ -140,27 +138,22 @@ void espr_walk(
|
|||||||
* `walk_concat` will call the appropriate walking function
|
* `walk_concat` will call the appropriate walking function
|
||||||
* for each segment of unknown data in this concatenation.
|
* for each segment of unknown data in this concatenation.
|
||||||
*/
|
*/
|
||||||
char *walk_concat(
|
void walk_concat(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
|
||||||
struct sized_buf tree,
|
{
|
||||||
struct walker_callbacks cb,
|
while (!sb_empty(*tree)) {
|
||||||
void *from_parent
|
const Type4 *type = NULL;
|
||||||
) {
|
int err = sb_peek(*tree, sizeof(Type4), &type);
|
||||||
const char *end = tree.data + tree.size;
|
assert(err == 0);
|
||||||
while (tree.data != end) {
|
|
||||||
assert(tree.data < end);
|
|
||||||
|
|
||||||
const Type4 *type = (Type4 *)tree.data;
|
|
||||||
|
|
||||||
// check valid type
|
// check valid type
|
||||||
assert(rt[rt_hash(type->uint)] == type->uint);
|
assert(rt[rt_hash(type->uint)] == type->uint);
|
||||||
|
|
||||||
// only need to distinguish between groups and records
|
// only need to distinguish between groups and records
|
||||||
if (type->uint == rt[GRUP])
|
if (type->uint == rt[GRUP])
|
||||||
tree.data = walk_group(tree.data, cb, from_parent);
|
walk_group(tree, cb, from_parent);
|
||||||
else
|
else
|
||||||
tree.data = walk_record(tree.data, cb, from_parent);
|
walk_record(tree, cb, from_parent);
|
||||||
}
|
}
|
||||||
return tree.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Walk a group record. Group records are containers for any other type of
|
/* Walk a group record. Group records are containers for any other type of
|
||||||
@@ -169,18 +162,25 @@ char *walk_concat(
|
|||||||
* This function will also call `cb` with the node constructed from this group
|
* This function will also call `cb` with the node constructed from this group
|
||||||
* record.
|
* record.
|
||||||
*/
|
*/
|
||||||
char *walk_group(char *data, struct walker_callbacks cb, void *from_parent)
|
void walk_group(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
|
||||||
{
|
{
|
||||||
Group *const header = (Group *const)data;
|
Group *header = NULL;
|
||||||
|
{
|
||||||
|
int err = sb_peek(*tree, sizeof(Group), &header);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// The size in the group header includes the size of the header
|
SizedBuf group = { .size = header->size };
|
||||||
char *data_start = data + sizeof(Group);
|
{
|
||||||
char *data_end = data + header->size;
|
int err = sb_recast(tree, group.size, &group.data);
|
||||||
size_t data_size = data_end - data_start;
|
assert(err == 0);
|
||||||
|
err = sb_recast(&group, sizeof(Group), &header);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
Node n = {
|
Node n = {
|
||||||
.header.group = header,
|
.header.group = header,
|
||||||
.data = data_start,
|
.data = group.data,
|
||||||
.type = NT_GROUP
|
.type = NT_GROUP
|
||||||
};
|
};
|
||||||
void *carry = NULL;
|
void *carry = NULL;
|
||||||
@@ -191,27 +191,30 @@ char *walk_group(char *data, struct walker_callbacks cb, void *from_parent)
|
|||||||
cb.pre(n, cb.data, &carry, from_parent, &to_children);
|
cb.pre(n, cb.data, &carry, from_parent, &to_children);
|
||||||
|
|
||||||
// Walk through the concatenation of data inside the group.
|
// Walk through the concatenation of data inside the group.
|
||||||
struct sized_buf tree = { data_start, data_size };
|
walk_concat(&group, cb, to_children);
|
||||||
data = walk_concat(tree, cb, to_children);
|
assert(sb_empty(group));
|
||||||
assert(data == data_end);
|
|
||||||
|
|
||||||
// Post-walk callback
|
// Post-walk callback
|
||||||
if (cb.post)
|
if (cb.post)
|
||||||
cb.post(n, cb.data, carry);
|
cb.post(n, cb.data, carry);
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *walk_record(char *data, struct walker_callbacks cb, void *from_parent)
|
void walk_record(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
|
||||||
{
|
{
|
||||||
Record *header = (Record *)data;
|
Record *header = NULL;
|
||||||
assert(header->type.uint != rt[GRUP]);
|
char *data = NULL;
|
||||||
|
{
|
||||||
|
int err = sb_recast(tree, sizeof(Record), &header);
|
||||||
|
assert(err == 0);
|
||||||
|
err = sb_recast(tree, header->size, &data);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
char *data_start = data + sizeof(Record);
|
assert(header->type.uint != rt[GRUP]);
|
||||||
|
|
||||||
Node n = {
|
Node n = {
|
||||||
.header.record = header,
|
.header.record = header,
|
||||||
.data = data_start,
|
.data = data,
|
||||||
.type = NT_RECORD
|
.type = NT_RECORD
|
||||||
};
|
};
|
||||||
void *carry = NULL;
|
void *carry = NULL;
|
||||||
@@ -226,17 +229,12 @@ char *walk_record(char *data, struct walker_callbacks cb, void *from_parent)
|
|||||||
if (cb.pre)
|
if (cb.pre)
|
||||||
cb.pre(n, cb.data, &carry, from_parent, &to_children);
|
cb.pre(n, cb.data, &carry, from_parent, &to_children);
|
||||||
|
|
||||||
// Update data ptr based on record size.
|
|
||||||
data += sizeof(Record) + header->size;
|
|
||||||
|
|
||||||
// Post-walk callback
|
// Post-walk callback
|
||||||
if (cb.post)
|
if (cb.post)
|
||||||
cb.post(n, cb.data, carry);
|
cb.post(n, cb.data, carry);
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void espr_print(struct sized_buf esp)
|
void espr_print(SizedBuf esp)
|
||||||
{
|
{
|
||||||
struct walker_callbacks cb = { .pre = print_cb };
|
struct walker_callbacks cb = { .pre = print_cb };
|
||||||
espr_walk(esp, cb, NULL);
|
espr_walk(esp, cb, NULL);
|
||||||
@@ -265,9 +263,9 @@ void print_cb(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct esp_stats espr_stats(struct sized_buf esp)
|
ESPStats espr_stats(SizedBuf esp)
|
||||||
{
|
{
|
||||||
struct esp_stats stats = { 0 };
|
ESPStats stats = { 0 };
|
||||||
struct walker_callbacks cb = { .pre = stats_cb, .data = &stats };
|
struct walker_callbacks cb = { .pre = stats_cb, .data = &stats };
|
||||||
espr_walk(esp, cb, NULL);
|
espr_walk(esp, cb, NULL);
|
||||||
return stats;
|
return stats;
|
||||||
@@ -310,7 +308,7 @@ void stats_cb(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void espr_decompress(struct sized_buf esp, struct sized_buf decom)
|
void espr_decompress(SizedBuf esp, SizedBuf decom)
|
||||||
{
|
{
|
||||||
struct walker_callbacks cb = {
|
struct walker_callbacks cb = {
|
||||||
.pre = decompress_pre,
|
.pre = decompress_pre,
|
||||||
@@ -334,7 +332,7 @@ void espr_decompress(struct sized_buf esp, struct sized_buf decom)
|
|||||||
*/
|
*/
|
||||||
void decompress_pre(
|
void decompress_pre(
|
||||||
Node n,
|
Node n,
|
||||||
void *decom_ptr,
|
void *out_buf,
|
||||||
void **carry_out,
|
void **carry_out,
|
||||||
void *from_parent,
|
void *from_parent,
|
||||||
void **to_children
|
void **to_children
|
||||||
@@ -342,28 +340,32 @@ void decompress_pre(
|
|||||||
(void)from_parent;
|
(void)from_parent;
|
||||||
(void)to_children;
|
(void)to_children;
|
||||||
|
|
||||||
struct sized_buf *d = decom_ptr;
|
SizedBuf *d = out_buf;
|
||||||
|
|
||||||
switch (n.type) {
|
switch (n.type) {
|
||||||
case NT_RECORD:
|
case NT_RECORD:
|
||||||
// compressed record
|
// compressed record
|
||||||
if (n.header.record->flags & COMPRESSED_FLAG) {
|
if (n.header.record->flags & COMPRESSED_FLAG) {
|
||||||
|
Record *copied_header = NULL;
|
||||||
|
{
|
||||||
|
// Acces for copied header
|
||||||
|
int err = sb_peek(*d, sizeof(Record), &copied_header);
|
||||||
|
assert(err == 0);
|
||||||
// copy header
|
// copy header
|
||||||
memcpy(d->data, n.header.record, sizeof(Record));
|
err = sb_copyin(d, (char *)n.header.record, sizeof(Record));
|
||||||
|
assert(err == 0);
|
||||||
// copied header reference
|
}
|
||||||
Record *header = (Record *)d->data;
|
|
||||||
|
|
||||||
// update decom struct
|
|
||||||
sized_buf_update(d, sizeof(Record));
|
|
||||||
|
|
||||||
// decompress directly into buffer
|
// decompress directly into buffer
|
||||||
// first 4 bytes are the decompressed size
|
// first 4 bytes are the decompressed size
|
||||||
const uint32_t dc_size = *((uint32_t *)n.data);
|
const uint32_t dc_size = *((uint32_t *)n.data);
|
||||||
uint32_t to_copy = dc_size;
|
uint32_t to_copy = dc_size;
|
||||||
uint32_t cur_size =
|
uint32_t cur_size = n.header.record->size - sizeof(uint32_t);
|
||||||
n.header.record->size - sizeof(uint32_t);
|
|
||||||
char *data_start = n.data + sizeof(uint32_t);
|
char *data_start = n.data + sizeof(uint32_t);
|
||||||
|
|
||||||
|
// check that we have enough space in the buffer
|
||||||
|
sb_check(*d, dc_size);
|
||||||
|
|
||||||
int ret = uncompress(
|
int ret = uncompress(
|
||||||
(Bytef *)d->data,
|
(Bytef *)d->data,
|
||||||
(uLongf *)&to_copy,
|
(uLongf *)&to_copy,
|
||||||
@@ -373,32 +375,27 @@ void decompress_pre(
|
|||||||
assert(ret == Z_OK);
|
assert(ret == Z_OK);
|
||||||
assert(to_copy == dc_size);
|
assert(to_copy == dc_size);
|
||||||
|
|
||||||
// update decom struct
|
// update the buffer
|
||||||
sized_buf_update(d, dc_size);
|
sb_update(d, dc_size);
|
||||||
|
|
||||||
// update header data size
|
// update header data size
|
||||||
header->size = dc_size;
|
copied_header->size = dc_size;
|
||||||
|
|
||||||
// unset compressed flag
|
// unset compressed flag
|
||||||
header->flags &= ~COMPRESSED_FLAG;
|
copied_header->flags &= ~COMPRESSED_FLAG;
|
||||||
} else {
|
} else {
|
||||||
// copy record
|
// copy record
|
||||||
size_t record_size = sizeof(Record) + n.header.record->size;
|
size_t record_size = sizeof(Record)
|
||||||
memcpy(d->data, n.header.record, record_size);
|
+ n.header.record->size;
|
||||||
|
sb_copyin(d, (char *)n.header.record, record_size);
|
||||||
// update decom
|
|
||||||
sized_buf_update(d, record_size);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NT_GROUP:
|
case NT_GROUP:
|
||||||
// copy header, contents will be copied while walking
|
|
||||||
memcpy(d->data, n.header.group, sizeof(Group));
|
|
||||||
|
|
||||||
// save copied header location for post-walk group size recalc
|
// save copied header location for post-walk group size recalc
|
||||||
*carry_out = (void *)d->data;
|
*carry_out = (void *)d->data;
|
||||||
|
|
||||||
// update decom
|
// copy header, contents will be copied while walking
|
||||||
sized_buf_update(d, sizeof(Group));
|
sb_copyin(d, (char *)n.header.group, sizeof(Group));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -412,9 +409,9 @@ void decompress_pre(
|
|||||||
* based on the difference between the current destination pointer and the
|
* based on the difference between the current destination pointer and the
|
||||||
* group header pointer.
|
* group header pointer.
|
||||||
*/
|
*/
|
||||||
void decompress_post(Node n, void *decom_ptr, void *carry_in)
|
void decompress_post(Node n, void *out, void *carry_in)
|
||||||
{
|
{
|
||||||
struct sized_buf *d = decom_ptr;
|
SizedBuf *d = out;
|
||||||
|
|
||||||
// only need to handle group resize
|
// only need to handle group resize
|
||||||
if (n.type == NT_GROUP) {
|
if (n.type == NT_GROUP) {
|
||||||
@@ -630,15 +627,16 @@ Timestamp convert_ts(uint16_t ts)
|
|||||||
return (Timestamp) { year, month, day };
|
return (Timestamp) { year, month, day };
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaTree espr_create_tree(struct sized_buf in, struct sized_buf tree)
|
MetaTree espr_create_tree(SizedBuf in, SizedBuf tree)
|
||||||
{
|
{
|
||||||
// create root node
|
// create root node
|
||||||
MetaNode *root = (MetaNode *)tree.data;
|
MetaNode *root = NULL;
|
||||||
|
{
|
||||||
|
int err = sb_recast(&tree, sizeof(MetaNode), &root);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
*root = (MetaNode){ 0 };
|
*root = (MetaNode){ 0 };
|
||||||
|
|
||||||
// update tree
|
|
||||||
sized_buf_update(&tree, sizeof(MetaNode));
|
|
||||||
|
|
||||||
// walk
|
// walk
|
||||||
struct walker_callbacks cb = { .pre = create_tree_cb, .data = &tree };
|
struct walker_callbacks cb = { .pre = create_tree_cb, .data = &tree };
|
||||||
espr_walk(in, cb, root);
|
espr_walk(in, cb, root);
|
||||||
@@ -656,9 +654,12 @@ void create_tree_cb(
|
|||||||
(void)carry_out;
|
(void)carry_out;
|
||||||
|
|
||||||
// add new metanode to tree
|
// add new metanode to tree
|
||||||
struct sized_buf *tree = data;
|
SizedBuf *tree = data;
|
||||||
MetaNode *m = (MetaNode *)tree->data;
|
MetaNode *m = NULL;
|
||||||
sized_buf_update(tree, sizeof(MetaNode));
|
{
|
||||||
|
int err = sb_recast(tree, sizeof(MetaNode), &m);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// parent passes their MetaNode to children
|
// parent passes their MetaNode to children
|
||||||
MetaNode *p = from_parent;
|
MetaNode *p = from_parent;
|
||||||
@@ -692,13 +693,13 @@ void espr_meta_node_walk(MetaNode *m, struct meta_callbacks cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void espr_serialize(MetaTree tree, struct sized_buf out) {
|
void espr_serialize(MetaTree tree, SizedBuf out) {
|
||||||
struct meta_callbacks cb = { .pre = serialize_cb, .data = &out };
|
struct meta_callbacks cb = { .pre = serialize_cb, .data = &out };
|
||||||
espr_meta_walk(tree, cb);
|
espr_meta_walk(tree, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize_cb(MetaNode *m, void *data) {
|
void serialize_cb(MetaNode *m, void *data) {
|
||||||
struct sized_buf *out = data;
|
SizedBuf *out = data;
|
||||||
|
|
||||||
// exit on empty node
|
// exit on empty node
|
||||||
if (!m->n.data)
|
if (!m->n.data)
|
||||||
@@ -707,19 +708,25 @@ void serialize_cb(MetaNode *m, void *data) {
|
|||||||
switch (m->n.type) {
|
switch (m->n.type) {
|
||||||
case NT_GROUP:
|
case NT_GROUP:
|
||||||
// only serialize the header of groups
|
// only serialize the header of groups
|
||||||
assert(out->size >= sizeof(Group));
|
{
|
||||||
memcpy(out->data, m->n.header.group, sizeof(Group));
|
int err = sb_copyin(out, (char *)m->n.header.group, sizeof(Group));
|
||||||
sized_buf_update(out, sizeof(Group));
|
assert(err == 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NT_RECORD:
|
case NT_RECORD:
|
||||||
size_t data_size = m->n.header.record->size;
|
size_t data_size = m->n.header.record->size;
|
||||||
assert(out->size >= data_size + sizeof(Record));
|
char *header = (char *)m->n.header.record;
|
||||||
// serialize header and data separately as they may be
|
// serialize header and data separately as they may be
|
||||||
// discontiguous
|
// discontiguous
|
||||||
memcpy(out->data, m->n.header.record, sizeof(Record));
|
{
|
||||||
sized_buf_update(out, sizeof(Record));
|
int err = sb_copyin(out, header, sizeof(Record));
|
||||||
memcpy(out->data, m->n.data, data_size);
|
assert(err == 0);
|
||||||
sized_buf_update(out, data_size);
|
err = sb_copyin(out, m->n.data, data_size);
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||||
<AdditionalIncludeDirectories>..\zlib-win-build</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\zlib-win-build;..\SizedBuffer</AdditionalIncludeDirectories>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||||
<AdditionalIncludeDirectories>..\zlib-win-build</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\zlib-win-build;..\SizedBuffer</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>
|
<SubSystem>
|
||||||
@@ -148,6 +148,9 @@
|
|||||||
<ClCompile Include="Reader.c" />
|
<ClCompile Include="Reader.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SizedBuffer\SizedBuffer.vcxproj">
|
||||||
|
<Project>{cb1c8f66-5b90-4de7-890b-f6430daaf25f}</Project>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\zlib-win-build\build-VS2022\libz-static\libz-static.vcxproj">
|
<ProjectReference Include="..\zlib-win-build\build-VS2022\libz-static\libz-static.vcxproj">
|
||||||
<Project>{b56d17bc-072b-42f3-844a-870a07afbaaa}</Project>
|
<Project>{b56d17bc-072b-42f3-844a-870a07afbaaa}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
|||||||
Reference in New Issue
Block a user