/* * Networking binary buffers pack/unpack library * * * (c) Alexander Vdolainen 2016 * (c) Alexander Vdolainen 2017 * * libndbuf 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 2.1 of the License, or * (at your option) any later version. * * libndbuf 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 this program. If not, see ."; * */ #ifndef __NDBUF_H__ #define __NDBUF_H__ #include #define NDBUF_TERMINAT 0xdeadbeef /* List of supported flags: */ #define NDBUF_BURN (1 << 1) /* burn buffer data before free */ #define NDBUF_NREA (1 << 2) /* non reallocatable buffer */ #define NDBUF_UCMO (1 << 3) /* user defined memops functions */ #define NDBUF_RORB (1 << 4) /* read-only buffer */ #define NDBUF_MOLS (1 << 5) /* "memory-ops"-less escan i.e. return * pointers to the raw buffer itself, * instead of alloc/memcpy */ struct ndbuf_memops { void *(*alloc)(size_t); uint32_t (*zero)(void *, size_t); void (*free)(void *ptr); }; typedef struct __rawdatabuffer_type { char *raw; union { void (*freebuf)(char *); const struct ndbuf_memops *mop; }; uint32_t rlength; /* raw buffer allocated length */ uint32_t ulength; /* length of used allocated space */ uint32_t curr; /* cursor for read/write operations */ size_t blk_size; uint32_t flags; } ndbuf_t; /* variadic macro workaround */ #define VA_APPLY_VARIADIC_MACRO(macro, tuple) macro tuple #define __VA_NARG__(...) \ (__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1) #define __VA_NARG_(...) \ VA_APPLY_VARIADIC_MACRO(__VA_ARG_N, (__VA_ARGS__)) #define __VA_ARG_N( \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ _61,_62,_63,N,...) N #define __RSEQ_N() \ 63, 62, 61, 60, \ 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 /* allocation, freeing */ /* allocate raw buffer with defaults preallocation */ ndbuf_t *ndbuf_new(void); /* will do the same as ndbuf_new but will pre-allocate with the given length */ ndbuf_t *ndbuf_new_palloc(uint32_t); /* create ndbuf from raw buffer */ ndbuf_t *ndbuf_new_frombuf(char *buf, size_t buf_len, void (*freebuf)(char *)); /* create a new buffer with user defined memops */ ndbuf_t *ndbuf_new_wmops(const struct ndbuf_memops *, const size_t); /* free all allocated space and buffer itself */ void ndbuf_free(ndbuf_t *); /* read/write */ /* read different types, should return the size of the * ridden data, otherwise error occurs */ uint32_t ndbuf_read_u8(ndbuf_t *, uint8_t *); uint32_t ndbuf_read_u16(ndbuf_t *, uint16_t *); uint32_t ndbuf_read_u32(ndbuf_t *, uint32_t *); uint32_t ndbuf_read_u64(ndbuf_t *, uint64_t *); /* get raw data, pointer must be allocated with at least required length, * will return size of ridden data */ uint32_t ndbuf_read_raw(ndbuf_t *, void *, uint32_t); /* write different types, should return the size of the * written data, otherwise error occurs */ uint32_t ndbuf_write_u8(ndbuf_t *, uint8_t); uint32_t ndbuf_write_u16(ndbuf_t *, uint16_t); uint32_t ndbuf_write_u32(ndbuf_t *, uint32_t); uint32_t ndbuf_write_u64(ndbuf_t *, uint64_t); /* write raw data with the given length */ uint32_t ndbuf_write_raw(ndbuf_t *, void *, uint32_t); /* write raw data *before* existing data */ uint32_t ndbuf_write_raw_head(ndbuf_t *, void *, uint32_t); /* parse */ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap); int ndbuf_escan_wot(ndbuf_t *b, const char *fmt, int argc, ...); #define ndbuf_escan(b, fmt, ...) \ ndbuf_escan_wot((b), (fmt), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, NDBUF_TERMINAT) /* print */ uint32_t ndbuf_print_va(ndbuf_t *b, const char *fmt, int argc, va_list ap); uint32_t ndbuf_print_wot(ndbuf_t *b, const char *fmt, int argc, ...); #define ndbuf_print(b, fmt, ...) \ ndbuf_print_wot((b), (fmt), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, NDBUF_TERMINAT) /* misc */ /* returns length of used space in the buffer */ uint32_t ndbuf_length(ndbuf_t *); /* set used length */ int ndbuf_setlength(ndbuf_t *, uint32_t); /* returns length of allocated space in the buffer */ uint32_t ndbuf_alength(ndbuf_t *); /* returns length of the left data to read */ uint32_t ndbuf_leftlength(ndbuf_t *); /* returns a pointer to the raw data */ void *ndbuf_rdata(ndbuf_t *); /* return pointer to the data currently being read/write */ void *ndbuf_rdatacur(ndbuf_t *); /* set flags to the raw buffer */ void ndbuf_setflags(ndbuf_t *, int); /* exchange flags for raw buff */ void ndbuf_exflags(ndbuf_t *, int); /* reset current pointer */ void ndbuf_resetcur(ndbuf_t *); /* reset all the flags */ #define ndbuf_flagsreset(a) ndbuf_exflags((a), 0) /* compare buffers, returns 0 if equal */ int ndbuf_cmp(ndbuf_t *, ndbuf_t *); /* let the buffer to use actually used bytes, not all allocated space * will return 0 on success (or in case if it doesn't required), * ENOMEM or other error if fails */ int ndbuf_memopt(ndbuf_t *); /* free in a right way: freing allocated memory during escan */ void ndbuf_free_item(ndbuf_t *b, void *ip, size_t is); #endif /* __NDBUF_H__ */