mirror of
https://github.com/tezc/sc.git
synced 2025-01-14 06:43:04 +08:00
407 lines
11 KiB
C
407 lines
11 KiB
C
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2021 Ozan Tezcan
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
#ifndef SC_BUF_H
|
|
#define SC_BUF_H
|
|
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef SC_HAVE_CONFIG_H
|
|
#include "sc_config.h"
|
|
#else
|
|
#define sc_buf_malloc malloc
|
|
#define sc_buf_realloc realloc
|
|
#define sc_buf_free free
|
|
#endif
|
|
|
|
|
|
#define SC_BUF_CORRUPT 1u
|
|
#define SC_BUF_OOM 3u
|
|
|
|
#define SC_BUF_REF 8
|
|
#define SC_BUF_DATA 16
|
|
#define SC_BUF_READ (SC_BUF_REF | SC_BUF_DATA)
|
|
|
|
struct sc_buf
|
|
{
|
|
unsigned char *mem;
|
|
uint32_t cap;
|
|
uint32_t limit;
|
|
uint32_t rpos;
|
|
uint32_t wpos;
|
|
|
|
unsigned int error;
|
|
bool ref;
|
|
};
|
|
|
|
/**
|
|
* Create buffer
|
|
*
|
|
* @param buf buffer
|
|
* @param cap initial capacity
|
|
* @return 'false' on out of memory.
|
|
*/
|
|
bool sc_buf_init(struct sc_buf *buf, uint32_t cap);
|
|
|
|
/**
|
|
* Destroy buffer
|
|
* @param buf buffer
|
|
*/
|
|
void sc_buf_term(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Wrap memory into buffer, write position will be '0' after this call.
|
|
* Useful for using preallocated or stack allocated buffers.
|
|
*
|
|
* @param data data pointer
|
|
* @param len len
|
|
* @param flags if set 'SC_BUF_REF', buffer will not try to expand itself and
|
|
* 'sc_buf_term' will not try to 'free()' buffer.
|
|
* if set 'SC_BUF_DATA', buffer wpos will be 'len'.
|
|
* flags can be combined : SC_BUF_REF | SC_BUF_DATA
|
|
* @return
|
|
*/
|
|
struct sc_buf sc_buf_wrap(void *data, uint32_t len, int flags);
|
|
|
|
/**
|
|
* Set limit of the buffer, when buffer reaches limit, it will set buffer's
|
|
* 'out of memory' flag. Default is UINT32_MAX.
|
|
*
|
|
* @param buf buffer
|
|
* @param limit limit
|
|
*/
|
|
void sc_buf_limit(struct sc_buf *buf, uint32_t limit);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @param pos pos
|
|
* @return buffer address at 'pos'
|
|
*/
|
|
void *sc_buf_at(struct sc_buf *buf, uint32_t pos);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return current capacity.
|
|
*/
|
|
uint32_t sc_buf_cap(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Reserve space
|
|
*
|
|
* @param buf buffer
|
|
* @param len len
|
|
* @return 'false' on out of memory or hits the 'limit'.
|
|
* 'out memory flag' will be set to check it later.
|
|
*/
|
|
bool sc_buf_reserve(struct sc_buf *buf, uint32_t len);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return 'true' if buffer is valid. Buffer can be invalid either on
|
|
* allocation failure or when you try to read data more than buffer
|
|
* has.
|
|
*/
|
|
bool sc_buf_valid(struct sc_buf *buf);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return current remaining space to write
|
|
*/
|
|
uint32_t sc_buf_quota(struct sc_buf *buf);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return current byte count in the buffer
|
|
*/
|
|
uint32_t sc_buf_size(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Set read and write position to '0', clear error flag.
|
|
* @param buf buffer
|
|
*/
|
|
void sc_buf_clear(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Compact buffer, e.g if bytes in buffer at [3, 20],
|
|
* it will be moved to [0, 17]
|
|
*
|
|
* @param buf buffer
|
|
*/
|
|
void sc_buf_compact(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Advance read position, useful when you pass underlying array to another
|
|
* function which operates on void*. e.g socket write() call.
|
|
*
|
|
* @param buf buffer
|
|
* @param len len
|
|
*/
|
|
void sc_buf_mark_read(struct sc_buf *buf, uint32_t len);
|
|
|
|
/**
|
|
* Advance read position, useful when you pass underlying array to another
|
|
* function which operates on void*. e.g socket read() call.
|
|
*
|
|
* @param buf buffer
|
|
* @param len len
|
|
*/
|
|
void sc_buf_mark_write(struct sc_buf *buf, uint32_t len);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return current read position
|
|
*/
|
|
uint32_t sc_buf_rpos(struct sc_buf *buf);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return new read position
|
|
*/
|
|
void sc_buf_set_rpos(struct sc_buf *buf, uint32_t pos);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return current write position
|
|
*/
|
|
uint32_t sc_buf_wpos(struct sc_buf *buf);
|
|
|
|
/**
|
|
* @param buf buffer
|
|
* @return new write position
|
|
*/
|
|
void sc_buf_set_wpos(struct sc_buf *buf, uint32_t pos);
|
|
|
|
/**
|
|
* Get address of read position. Useful for e.g : write(fd, sc_buf_rbuf(buf) ..)
|
|
*
|
|
* @param buf buffer
|
|
* @return read address
|
|
*/
|
|
void *sc_buf_rbuf(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Get address of write position. Useful for e.g : read(fd, sc_buf_wbuf(buf) ..)
|
|
*
|
|
* @param buf buffer
|
|
* @return write address
|
|
*/
|
|
void *sc_buf_wbuf(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Copy from src to dest, it will copy maximum amount of bytes without expanding
|
|
* dest buffer size
|
|
*
|
|
* @param dest Destination buffer
|
|
* @param src Source buffer
|
|
*/
|
|
void sc_buf_move(struct sc_buf *dest, struct sc_buf *src);
|
|
|
|
/**
|
|
* Read from buffer without advancing read position. 'peek' functions will set
|
|
* error flags if buffer does not have required amount of data.
|
|
*/
|
|
uint8_t sc_buf_peek_8_at(struct sc_buf *buf, uint32_t pos);
|
|
uint16_t sc_buf_peek_16_at(struct sc_buf *buf, uint32_t pos);
|
|
uint32_t sc_buf_peek_32_at(struct sc_buf *buf, uint32_t pos);
|
|
uint64_t sc_buf_peek_64_at(struct sc_buf *buf, uint32_t pos);
|
|
|
|
uint8_t sc_buf_peek_8(struct sc_buf *buf);
|
|
uint16_t sc_buf_peek_16(struct sc_buf *buf);
|
|
uint32_t sc_buf_peek_32(struct sc_buf *buf);
|
|
uint64_t sc_buf_peek_64(struct sc_buf *buf);
|
|
uint32_t sc_buf_peek_data(struct sc_buf *buf, uint32_t pos, unsigned char *dest,
|
|
uint32_t len);
|
|
|
|
/**
|
|
* Set value at current write position. 'set' functions will not try to expand
|
|
* buffer if there is no space and error flags will be set.
|
|
*/
|
|
void sc_buf_set_8_at(struct sc_buf *buf, uint32_t pos, uint8_t val);
|
|
void sc_buf_set_16_at(struct sc_buf *buf, uint32_t pos, uint16_t val);
|
|
void sc_buf_set_32_at(struct sc_buf *buf, uint32_t pos, uint32_t val);
|
|
void sc_buf_set_64_at(struct sc_buf *buf, uint32_t pos, uint64_t val);
|
|
|
|
void sc_buf_set_8(struct sc_buf *buf, uint8_t val);
|
|
void sc_buf_set_16(struct sc_buf *buf, uint16_t val);
|
|
void sc_buf_set_32(struct sc_buf *buf, uint32_t val);
|
|
void sc_buf_set_64(struct sc_buf *buf, uint64_t val);
|
|
uint32_t sc_buf_set_data(struct sc_buf *buf, uint32_t pos, const void *src,
|
|
uint32_t len);
|
|
/**
|
|
* Get values from buffer, read position will be advanced.
|
|
*/
|
|
bool sc_buf_get_bool(struct sc_buf *buf);
|
|
uint8_t sc_buf_get_8(struct sc_buf *buf);
|
|
uint16_t sc_buf_get_16(struct sc_buf *buf);
|
|
uint32_t sc_buf_get_32(struct sc_buf *buf);
|
|
uint64_t sc_buf_get_64(struct sc_buf *buf);
|
|
double sc_buf_get_double(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Read string. Strings are stored as [4 bytes length][string bytes]['\0'].
|
|
* So you can use return value without copying/freeing until you overwrite it
|
|
* in the buffer.
|
|
*
|
|
* @param buf buffer
|
|
* @return Pointer to string, possibly NULL if NULL has been put before.
|
|
*/
|
|
const char *sc_buf_get_str(struct sc_buf *buf);
|
|
|
|
/**
|
|
* Get binary data, returned pointer is valid until buffer is altered.
|
|
*
|
|
* @param buf buffer
|
|
* @param len data len
|
|
* @return pointer to data.
|
|
*/
|
|
void *sc_buf_get_blob(struct sc_buf *buf, uint32_t len);
|
|
|
|
/**
|
|
* Get binary data to destination buffer. If buffer does not have 'len' bytes,
|
|
* error flags will be set.
|
|
*
|
|
* @param buf buffer
|
|
* @param dest destination
|
|
* @param len len
|
|
*/
|
|
void sc_buf_get_data(struct sc_buf *buf, void *dest, uint32_t len);
|
|
|
|
/**
|
|
* Put functions, 'val' will be copied to the buffer and write position will
|
|
* be advanced.
|
|
*/
|
|
void sc_buf_put_bool(struct sc_buf *buf, bool val);
|
|
void sc_buf_put_8(struct sc_buf *buf, uint8_t val);
|
|
void sc_buf_put_16(struct sc_buf *buf, uint16_t val);
|
|
void sc_buf_put_32(struct sc_buf *buf, uint32_t val);
|
|
void sc_buf_put_64(struct sc_buf *buf, uint64_t val);
|
|
void sc_buf_put_double(struct sc_buf *buf, double val);
|
|
|
|
/**
|
|
* Write string. Strings are stored as [4 bytes length][string bytes]['\0'].
|
|
* NULL values are accepted, stored as [4 bytes length] = -1.
|
|
*
|
|
* @param buf buffer
|
|
* @param str string
|
|
*/
|
|
void sc_buf_put_str(struct sc_buf *buf, const char *str);
|
|
|
|
/**
|
|
* Write string. Strings are stored as [4 bytes length][string bytes]['\0'].
|
|
* NULL values are accepted, stored as [4 bytes length] = -1.
|
|
*
|
|
* @param buf buffer
|
|
* @param str string
|
|
* @param len string len excluding '\0' byte at the end
|
|
*/
|
|
void sc_buf_put_str_len(struct sc_buf *buf, const char *str, int len);
|
|
|
|
/**
|
|
* Put formatted string, passes arguments to vsnprintf
|
|
*
|
|
* @param buf buffer
|
|
* @param fmt fmt
|
|
* @param ... arguments
|
|
*/
|
|
void sc_buf_put_fmt(struct sc_buf *buf, const char *fmt, ...);
|
|
|
|
/**
|
|
* Put formatted string, passes arguments to vsnprintf but concatenates strings.
|
|
* Only useful if you want to append strings. It doesn't store string as length
|
|
* prefixed string. So, only valid use case is :
|
|
*
|
|
* e.g
|
|
*
|
|
* char tmp[128];
|
|
* struct sc_buf buf = sc_buf_wrap(tmp, sizeof(tmp), SC_BUF_REF);
|
|
* sc_buf_put_text(&buf, "Hello");
|
|
* sc_buf_put_text(&buf, " world");
|
|
*
|
|
* printf("%s", buf.mem); // Prints "Hello world"
|
|
*
|
|
*
|
|
* @param buf buffer
|
|
* @param fmt fmt
|
|
* @param ... arguments
|
|
*/
|
|
void sc_buf_put_text(struct sc_buf *buf, const char *fmt, ...);
|
|
|
|
/**
|
|
* Put binary data, it will store len in 4 bytes first, then binary data.
|
|
*
|
|
* @param buf buffer
|
|
* @param ptr data
|
|
* @param len data len
|
|
*/
|
|
void sc_buf_put_blob(struct sc_buf *buf, const void *ptr, uint32_t len);
|
|
|
|
/**
|
|
* Write 'len' bytes to buffer, on out of memory, error flag will be set.
|
|
*
|
|
* @param buf buffer
|
|
* @param dest dest
|
|
* @param len len
|
|
*/
|
|
void sc_buf_put_raw(struct sc_buf *buf, const void *ptr, uint32_t len);
|
|
|
|
/**
|
|
* Get encoded length of the variables.
|
|
*/
|
|
|
|
// clang-format off
|
|
static inline uint32_t sc_buf_bool_len(bool val) {(void) val; return 1;}
|
|
static inline uint32_t sc_buf_8_len(uint8_t val) {(void) val; return 1;}
|
|
static inline uint32_t sc_buf_16_len(uint16_t val){(void) val; return 2;}
|
|
static inline uint32_t sc_buf_32_len(uint32_t val){(void) val; return 4;}
|
|
static inline uint32_t sc_buf_64_len(uint64_t val){(void) val; return 8;}
|
|
static inline uint32_t sc_buf_double_len(double val){(void) val; return 8;}
|
|
// clang-format on
|
|
|
|
static inline uint32_t sc_buf_blob_len(void *ptr, uint32_t len)
|
|
{
|
|
(void) ptr;
|
|
assert(len <= INT32_MAX - 4);
|
|
|
|
return len + sc_buf_32_len(len);
|
|
}
|
|
|
|
static inline uint32_t sc_buf_str_len(const char *str)
|
|
{
|
|
const uint32_t bytes = sc_buf_32_len(UINT32_MAX) + sc_buf_8_len('\0');
|
|
|
|
if (str == NULL) {
|
|
return sc_buf_32_len(UINT32_MAX);
|
|
}
|
|
|
|
assert(strlen(str) <= INT32_MAX - 5);
|
|
|
|
return bytes + (uint32_t) strlen(str);
|
|
}
|
|
|
|
#endif
|