librlp

C library for the Recursive Length Prefix (RLP) serialization format
git clone git://git.defalsify.org/librlp.git
Log | Files | Refs | LICENSE

commit 66047667307d534d0586c30c322698f9aee2b797
parent b300a936f4160a780164f9efd1dc06b2d8136ce6
Author: nolash <dev@holbrook.no>
Date:   Sat, 10 Apr 2021 12:46:19 +0200

Add multi byte type add

Diffstat:
MMakefile | 6+++++-
Asrc/bits.c | 30++++++++++++++++++++++++++++++
Asrc/bits.h | 7+++++++
Asrc/endian.c | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/endian.h | 20++++++++++++++++++++
Msrc/rlp.c | 48++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/rlp.h | 4+++-
Atests/check_bits | 0
Atests/check_bits.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/check_rlp | 0
Mtests/check_rlp.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 342 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,10 +1,14 @@ build: gcc -I./src -g3 -c src/rlp.c -o src/rlp.o + gcc -I./src -g3 -c src/bits.c -o src/bits.o + gcc -I./src -g3 -c src/endian.c -o src/endian.o tests_build: build - gcc -I./src -g3 tests/check_rlp.c src/rlp.o -o tests/check_rlp -lcheck + gcc -I./src -g3 tests/check_rlp.c src/bits.o src/rlp.o src/endian.o -o tests/check_rlp -lcheck + gcc -I./src -g3 tests/check_bits.c src/bits.o src/rlp.o src/endian.o -o tests/check_bits -lcheck check: tests_build tests/check_rlp + tests/check_bits .PHONY test: check diff --git a/src/bits.c b/src/bits.c @@ -0,0 +1,30 @@ + +int intbits_le(int len, char *n) { + char ri = 0; + char ry = 0; + char i = 0; + + if (len == 0) { + return 0; + } + + for (int b = 0; b < len; b++) { + for (i = 0; i < 8; i++) { + if (((1 << i) & *(n + b)) > 0) { + ri = i + 1; + ry = b; + } + } + } + + if (ri == 0 && ry == 0) { + ri = 1; + } + + return ri + (ry * 8); +} + +int intbytes_le(int len, char *n) { + int r = intbits_le(len, n); + return (r - 1) / 8 + 1; +} diff --git a/src/bits.h b/src/bits.h @@ -0,0 +1,7 @@ +#ifndef LASH_BITS_H_ +#define LASH_BITS_H_ + +char intbits_le(int len, char *n); +char intbytes_le(int len, char *n); + +#endif diff --git a/src/endian.c b/src/endian.c @@ -0,0 +1,44 @@ +#include "endian.h" + +int is_le() { + short s = 42; + return *((unsigned char*)&s) == 42; +} + +// convert unsigned integer to little-endian representation +int to_endian(char direction, int l, void *n) { + union le un; + + if (l == 1 || is_le() == direction) { + return 0; + } + switch(l) { + case sizeof(long long): + un.ll = (long long*)n; + break; + case sizeof(int): + un.i = (int*)n; + break; + case sizeof(short): + un.s = (short*)n; + break; + default: + un.c = (char*)n; + } + flip_endian(l, &un); + + return 0; +} + +void flip_endian(int l, union le *n) { + int i; + char t; + char *ne; + + ne = (n->c)+(l-1); + for (i = 0; i < l/2; i++) { + t = *(n->c+i); + *((n->c)+i) = *(ne-i); + *(ne-i) = t; + } +} diff --git a/src/endian.h b/src/endian.h @@ -0,0 +1,20 @@ +#ifndef LASH_ENDIAN_H_ +#define LASH_ENDIAN_H_ + +#define CONVERT_BIGENDIAN 0x00 +#define CONVERT_LITTLEENDIAN 0x01 +#define CONVERT_PLATFORM is_le() + +union le { + short *s; + int *i; + long long *ll; + char *c; +}; + +int le(int l, void *n); +int is_le(); +int to_endian(char direction, int l, void *n); +void flip_endian(int l, union le *n); + +#endif // LASH_ENDIAN_H_ diff --git a/src/rlp.c b/src/rlp.c @@ -1,13 +1,57 @@ #include <stdint.h> #include <stdlib.h> +#include <string.h> #include "rlp.h" +#include "bits.h" +#include "endian.h" int rlp_init(rlp_encoder_t *encoder, int buffer_capacity) { - encoder->data_buf = malloc(buffer_capacity); + encoder->buf = malloc(buffer_capacity); encoder->depth = 0; + encoder->ptr = encoder->buf; } void rlp_free(rlp_encoder_t *encoder) { - free(encoder->data_buf); + free(encoder->buf); + encoder->ptr = NULL; } + + +int rlp_add(rlp_encoder_t *encoder, int len, char *data) { + char v; + int lenlen; + size_t r; + + r = (size_t)encoder->ptr; + + if (len == 0) { + *(encoder->ptr) = 0x80; + encoder->ptr++; + } else { + v = (char)*data; + if (len == 1 && v < 56) { + *(encoder->ptr) = v; + encoder->ptr++; + } else { + v = (char)*data; + if (len < 56) { + *(encoder->ptr) = len + 0x80; + encoder->ptr++; + memcpy(encoder->ptr, data, len); + encoder->ptr += len; + } else { + lenlen = intbytes_le(sizeof(int), (char*)&len); + *(encoder->ptr) = lenlen + 0xb7; + encoder->ptr++; + to_endian(CONVERT_BIGENDIAN, lenlen, &len); + memcpy(encoder->ptr, &len, lenlen); + to_endian(CONVERT_PLATFORM, lenlen, &len); + encoder->ptr+=lenlen; + memcpy(encoder->ptr, data, len); + encoder->ptr+=len; + } + } + } + return (int)(r - (size_t)encoder->ptr); +} diff --git a/src/rlp.h b/src/rlp.h @@ -8,7 +8,9 @@ typedef struct rlp_encoder { uint32_t depth; uint32_t list_buf[RLP_MAX_LIST_DEPTH]; - char *data_buf; + char *buf; + char *ptr; + } rlp_encoder_t; int rlp_init(rlp_encoder_t *encoder, int buffer_capacity); diff --git a/tests/check_bits b/tests/check_bits Binary files differ. diff --git a/tests/check_bits.c b/tests/check_bits.c @@ -0,0 +1,86 @@ +#include <check.h> +#include <stdlib.h> +#include <string.h> + +#include "bits.h" + +START_TEST(le_test) { + char v[10]; + int r; + + memset(v, 0, 10); + + r = intbits_le(0, NULL); + ck_assert_int_eq(r, 0); + + r = intbits_le(10, (char*)v); + ck_assert_int_eq(r, 1); + + v[0] = 2; + r = intbits_le(10, (char*)v); + ck_assert_int_eq(r, 2); + + v[1] = 2; + r = intbits_le(10, v); + ck_assert_int_eq(r, 10); + r = intbytes_le(10, v); + ck_assert_int_eq(r, 2); + + v[9] = 7; + r = intbits_le(10, v); + ck_assert_int_eq(r, 75); + r = intbytes_le(10, v); + ck_assert_int_eq(r, 10); +} +END_TEST + + +START_TEST(le_boundary_test) { + char v[10]; + int r; + + memset(v, 0, 10); + + + v[1] = 0x80; + r = intbytes_le(10, v); + ck_assert_int_eq(r, 2); + + v[2] = 0x01; + r = intbytes_le(10, v); + ck_assert_int_eq(r, 3); + +} +END_TEST + + +Suite *bits_suite(void) { + Suite *s; + TCase *tc; + + s = suite_create("Rlp"); + tc = tcase_create("Init"); + + tcase_add_test(tc, le_test); + tcase_add_test(tc, le_boundary_test); + suite_add_tcase(s, tc); + + return s; +} + + +int main(void) { + int num_fail; + + Suite *s; + SRunner *sr; + + s = bits_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_VERBOSE); + num_fail = srunner_ntests_failed(sr); + srunner_free(sr); + + return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/check_rlp b/tests/check_rlp Binary files differ. diff --git a/tests/check_rlp.c b/tests/check_rlp.c @@ -7,8 +7,102 @@ START_TEST(rlp_init_test) { rlp_encoder_t encoder; rlp_init(&encoder, 1024); + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_single_zero_byte_test) { + char v = 0x00; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + rlp_add(&encoder, 1, &v); + ck_assert_mem_eq(encoder.buf, &v, 1); + + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_empty_byte_test) { + char v = 0x80; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + + rlp_add(&encoder, 0, NULL); + ck_assert_mem_eq(encoder.buf, &v, 1); + + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_single_byte_test) { + char v = 55; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + + rlp_add(&encoder, 1, &v); + ck_assert_mem_eq(encoder.buf, &v, 1); + + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_single_byte_with_length_test) { + char l = 0x81; + char v = 56; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + + rlp_add(&encoder, 1, &v); + ck_assert_mem_eq(encoder.buf, &l, 1); + ck_assert_mem_eq(encoder.buf+1, &v, 1); + + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_short_bytes_with_length_test) { + char l = 0xb7; + char v[55]; + v[54] = 42; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + + rlp_add(&encoder, 55, (char*)&v); + ck_assert_mem_eq(encoder.buf, &l, 1); + ck_assert_mem_eq(encoder.buf+55, (char*)&(v[54]), 1); + + rlp_free(&encoder); +} +END_TEST + + +START_TEST(rlp_encode_long_bytes_with_length_test) { + char l = 0xb8; + char ll = 56; + char v[56]; + v[55] = 42; + + rlp_encoder_t encoder; + rlp_init(&encoder, 1024); + + rlp_add(&encoder, 56, (char*)&v); + ck_assert_mem_eq(encoder.buf, &l, 1); + ck_assert_mem_eq(encoder.buf+1, &ll, 1); + ck_assert_mem_eq(encoder.buf+57, (char*)&(v[55]), 1); + + rlp_free(&encoder); } END_TEST @@ -20,11 +114,18 @@ Suite *rlp_suite(void) { tc = tcase_create("Init"); tcase_add_test(tc, rlp_init_test); + tcase_add_test(tc, rlp_encode_empty_byte_test); + tcase_add_test(tc, rlp_encode_single_zero_byte_test); + tcase_add_test(tc, rlp_encode_single_byte_test); + tcase_add_test(tc, rlp_encode_single_byte_with_length_test); + tcase_add_test(tc, rlp_encode_short_bytes_with_length_test); + tcase_add_test(tc, rlp_encode_long_bytes_with_length_test); suite_add_tcase(s, tc); return s; } + int main(void) { int num_fail;