rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 93ad86974a4ffa9907a66a7ca441bfb54d95250e
parent 99fe39ccd3388bf966db0f8b6c03f349c641b5b6
Author: vaplv <vaplv@free.fr>
Date:   Thu, 17 Sep 2020 10:53:52 +0200

Merge branch 'release_0.10'

Diffstat:
MREADME.md | 20++++++++++++++++++++
Mcmake/CMakeLists.txt | 8++++++--
Asrc/endianness.h | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/hash.c | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/hash.h | 25+++++++++++++++++++++++++
Msrc/str.c | 50++++++++++++++++++++++++++++++++++++++++++--------
Msrc/str.h | 24++++++++++++++++++++++++
Asrc/test_endianness.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_hash_sha256.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_str.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_text_reader.c | 9++++++---
11 files changed, 668 insertions(+), 13 deletions(-)

diff --git a/README.md b/README.md @@ -17,6 +17,26 @@ project can be now edited, built, tested and installed as any CMake project. ## Release notes +### Version 0.10 + +- Add the `str_vprintf` and `str_append_[v]printf` functions to the string API + that sets the string content or appends text to it, respectively. The input + text is formatted following the `[v]printf` syntax, i.e. a literal is used to + format the text and a variable list of data are either provided directly as + function arguments (`printf`) or through a `va_list` (`vprintf`). +- Add macros and functions to deal with data endianness. The `BYTE_ORDER` macro + defines the endianness of the host; its value can be `LITTLE_ENDIAN` or + `BIG_ENDIAN`. The `byte_swap_<16|32|64>` functions revert the byte ordering + of the submitted unsigned integer of 16, 32 or 64 bits. Finally, the + `<little|big>_endian_<16|32|64>` functions ensure that the input unsigned + integer follows the little or big endian ordering: bytes are swapped only if + the host endianness is not the expected one. +- Add support of 256 bits hash. The `hash_sha256` function digest input data + wrt to the SHA-256 cryptographic hash algorithm. The `hash256_to_cstr` + function converts a 256 bits hash to its corresponding lower case string. + Finally The `hash256_eq` function check that the submitted 256 bits hashes + are the same. + ### Version 0.9.1 - Add the `VFATAL` macro that works as the regular `FATAL` macro but with an diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -38,13 +38,14 @@ include(rcmake) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 9) -set(VERSION_PATCH 1) +set(VERSION_MINOR 10) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(RSYS_FILES_SRC clock_time.c cstr.c + hash.c image.c library.c logger.c @@ -90,6 +91,7 @@ set(RSYS_FILES_INC_API dynamic_array_uint.h dynamic_array_size_t.h dynamic_array_str.h + endianness.h float2.h float3.h float4.h @@ -209,6 +211,7 @@ if(NOT NO_TEST) new_test(test_double22) new_test(test_double33 ${MATH_LIB}) new_test(test_double44) + new_test(test_endianness) new_test(test_dynamic_array rsys) new_test(test_float2 ${MATH_LIB}) new_test(test_float3 ${MATH_LIB}) @@ -219,6 +222,7 @@ if(NOT NO_TEST) new_test(test_free_list rsys) new_test(test_func_name) new_test(test_hash_table rsys) + new_test(test_hash_sha256 rsys) new_test(test_image rsys) new_test(test_library rsys) new_test(test_list rsys) diff --git a/src/endianness.h b/src/endianness.h @@ -0,0 +1,124 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef ENDIANNESS_H +#define ENDIANNESS_H + +#include "rsys.h" + +#if defined(COMPILER_GCC) + #define BYTE_ORDER __BYTE_ORDER__ + #define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ + #define BIG_ENDIAN __ORDER_BIG_ENDIAN__ + #include <byteswap.h> +#elif defined(COMPILER_CL) + #include <Windows.h> + #define BYTE_ORDER REG_DWORD + #define LITTLE_ENDIAN REG_DWORD_LITTLE_ENDIAN + #define BIG_ENDIAN REG_DWORD_BIG_ENDIAN +#else + #error "Undefined byte ordering macros" +#endif + +#ifdef COMPILER_GCC +static FINLINE uint16_t byte_swap_16(const uint16_t ui) { return bswap_16(ui); } +static FINLINE uint32_t byte_swap_32(const uint32_t ui) { return bswap_32(ui); } +static FINLINE uint64_t byte_swap_64(const uint64_t ui) { return bswap_64(ui); } + +#elif defined COMPILER_CL +static FINLINE uint16_t +byte_swap_16(const uint16_t ui) +{ + STATIC_ASSERT(sizeof(unsigned short) == sizeof(uint16_t), + Unexpected_sizeof_ushort); + return _byteswap_ushort(ui); +} + +static FINLINE uint32_t +byte_swap_32(const uint32_t ui) +{ + STATIC_ASSERT(sizeof(unsigned long) == sizeof(uint32_t), + Unexpected_sizeof_ushort); + return _byteswap_ulong(ui); +} + +static FINLINE uint64_t +byte_swap_64(const uint64_t ui) +{ + return _byteswap_uint64(ui); +} +#endif + +static FINLINE uint16_t +little_endian_16(const uint16_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_16(ui); +#endif +} + +static FINLINE uint32_t +little_endian_32(const uint32_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_32(ui); +#endif +} + +static FINLINE uint64_t +little_endian_64(const uint64_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return ui; +#elif BYTE_ORDER == BIG_ENDIAN + return byte_swap_64(ui); +#endif +} + +static FINLINE uint16_t +big_endian_16(const uint16_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_16(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +static FINLINE uint32_t +big_endian_32(const uint32_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_32(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +static FINLINE uint64_t +big_endian_64(const uint64_t ui) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return byte_swap_64(ui); +#elif BYTE_ORDER == BIG_ENDIAN + return ui; +#endif +} + +#endif /* ENDIANNESS_H */ diff --git a/src/hash.c b/src/hash.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L + +#include "endianness.h" +#include "hash.h" +#include "mem_allocator.h" + +#include <string.h> + +/* Array of round constants: first 32 bits of the fractional parts of the cube + * roots of the first 64 primes 2..311 */ +static const uint32_t k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +/* Right rotation */ +static FINLINE uint32_t +rrot(const uint32_t ui, const unsigned int count) +{ + ASSERT(count <= 32); + return ui >> count | ui << (32 - count); +} + +static size_t +create_msg + (struct mem_allocator* allocator, + const void* data, + const size_t len, + char** out_msg) +{ + char* msg = NULL; + size_t msg_sz = 0; + ASSERT(allocator && out_msg); + + msg_sz = ALIGN_SIZE(len + 1/*Byte of the '1' bit*/ + 8/*message len*/, 64u); + msg = MEM_ALLOC(allocator, msg_sz); + if(!msg) goto error; + + memcpy(msg, data, len); + + /* Setup the '1' bit that marks the end of the msg */ + msg[len] = (char)0x80u; + /* Clean up the bytes after the msg up to the last 8 bytes */ + memset(msg+len+1, 0, msg_sz - len - 1 - 8); + /* Store the message 8*len in big endian */ + *(uint64_t*)(msg+msg_sz-8) = big_endian_64(len*8); + +exit: + *out_msg = msg; + return msg_sz; + +error: + msg_sz = 0; + if(msg) { MEM_RM(allocator, msg); msg = NULL; } + goto exit; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +hash_sha256 + (struct mem_allocator* mem_allocator, + const void* data, + const size_t len, + hash256_T hash) +{ + struct mem_allocator* allocator = NULL; + char* msg = NULL; + size_t msg_sz = 0; + size_t ichunk = 0; + size_t nchunks = 0; + res_T res = RES_OK; + + /* Initial hash values: first 32 bits of the fractional parts of the square + * roots of the first 8 primes 2..19 */ + uint32_t h0 = 0x6a09e667; + uint32_t h1 = 0xbb67ae85; + uint32_t h2 = 0x3c6ef372; + uint32_t h3 = 0xa54ff53a; + uint32_t h4 = 0x510e527f; + uint32_t h5 = 0x9b05688c; + uint32_t h6 = 0x1f83d9ab; + uint32_t h7 = 0x5be0cd19; + ASSERT(hash); + + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + + msg_sz = create_msg(allocator, data, len, &msg); + if(!msg) { res = RES_MEM_ERR; goto error; } + + ASSERT((msg_sz % 64) == 0); + nchunks = msg_sz / 64; /* #chunks of 512 bits */ + + FOR_EACH(ichunk, 0, nchunks) { + const char* chunk = msg + ichunk*64; + uint32_t w[64] = {0}; + uint32_t a=h0, b=h1, c=h2, d=h3, e=h4, f=h5, g=h6, h=h7; + int i; + + FOR_EACH(i, 0, 16) { + w[i] = big_endian_32(((uint32_t*)chunk)[i]); + } + FOR_EACH(i, 16, 64) { + const uint32_t s0 = rrot(w[i-15],7) ^ rrot(w[i-15],18) ^ (w[i-15] >> 3); + const uint32_t s1 = rrot(w[i-2],17) ^ rrot(w[i-2], 19) ^ (w[i-2] >> 10); + w[i] = w[i-16] + s0 + w[i-7] + s1; + } + + /* Compress the chunk */ + FOR_EACH(i, 0, 64) { + const uint32_t s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25); + const uint32_t ch = (e & f) ^ ((~e) & g); + const uint32_t tmp1 = h + s1 + ch + k[i] + w[i]; + const uint32_t s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22); + const uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + const uint32_t tmp2 = s0 + maj; + + h = g; + g = f; + f = e; + e = d + tmp1; + d = c; + c = b; + b = a; + a = tmp1 + tmp2; + } + + /* Update hash with the current compressed chunk */ + h0+=a; h1+=b; h2+=c; h3+=d; h4+=e; h5+=f; h6+=g; h7+=h; + } + + /* Write the results */ + ((uint32_t*)hash)[0] = big_endian_32(h0); + ((uint32_t*)hash)[1] = big_endian_32(h1); + ((uint32_t*)hash)[2] = big_endian_32(h2); + ((uint32_t*)hash)[3] = big_endian_32(h3); + ((uint32_t*)hash)[4] = big_endian_32(h4); + ((uint32_t*)hash)[5] = big_endian_32(h5); + ((uint32_t*)hash)[6] = big_endian_32(h6); + ((uint32_t*)hash)[7] = big_endian_32(h7); + +exit: + if(msg) MEM_RM(allocator, msg); + return res; +error: + goto exit; +} + +void +hash256_to_cstr(const hash256_T hash, char cstr[65]) +{ + size_t i; + ASSERT(hash && cstr); + FOR_EACH(i, 0, sizeof(hash256_T)) { + sprintf(cstr+i*2, "%02x", (uint8_t)hash[i]); + } +} + +int +hash256_eq(const hash256_T hash0, const hash256_T hash1) +{ + return memcmp(hash0, hash1, sizeof(hash256_T)) == 0; +} + diff --git a/src/hash.h b/src/hash.h @@ -18,6 +18,10 @@ #include "rsys.h" +struct mem_allocator; + +typedef char hash256_T[32]; + /* 32-bits Fowler/Noll/Vo hash function */ static INLINE uint32_t hash_fnv32(const void* data, const size_t len) @@ -56,5 +60,26 @@ hash_fnv64(const void* data, const size_t len) return hash; } +BEGIN_DECLS + +RSYS_API res_T +hash_sha256 + (struct mem_allocator* allocator, + const void* data, + const size_t len, + hash256_T hash); + +RSYS_API void +hash256_to_cstr + (const hash256_T hash, + char cstr[65]); + +RSYS_API int +hash256_eq + (const hash256_T hash0, + const hash256_T hash1); + +END_DECLS + #endif /* HASH_H */ diff --git a/src/str.c b/src/str.c @@ -17,7 +17,6 @@ #include "io_c99.h" #include "str.h" -#include <stdarg.h> #include <string.h> /******************************************************************************* @@ -185,22 +184,57 @@ res_T str_printf(struct str* str, const char* fmt, ...) { va_list ap; - size_t len; res_T res = RES_OK; ASSERT(str && fmt); + va_start(ap, fmt); + res = str_vprintf(str, fmt, ap); + va_end(ap); + return res; +} +res_T +str_append_printf(struct str* str, const char* fmt, ...) +{ + va_list ap; + res_T res = RES_OK; + ASSERT(str && fmt); va_start(ap, fmt); - len = (size_t)vsnprintf(str->cstr, str->allocated, fmt, ap); + res = str_append_vprintf(str, fmt, ap); + va_end(ap); + return res; +} + +res_T +str_vprintf(struct str* str, const char* fmt, va_list vargs_list) +{ + ASSERT(str && fmt); + str_clear(str); + return str_append_vprintf(str, fmt, vargs_list); +} + +res_T +str_append_vprintf(struct str* str, const char* fmt, va_list vargs_list) +{ + va_list ap; + size_t flen; /* Length of the formatted message */ + size_t slen; /* Length of the string */ + res_T res = RES_OK; + ASSERT(str && fmt); + + slen = str_len(str); + + VA_COPY(ap, vargs_list); + flen = (size_t)vsnprintf(str->cstr + slen, str->allocated - slen, fmt, ap); va_end(ap); - if(len >= str->allocated) { - res = ensure_allocated(str, len + 1/* Null char */, 0); + if(slen + flen >= str->allocated) { + res = ensure_allocated(str, slen + flen + 1/* Null char */, 1); if(res != RES_OK) goto error; - va_start(ap, fmt); - len = (size_t)vsnprintf(str->cstr, str->allocated, fmt, ap); + VA_COPY(ap, vargs_list); + flen = (size_t)vsnprintf(str->cstr + slen, str->allocated - slen, fmt, ap); va_end(ap); - CHK(len < str->allocated); + CHK(slen + flen < str->allocated); } exit: diff --git a/src/str.h b/src/str.h @@ -19,6 +19,8 @@ #include "hash.h" #include "mem_allocator.h" #include "rsys.h" + +#include <stdarg.h> #include <string.h> struct str { @@ -115,6 +117,28 @@ str_printf #endif ; +RSYS_API res_T +str_append_printf + (struct str* str, + const char* fmt, + ...) +#ifdef COMPILER_GCC + __attribute__((format(printf, 2, 3))) +#endif +; + +RSYS_API res_T +str_vprintf + (struct str* str, + const char* fmt, + va_list vargs_list); + +RSYS_API res_T +str_append_vprintf + (struct str* str, + const char* fmt, + va_list vargs_list); + END_DECLS static INLINE res_T diff --git a/src/test_endianness.c b/src/test_endianness.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "endianness.h" + +int +main(int argc, char** argv) +{ + uint16_t ui16 = 0x0123; + uint32_t ui32 = 0x01234567; + uint64_t ui64 = 0x0123456789ABCDEF; + (void)argc, (void)argv; + + CHK(byte_swap_16(ui16) == 0x2301); + CHK(byte_swap_32(ui32) == 0x67452301); + CHK(byte_swap_64(ui64) == 0xEFCDAB8967452301); + +#if BYTE_ORDER == LITTLE_ENDIAN + CHK(little_endian_16(ui16) == ui16); + CHK(little_endian_32(ui32) == ui32); + CHK(little_endian_64(ui64) == ui64); + CHK(big_endian_16(ui16) == byte_swap_16(ui16)); + CHK(big_endian_32(ui32) == byte_swap_32(ui32)); + CHK(big_endian_64(ui64) == byte_swap_64(ui64)); + +#elif BYTE_ORDER == BIG_ENDIAN + CHK(little_endian_16(ui16) == byte_swap_16(ui16)); + CHK(little_endian_32(ui32) == byte_swap_32(ui32)); + CHK(little_endian_64(ui64) == byte_swap_64(ui64)); + CHK(big_endian_16(ui16) == ui16); + CHK(big_endian_32(ui32) == ui32); + CHK(big_endian_64(ui64) == ui64); + +#else + #error "Undefined endianness" +#endif + + return 0; +} diff --git a/src/test_hash_sha256.c b/src/test_hash_sha256.c @@ -0,0 +1,133 @@ +/* Copyright (C) 2013-2020 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "endianness.h" +#include "hash.h" +#include "mem_allocator.h" +#include <string.h> + +struct test_str { + const char* str; + const char* sha256sum; +}; +struct test_data { + const void* mem; + const size_t len; + const char* sha256sum; +}; + +static void +chk_hash(const void* data, const size_t data_len, const char* sha256sum) +{ + hash256_T hash; + char hash_str[65]; + ASSERT(sha256sum); + CHK(hash_sha256(NULL, data, data_len, hash) == RES_OK); + hash256_to_cstr(hash, hash_str); + CHK(!strcmp(hash_str, sha256sum)); +} + +int +main(int argc, char** argv) +{ + char* data = NULL; + hash256_T hash0, hash1; + (void)argc, (void)argv; + + data = mem_alloc(0x6000003e); + CHK(data); + + data[0] = '\0'; + chk_hash(data, 0, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + CHK(hash_sha256(&mem_default_allocator, data, 0, hash0) == RES_OK); + ((uint32_t*)hash1)[0] = big_endian_32(0xe3b0c442); + ((uint32_t*)hash1)[1] = big_endian_32(0x98fc1c14); + ((uint32_t*)hash1)[2] = big_endian_32(0x9afbf4c8); + ((uint32_t*)hash1)[3] = big_endian_32(0x996fb924); + ((uint32_t*)hash1)[4] = big_endian_32(0x27ae41e4); + ((uint32_t*)hash1)[5] = big_endian_32(0x649b934c); + ((uint32_t*)hash1)[6] = big_endian_32(0xa495991b); + ((uint32_t*)hash1)[7] = big_endian_32(0x7852b855); + CHK(hash256_eq(hash0, hash1)); + + sprintf(data, "abc"); + chk_hash(data, strlen(data), + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + sprintf(data, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + chk_hash(data, strlen(data), + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + + data[0] = (char)0xbdu; + chk_hash(data, 1, + "68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b"); + + data[0] = (char)0xc9u; + data[1] = (char)0x8cu; + data[2] = (char)0x8eu; + data[3] = (char)0x55u; + chk_hash(data, 4, + "7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504"); + + memset(data, 0, 55); + chk_hash(data, 55, + "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7"); + + memset(data, 0, 56); + chk_hash(data, 56, + "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb"); + + memset(data, 0, 57); + chk_hash(data, 57, + "65a16cb7861335d5ace3c60718b5052e44660726da4cd13bb745381b235a1785"); + + memset(data, 0, 64); + chk_hash(data, 64, + "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"); + + memset(data, 0, 1000); + chk_hash(data, 1000, + "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53"); + + memset(data, 'A', 1000); + chk_hash(data, 1000, + "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4"); + + memset(data, 'U', 1005); + chk_hash(data, 1005, + "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0"); + + memset(data, 0, 1000000); + chk_hash(data, 1000000, + "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025"); + + memset(data, 'Z', 0x20000000); + chk_hash(data, 0x20000000, + "15a1868c12cc53951e182344277447cd0979536badcc512ad24c67e9b2d4f3dd"); + + memset(data, 0, 0x41000000); + chk_hash(data, 0x41000000, + "461c19a93bd4344f9215f5ec64357090342bc66b15a148317d276e31cbc20b53"); + + memset(data, 'B', 0x6000003e); + chk_hash(data, 0x6000003e, + "c23ce8a7895f4b21ec0daf37920ac0a262a220045a03eb2dfed48ef9b05aabea"); + + mem_rm(data); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_str.c b/src/test_str.c @@ -15,8 +15,34 @@ #include "str.h" #include "test_utils.h" +#include <stdarg.h> #include <string.h> +#ifdef COMPILER_GCC +__attribute__((format(printf, 2, 3))) +#endif +static void +chk_vprintf(struct str* str, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + CHK(str_vprintf(str, fmt, ap) == RES_OK); + va_end(ap); +} + +#ifdef COMPILER_GCC +__attribute__((format(printf, 2, 3))) +#endif +static void +chk_append_vprintf(struct str* str, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + CHK(str_append_vprintf(str, fmt, ap) == RES_OK); + va_end(ap); +} + + int main(int argc, char** argv) { @@ -150,6 +176,25 @@ main(int argc, char** argv) str_release(&str); str_init(&allocator_proxy, &str); + CHK(str_printf(&str, "Hello, ") == RES_OK); + CHK(str_append_printf(&str, "world!") == RES_OK); + CHK(!strcmp(str_cget(&str), "Hello, world!")); + CHK(str_printf(&str, "%s:%lu", __FILE__, 0xDECAFBADlu) == RES_OK); + CHK(str_append_printf(&str, ":%s", __FILE__) == RES_OK); + CHK(!strcmp(str_cget(&str), __FILE__":3737844653:"__FILE__)); + chk_vprintf(&str, "You should have received a copy of the %s %s %d", + "GNU", "Lesser General Public License", 3); + CHK(!strcmp(str_cget(&str), + "You should have received a copy of the " + "GNU Lesser General Public License 3")); + chk_append_vprintf(&str, " along with the %s library. If not, see %c%s%c.", + "RSys", '<', "http://www.gnu.org/licenses/", '>'); + CHK(!strcmp(str_cget(&str), + "You should have received a copy of the GNU Lesser General Public License 3 " + "along with the RSys library. If not, see <http://www.gnu.org/licenses/>.")); + str_release(&str); + + str_init(&allocator_proxy, &str); CHK(str_set(&str, "abcd") == RES_OK); CHK(str_len(&str) == 4); str_get(&str)[3] = '\0'; diff --git a/src/test_text_reader.c b/src/test_text_reader.c @@ -77,7 +77,8 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); /* Write the text into a stream */ - CHK(stream = fopen(filename, "w+")); + stream = fopen(filename, "w+"); + CHK(stream); FOR_EACH(i, 0, nlines) { const size_t len = strlen(text[i]); CHK(fwrite(text[i], 1, len, stream) == len); @@ -102,7 +103,8 @@ main(int argc, char** argv) check_text_reader(txtrdr); txtrdr_ref_put(txtrdr); - CHK(stream = freopen(filename, "w+", stream)); + stream = freopen(filename, "w+", stream); + CHK(stream); fprintf(stream, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); fprintf(stream, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); rewind(stream); @@ -110,7 +112,8 @@ main(int argc, char** argv) CHK(txtrdr_read_line(txtrdr) == RES_OK); txtrdr_ref_put(txtrdr); - CHK(stream = freopen(filename, "w+", stream)); + stream = freopen(filename, "w+", stream); + CHK(stream); fprintf(stream, "\r\n"); rewind(stream); CHK(txtrdr_stream(&allocator, stream, filename, '#', &txtrdr) == RES_OK);