Skip to content

Commit

Permalink
Bindings: Add C binding for SC::Hashing (sc_hashing)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pagghiu committed Apr 4, 2024
1 parent 1112fd3 commit 91ac131
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 0 deletions.
31 changes: 31 additions & 0 deletions Bindings/c/CBindingsTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "../../Libraries/Testing/Testing.h"

// Includes
#include "sc_hashing/sc_hashing.h"

// Tests
extern "C" const char* sc_hashing_test();

namespace SC
{
struct CBindingsTest;
}

struct SC::CBindingsTest : public SC::TestCase
{
CBindingsTest(SC::TestReport& report) : TestCase(report, "CBindingsTest")
{
using namespace SC;
const char* res;
if (test_section("Hashing"))
{
res = sc_hashing_test();
recordExpectation(res ? StringView::fromNullTerminated(res, StringEncoding::Utf8) : "Hashing",
res == nullptr);
}
}
};
namespace SC
{
void runCBindingsTest(SC::TestReport& report) { CBindingsTest test(report); }
} // namespace SC
36 changes: 36 additions & 0 deletions Bindings/c/sc_hashing/sc_hashing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "sc_hashing.h"
#include "../../../Libraries/Hashing/Hashing.h"

SC::Hashing& sc_hashing_self(sc_hashing_t* hashing)
{
static_assert(sizeof(sc_hashing_t::opaque) >= sizeof(SC::Hashing), "sc_hashing_t::opaque size");
static_assert(alignof(sc_hashing_t) >= alignof(SC::Hashing), "sc_hashing_t::opaque alignment");
return *reinterpret_cast<SC::Hashing*>(hashing->opaque);
}

extern "C" bool sc_hashing_init(sc_hashing_t* hashing, sc_hashing_type type)
{
SC::Hashing& self = sc_hashing_self(hashing);
placementNew(self);
switch (type)
{
case SC_HASHING_TYPE_MD5: return self.setType(SC::Hashing::TypeMD5);
case SC_HASHING_TYPE_SHA1: return self.setType(SC::Hashing::TypeSHA1);
case SC_HASHING_TYPE_SHA256: return self.setType(SC::Hashing::TypeSHA256);
}
return false;
}

extern "C" void sc_hashing_close(sc_hashing_t* hashing) { sc_hashing_self(hashing).~Hashing(); }

extern "C" bool sc_hashing_add(sc_hashing_t* hashing, sc_hashing_span_t span)
{
return sc_hashing_self(hashing).add({reinterpret_cast<const uint8_t*>(span.data), span.length});
}

extern "C" bool sc_hashing_get(sc_hashing_t* hashing, sc_hashing_result_t* result)
{
static_assert(sizeof(sc_hashing_result_t) == sizeof(SC::Hashing::Result), "sc_hashing_result_t size");
static_assert(alignof(sc_hashing_result_t) == alignof(SC::Hashing::Result), "sc_hashing_result_t alignment");
return sc_hashing_self(hashing).getHash(*reinterpret_cast<SC::Hashing::Result*>(result));
}
92 changes: 92 additions & 0 deletions Bindings/c/sc_hashing/sc_hashing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Stefano Cristiano
// SPDX-License-Identifier: MIT
#if !defined(SANE_CPP_LIBRARIES_HASHING)
#define SANE_CPP_LIBRARIES_HASHING 1
#include <stdbool.h> // bool
#include <stddef.h> // size_t
#include <stdint.h> // uint64_t

//! @defgroup group_c_bindings C Bindings
//! @brief C bindings for all libraries

//! @defgroup group_sc_hashing sc_hashing
//! @ingroup group_c_bindings

//! @addtogroup group_sc_hashing
//! @brief C bindings for @ref library_hashing library
///
/// Sample usage:
/// @code{.c}
/// sc_hashing_t ctx;
/// bool res;
/// res = sc_hashing_init(&ctx, type);
/// res = sc_hashing_add(&ctx, (sc_hashing_span_t){.data = "test", .length = strlen("test")});
/// res = sc_hashing_add(&ctx, (sc_hashing_span_t){.data = "data", .length = strlen("data")});
/// sc_hashing_result_t result;
/// sc_hashing_get(&ctx, &result);
/// //... use result.hash
/// sc_hashing_close(&ctx);
/// @endcode

//! @{

#if _MSC_VER
#define SANE_CPP_NO_DISCARD
#else
#define SANE_CPP_NO_DISCARD __attribute__((warn_unused_result))
#endif
// clang-format off
#ifdef __cplusplus
extern "C"
{
#endif

/// @brief Type of hashing algorithm to use
typedef enum
{
SC_HASHING_TYPE_MD5, ///< Computes MD5 Hash
SC_HASHING_TYPE_SHA1, ///< Computes SHA1 Hash
SC_HASHING_TYPE_SHA256 ///< Computes SHA256 Hash
} sc_hashing_type;

/// @brief Opaque object holding state of hashing
typedef struct
{
uint64_t opaque[14];
} sc_hashing_t;

/// @brief Hash result
typedef struct
{
uint8_t hash[32]; ///< Contains the computed hash of length size
size_t size; ///< Length of the computed hash
} sc_hashing_result_t;

/// @brief Just a generic data span
typedef struct
{
const void* data; ///< Pointer to data
size_t length; ///< Length of the data (in bytes)
} sc_hashing_span_t;

/// @brief Initializes OS objects to compute hash (call sc_hashing_close when done).
SANE_CPP_NO_DISCARD bool sc_hashing_init(sc_hashing_t* hashing, sc_hashing_type type);

/// @brief Releases os resources allocated by sc_hashing_init.
void sc_hashing_close(sc_hashing_t* hashing);

/// @brief Add data to hash computation. Can be called multiple times to hash data iteratively.
SANE_CPP_NO_DISCARD bool sc_hashing_add(sc_hashing_t* hashing, sc_hashing_span_t span);

/// @brief Obtain the actual hash of data added through sc_hashing_add.
SANE_CPP_NO_DISCARD bool sc_hashing_get(sc_hashing_t* hashing, sc_hashing_result_t* result);

#ifdef __cplusplus
} // extern "C"
#endif
// clang-format on

#undef SANE_CPP_NO_DISCARD
//! @}

#endif // SANE_CPP_LIBRARIES_HASHING
79 changes: 79 additions & 0 deletions Bindings/c/sc_hashing/sc_hashing_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Stefano Cristiano
// SPDX-License-Identifier: MIT
#include "sc_hashing.h"
#include <assert.h>
#include <string.h>

#define SC_TEST_EXPECT(a) \
if (!(a)) \
{ \
assert(a); \
return #a; \
}

const char* sc_hashing_test_init(sc_hashing_type type, const uint8_t* expected, const size_t expected_size, bool update)
{
sc_hashing_t ctx;
SC_TEST_EXPECT(sc_hashing_init(&ctx, type));
SC_TEST_EXPECT(sc_hashing_add(&ctx, (sc_hashing_span_t){.data = "test", .length = strlen("test")}));
if (update)
{
SC_TEST_EXPECT(sc_hashing_add(&ctx, (sc_hashing_span_t){.data = "test", .length = strlen("test")}));
}
sc_hashing_result_t result;
SC_TEST_EXPECT(sc_hashing_get(&ctx, &result));
SC_TEST_EXPECT(result.size == expected_size);
SC_TEST_EXPECT(memcmp(result.hash, expected, result.size) == 0);
sc_hashing_close(&ctx);
return 0;
}

const char* sc_hashing_test(void)
{
const char* res;
const uint8_t md5_expected[] = {0x09, 0x8F, 0x6B, 0xCD, 0x46, 0x21, 0xD3, 0x73,
0xCA, 0xDE, 0x4E, 0x83, 0x26, 0x27, 0xB4, 0xF6};

res = sc_hashing_test_init(SC_HASHING_TYPE_MD5, md5_expected, sizeof(md5_expected), false);
if (res)
return res;

const uint8_t sha1_expected[] = {0xA9, 0x4A, 0x8F, 0xE5, 0xCC, 0xB1, 0x9B, 0xA6, 0x1C, 0x4C,
0x08, 0x73, 0xD3, 0x91, 0xE9, 0x87, 0x98, 0x2F, 0xBB, 0xD3};

res = sc_hashing_test_init(SC_HASHING_TYPE_SHA1, sha1_expected, sizeof(sha1_expected), false);
if (res)
return res;

const uint8_t sha256_expected[] = {0x9F, 0x86, 0xD0, 0x81, 0x88, 0x4C, 0x7D, 0x65, 0x9A, 0x2F, 0xEA,
0xA0, 0xC5, 0x5A, 0xD0, 0x15, 0xA3, 0xBF, 0x4F, 0x1B, 0x2B, 0x0B,
0x82, 0x2C, 0xD1, 0x5D, 0x6C, 0x15, 0xB0, 0xF0, 0x0A, 0x08};

res = sc_hashing_test_init(SC_HASHING_TYPE_SHA256, sha256_expected, sizeof(sha256_expected), false);
if (res)
return res;

const uint8_t md5_expected2[] = {0x05, 0xA6, 0x71, 0xC6, 0x6A, 0xEF, 0xEA, 0x12,
0x4C, 0xC0, 0x8B, 0x76, 0xEA, 0x6D, 0x30, 0xBB};

res = sc_hashing_test_init(SC_HASHING_TYPE_MD5, md5_expected2, sizeof(md5_expected2), true);
if (res)
return res;

const uint8_t sha1_expected2[] = {0x51, 0xAB, 0xB9, 0x63, 0x60, 0x78, 0xDE, 0xFB, 0xF8, 0x88,
0xD8, 0x45, 0x7A, 0x7C, 0x76, 0xF8, 0x5C, 0x8F, 0x11, 0x4C};

res = sc_hashing_test_init(SC_HASHING_TYPE_SHA1, sha1_expected2, sizeof(sha1_expected2), true);
if (res)
return res;

const uint8_t sha256_expected2[] = {0x37, 0x26, 0x83, 0x35, 0xDD, 0x69, 0x31, 0x04, 0x5B, 0xDC, 0xDF,
0x92, 0x62, 0x3F, 0xF8, 0x19, 0xA6, 0x42, 0x44, 0xB5, 0x3D, 0x0E,
0x74, 0x6D, 0x43, 0x87, 0x97, 0x34, 0x9D, 0x4D, 0xA5, 0x78};

res = sc_hashing_test_init(SC_HASHING_TYPE_SHA256, sha256_expected2, sizeof(sha256_expected2), true);
if (res)
return res;

return 0;
}
7 changes: 7 additions & 0 deletions Documentation/Libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ Library | Description
@subpage library_testing | @copybrief library_testing
@subpage library_threading | @copybrief library_threading
@subpage library_time | @copybrief library_time


Some libraries have [C Bindings](@ref group_c_bindings):

Library | Description
:-------------------------------------------|:-----------------------------------------------
@ref group_sc_hashing | @copybrief group_sc_hashing
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ Library
[Threading](https://pagghiu.github.io/SaneCppLibraries/library_threading.html) | 🟥 Atomic, thread, thread pool, mutex, condition variable
[Time](https://pagghiu.github.io/SaneCppLibraries/library_time.html) | 🟨 Time handling (relative, absolute, high resolution)

# C Bindings
Some Libraries have C bindings

Binding | Description
:---------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------
[sc_hashing](https://pagghiu.github.io/SaneCppLibraries/group__group__sc__hashing.html) | Bindings for the [Hashing](https://pagghiu.github.io/SaneCppLibraries/library_hashing.html) Library


# Building

Libraries can be used as is, adding a single file to your project and without needing any build system.
Expand Down
5 changes: 5 additions & 0 deletions Tests/SCTest/SCTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void runAsyncTest(SC::TestReport& report);
void runDebugVisualizersTest(TestReport& report);
void runSupportToolsTest(TestReport& report);

// Bindings
void runCBindingsTest(TestReport& report);
} // namespace SC

#include "../../Libraries/Containers/SmallVector.h"
Expand Down Expand Up @@ -205,5 +207,8 @@ int main(int argc, const char* argv[])
// Build tests
runBuildTest(report);

// C bindings tests
runCBindingsTest(report);

return report.getTestReturnCode();
}
3 changes: 3 additions & 0 deletions Tools/SC-build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ Result configure(Build::Definition& definition, Build::Parameters& parameters, S
}

// File overrides (order matters regarding to add / remove)
project.addDirectory("Bindings/c", "**.cpp"); // add all cpp support files for c bindings
project.addDirectory("Bindings/c", "**.c"); // add all c bindings
project.addDirectory("Bindings/c", "**.h"); // add all c bindings
project.addDirectory("Tools", "SC-*.cpp"); // add all tools
project.addDirectory("Tests/SCTest", "*.cpp"); // add all .cpp from SCTest directory
project.addDirectory("Tests/SCTest", "*.h"); // add all .h from SCTest directory
Expand Down

0 comments on commit 91ac131

Please sign in to comment.