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:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user