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:
2022-09-09 14:59:56 +10:00
parent 392e226013
commit fa7025f774
10 changed files with 539 additions and 146 deletions

81
SizedBuffer/SizedBuffer.h Normal file
View 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

View 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>

View 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>

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