Compare commits

...

15 Commits

Author SHA1 Message Date
9332a57be2 ndbuf_write_raw manual page has been added; 2025-10-10 00:42:28 +03:00
1f684819a4 ndbuf_read_raw refined 2025-10-10 00:00:14 +03:00
b1d0950b71 ndbuf_new refined; 2025-10-09 23:45:41 +03:00
6eea614d6c README refined 2025-10-09 23:23:03 +03:00
81756b45dd ndbuf_read_* man pages has been added; 2025-10-09 23:05:00 +03:00
Alexander Vdolainen
44f7aba37b Added: ndbuf_free_item manpage; 2018-09-18 19:11:03 +03:00
Alexander Vdolainen
68aa01d300 Added: ndbuf_free_item() function to free in a proper way e.g.
free allocated stuff via escan function.
2018-09-17 20:29:03 +03:00
Alexander Vdolainen
fb41052802 Added: new flag NDBUF_MOLS - if applied it will use allocless/memcpyless
escan e.g. just setup pointers to appropriate values within a raw
buffer memory piece.
2018-09-17 20:15:25 +03:00
Alexander Vdolainen
822146bf90 Version update: new things are added, time to increase version number; 2018-09-17 19:19:55 +03:00
Alexander Vdolainen
d0723c4a76 Added: Manpages directory and manpages for:
ndbuf_new(), ndbuf_new_frombuf(), ndbuf_new_wmops(),
	ndbuf_new_palloc(), ndbuf_new_free();
2018-09-17 18:38:37 +03:00
Alexander Vdolainen
6451c66518 Added: NDBUF_RORB flag is a read-only aware flag. Set this to avoid
writes to read-only buffers. E.g. use
ndbuf_setflags (b, NDBUF_RORB);
Fixes: More checks for non-reallocatable buffer are added;
2018-09-17 16:59:59 +03:00
baa1574746 Added possibility to use user defined memory ops:
Now u can create a special ndbuf with your custom memory operations,
 this is useful to keep ndbuf in a special mapped areas for a:
  - keep it secure (example lock pages to avoid your info going to swap)
  - using your own custom optimized allocator for your own block sizes
 Function: ndbuf_t *ndbuf_new_wmops(const struct ndbuf_memops *, const size_t);
  Args:
   1. Pointer to yout ops:
    struct ndbuf_memops {
     void *(*alloc)(size_t);
     uint32_t (*zero)(void *, size_t);
     void (*free)(void *ptr);
    };
   2. Size of chunk to grow buffer. if <= default value will be set.
2018-08-05 03:19:36 +03:00
0a9ff172a5 Fixed ret type warning; 2018-08-05 00:51:22 +03:00
Alexander Vdolainen
b6dba50071 NEWS updated; test commit (for sync); 2018-07-26 17:42:20 +03:00
Alexander Vdolainen
81bfa9eecc Fixed pkgconfig template file (version variable); 2018-07-26 16:05:46 +03:00
26 changed files with 622 additions and 92 deletions

View File

@ -1,3 +1,9 @@
0.0.2 (15-nov-2018)
* Added possibility to use user defined memory ops with:
ndbuf_t *ndbuf_new_wmops(const struct ndbuf_memops *, const size_t);
* Fixed bug with pkgconfig %VERSION% value
0.0.1 (24-nov-2017)
* initial version with all functions done
* tired from reuse this code and ... now it's lib

View File

@ -1,8 +1,9 @@
## Sample for libndbuf automaken stuff
## (c) alex@vapaa.xyz
## Distributed under GNU LGPL v2.1 or later
## Originally written by Alexander Vdolainen <alex@vapaa.xyz> (c) 2017
## Process this file with automake to produce Makefile.in
SUBDIRS = include
SUBDIRS = include man
clean-local:

2
NEWS
View File

@ -0,0 +1,2 @@
NEWS template
-------------

46
README
View File

@ -1,30 +1,28 @@
libndbuf: Network designed buffer ops library
----------------------------------------------
libndbuf: Network-oriented buffer operations library
----------------------------------------------------
1. What the shit is that ?
This is a quite small library to manipulate with binary packed buffers
in a normal network manner (i.e. bigendian). It might be useful to
apply for network packet creating/parsing.
Anyway, originally this code was resided in my different other *small*
projects - and i hate copy-paste -- well, that's why it gone to
this quite small library.
1. What is it?
A small C library providing a simple API to read and write typed values
to/from buffers with correct endianness handling.
2. API
Check out include directory...
btw, might be later i will write manpages, but for now didn't see any
sense for those effort.
Generally speaking - all is quite simple - create ndbuf_t structure fill
it in printf() style, read with sscanf() style, take raw data pointer and ...
send it somewhere whatever bla bla - you get a point.
2. Purpose
Make parsing and building network packets easy and concise. The API is
intended to act like a binary printf/scanf for packet fields.
Example:
Packet layout:
<16-bit><8-bit><32-bit><raw data>
Reading with a single call:
ndbuf_escan(buf, "wbdR", &a16, &a8, &a32, &data_ptr)
The same style is used to build packets.
3. Future plans
Fix bugs (but ... there are no bugs found, since this code was heavly used
already, but ... report me if found).
Write manpages (in my few projects those API is like a part of POSIX -
still cannot remember all).
Maybe will add a new functions (useful ones).
* Improve the API ergonomics (better support for preallocated buffers).
* Add convenience helpers and safer bounds checks.
* Possibly extend format specifiers and documentation.
4. Contact
That's simple -
Email/XMPP: alex@vapaa.xyz
Email: alex@vapaa.xyz

View File

@ -1,2 +1,2 @@
0.0.1
0.0.2

View File

@ -16,4 +16,5 @@ AC_OUTPUT([
Makefile
libndbuf.pc
include/Makefile
man/Makefile
])

View File

@ -5,12 +5,12 @@
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
* (c) Alexander Vdolainen 2017 <alex@vapaa.xyz>
*
* libtbusd is free software: you can redistribute it and/or modify it
* 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.
*
* libtbusd is distributed in the hope that it will be useful, but
* 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.
@ -27,16 +27,33 @@
#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 */
int flags;
void (*freebuf)(char *);
size_t blk_size;
uint32_t flags;
} ndbuf_t;
/* variadic macro workaround */
@ -67,12 +84,15 @@ typedef struct __rawdatabuffer_type {
/* allocate raw buffer with defaults preallocation */
ndbuf_t *ndbuf_new(void);
/* will do the same as ndbuf_new but will allocate given length */
/* 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 *);
@ -158,4 +178,7 @@ int ndbuf_cmp(ndbuf_t *, ndbuf_t *);
*/
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__ */

View File

@ -7,7 +7,7 @@ includedir=@includedir@
Name: libndbuf
Description: Network designed binary buffer pack/unpack library
Version: @LIBNDBUF_VERSION@
Version: @VERSION@
Requires:
Libs: -L${libdir} -lndbuf
Cflags: -I${includedir}

5
man/Makefile.am Normal file
View File

@ -0,0 +1,5 @@
man_MANS = ndbuf_new.3 ndbuf_new_palloc.3 ndbuf_new_wmops.3 ndbuf_new_frombuf.3 \
ndbuf_free.3 ndbuf_free_item.3 ndbuf_read_raw.3 ndbuf_read_u8.3 ndbuf_read_u16.3 \
ndbuf_read_u32.3 ndbuf_read_u64.3 ndbuf_write_raw.3 ndbuf_write_u8.3 ndbuf_write_u16.3 \
ndbuf_write_u32.3 ndbuf_write_u64.3

1
man/ndbuf_free.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_new.3

1
man/ndbuf_free_item.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_new.3

156
man/ndbuf_new.3 Normal file
View File

@ -0,0 +1,156 @@
.TH NDBUF_NEW 3 "15 September 2018" "NDBUF" "Binary buffers lib manual"
.SH NAME
ndbuf_new, ndbuf_new_palloc, ndbuf_new_frombuf, ndbuf_new_wmops, ndbuf_free - allocate and free buffer structure
.SH SYNOPSIS
.B "#include <ndbuf/ndbuf.h>"
.PP
.nf
ndbuf_t *ndbuf_new(void);
ndbuf_t *ndbuf_new_palloc(uint32_t len);
ndbuf_t *ndbuf_new_frombuf(char *buf, size_t buf_len,
void (*freebuf)(char *));
ndbuf_t *ndbuf_new_wmops(const struct ndbuf_memops *mops,
const size_t block_size);
void ndbuf_free(ndbuf_t *b);
void ndbuf_free_item(ndbuf_t *b, void *item, size_t item_size);
.PP
struct ndbuf_memops {
.br
void *(*alloc)(size_t);
.br
uint32_t (*zero)(void *, size_t);
.br
void (*free)(void *);
.br
};
.fi
.SH DESCRIPTION
The
.B ndbuf_new
family of functions create and initialize an
.B ndbuf_t
structure using different allocation and memory-operation options. These routines simplify handling raw network-oriented buffers while providing hooks for custom memory management and secure wiping.
.PP
.TP
.B ndbuf_new()
Allocate and return a newly initialized
.B ndbuf_t
using library defaults. A default memory chunk is preallocated. No special flags are set.
.PP
.TP
.B ndbuf_new_palloc(uint32_t len)
Allocate and return a new
.B ndbuf_t
with an initial buffer of the specified length (in bytes). Other defaults apply; no special flags are set.
.PP
.TP
.B ndbuf_new_frombuf(char *buf, size_t buf_len, void (*freebuf)(char *))
Create a
.B ndbuf_t
that uses the provided buffer pointer
.I buf
of length
.I buf_len
as its underlying storage. If
.I freebuf
is a valid pointer to the function, it will be called to free the buffer when the ndbuf is destroyed. The returned ndbuf will have the
.B NDBUF_NREA
flag set, indicating the buffer is non-reallocatable. See
.BR ndbuf_setflags(3)
for flag details.
.PP
.TP
.B ndbuf_new_wmops(const struct ndbuf_memops *mops, const size_t block_size)
Create a
.B ndbuf_t
that uses the caller-provided memory-operation callbacks and a custom block size. The
.I mops
structure must provide the following function pointers:
.IP
.B alloc(size_t)
Function to allocate a memory block of the given size.
.IP
.B zero(void *, size_t)
Function to zero or overwrite a memory region; used when the
.B NDBUF_BURN
flag is set to securely erase memory.
.IP
.B free(void *)
Free a previously allocated memory block.
.IP
No special flags are set by this call.
.PP
.TP
.B ndbuf_free(ndbuf_t *b)
Free the
.I ndbuf_t
structure and, unless prevented by flags or missing free callbacks, free the associated buffer data. The underlying buffer is not freed if:
.IP
The
.B NDBUF_NREA
flag is set and no
.I freebuf
callback was provided in
.B ndbuf_new_frombuf().
.IP
The
.B NDBUF_RORB
flag is set.
.PP
.TP
.B ndbuf_free_item(ndbuf_t *b, void item, size_t item_size)
Free an item previously allocated via the library's escan function. If the
.B NDBUF_BURN
flag is set and
.I item_size
is non-zero, the buffer will be securely zeroed (via
.B zero()
or
.B memset()
) before being freed. This function uses the default memory ops unless custom ops were provided at creation.
.SH RETURN VALUE
On success the
.B ndbuf_new
family of functions returns a pointer to the newly created
.B ndbuf_t.
On failure they return
.B NULL.
No specific
.I errno
value is set by these functions.
.SH ERRORS
These functions return NULL on allocation or initialization failure. Callers should check the return value before use.
.SH EXAMPLES
.PP
.nf
/ Create a default buffer */
ndbuf_t *b = ndbuf_new();
if (!b) { / handle error */ }
/* Create buffer from existing memory */
char *buf = malloc(256);
ndbuf_t *b2 = ndbuf_new_frombuf(buf, 256, free);
/* Create buffer with custom memory ops */
struct ndbuf_memops mops = { custom_alloc, custom_zero, custom_free };
ndbuf_t *b3 = ndbuf_new_wmops(&mops, 4096);
.fi
.SH RATIONALE
The
.B ndbuf_new_wmops()
function is useful for environments requiring special memory handling (for example, preventing pages from being swapped, using locked memory, or providing a custom zeroing routine to avoid compiler optimizations).
.SH SEE ALSO
.BR ndbuf_setflags(3),
.BR ndbuf_escan(3)
.SH COPYRIGHT
This software licensed under GNU LGPL v2.1 or later. See COPYING for further details.
.PP
(c) Authors of libndbuf 2017-2018 <http://vapaa.xyz>
.SH AUTHOR
Alexander Vdolainen (alex@vapaa.xyz)

1
man/ndbuf_new_frombuf.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_new.3

1
man/ndbuf_new_palloc.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_new.3

1
man/ndbuf_new_wmops.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_new.3

92
man/ndbuf_read_raw.3 Normal file
View File

@ -0,0 +1,92 @@
.TH NDBUF_READ_RAW 3 "15 September 2018" "NDBUF" "Binary buffers lib manual"
.SH NAME
ndbuf_read_u8, ndbuf_read_u16, ndbuf_read_u32, ndbuf_read_u64,
ndbuf_read_raw - read data of specified length and type
.SH SYNOPSIS
.B "#include <ndbuf/ndbuf.h>"
.PP
.nf
uint32_t ndbuf_read_u8(ndbuf_t *b, uint8_t *val);
uint32_t ndbuf_read_u16(ndbuf_t *b, uint16_t *val);
uint32_t ndbuf_read_u32(ndbuf_t *b, uint32_t *val);
uint32_t ndbuf_read_u64(ndbuf_t *b, uint64_t *val);
uint32_t ndbuf_read_raw(ndbuf_t *b, void *dst, uint32_t len);
.fi
.SH DESCRIPTION
The ndbuf_read_ family copies data from an
.B ndbuf_t
instance into caller-provided storage. On success each function returns the number of bytes read; on error it returns 0.
.TP
.B ndbuf_read_u8(ndbuf_t *b, uint8_t *val)
Read one unsigned 8bit value from the current buffer position into
.I val
and advance the buffer cursor by one byte. Returned value is the number of bytes read (1) or 0 on error.
.TP
.B ndbuf_read_u16(ndbuf_t *b, uint16_t *val)
Read one unsigned 16bit value, store it into
.I val
and advance the cursor by two bytes. Returns 2 on success or 0 on error.
.TP
.B ndbuf_read_u32(ndbuf_t *b, uint32_t *val)
Read one unsigned 32bit value, store into
.I val
and advance the cursor by four bytes. Returns 4 on success or 0 on error.
.TP
.B ndbuf_read_u64(ndbuf_t *b, uint64_t *val)
Read one unsigned 64bit value, store into
.I val
and advance the cursor by eight bytes. Returns 8 on success or 0 on error.
.TP
.B ndbuf_read_raw(ndbuf_t *b, void *dst, uint32_t len)
Copy
.I len
bytes of raw data from the buffer to
.I dst
and advance the cursor by
.I len. The caller must ensure
.I dst
points to memory at least
.I len
bytes long. Returns the number of bytes copied or 0 on error.
.SH RETURN VALUE
On success each function returns the number of bytes read. On error they return 0; no specific
.I errno
value is set.
.SH ERRORS
Functions return 0 when the requested read would exceed the available data, when
.I b
is NULL, or on other internal errors. Callers must validate the return value before using output data.
.SH RATIONALE
Use these functions when you need a local copy of numeric or raw data. For zero-copy parsing or formatted
extraction consider the
.BR ndbuf_escan(3)
family instead.
.SH EXAMPLES
.PP
.nf
/* Read values from buffer */
uint8_t a8;
uint16_t a16;
uint32_t a32;
if (ndbuf_read_u8(b, &a8) != 1) { /* handle error */ }
if (ndbuf_read_u16(b, &a16) != 2) { /* handle error */ }
if (ndbuf_read_u32(b, &a32) != 4) { /* handle error */ }
/* Read raw payload */
char payload[128];
if (ndbuf_read_raw(b, payload, sizeof(payload)) != sizeof(payload)) { /* handle error */ }
.fi
.SH SEE ALSO
.BR ndbuf_write_raw(3),
.BR ndbuf_escan(3)
.SH COPYRIGHT
This software licensed under GNU LGPL v2.1 or later. See COPYING for further details.
.PP
(c) Authors of libndbuf 2017-2018 <http://vapaa.xyz>
.SH AUTHOR
Alexander Vdolainen (alex@vapaa.xyz)

1
man/ndbuf_read_u16.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_read_raw.3

1
man/ndbuf_read_u32.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_read_raw.3

1
man/ndbuf_read_u64.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_read_raw.3

1
man/ndbuf_read_u8.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_read_raw.3

77
man/ndbuf_write_raw.3 Normal file
View File

@ -0,0 +1,77 @@
.TH NDBUF_WRITE_RAW 3 "15 September 2018" "NDBUF" "Binary buffers lib manual"
.SH NAME
ndbuf_write_u8, ndbuf_write_u16, ndbuf_write_u32, ndbuf_write_u64,
ndbuf_write_raw - write data to the buffer of specified length and type
.SH SYNOPSIS
.B "#include <ndbuf/ndbuf.h>"
.PP
.nf
uint32_t ndbuf_write_u8(ndbuf_t *b, uint8_t val);
uint32_t ndbuf_write_u16(ndbuf_t *b, uint16_t val);
uint32_t ndbuf_write_u32(ndbuf_t *b, uint32_t val);
uint32_t ndbuf_write_u64(ndbuf_t *b, uint64_t val);
uint32_t ndbuf_write_raw(ndbuf_t *b, void *src, uint32_t len);
.fi
.SH DESCRIPTION
The ndbuf_write_ family writes data to an
.B ndbuf_t
instance from caller-provided storage. On success each function returns the number of bytes written; on error it returns 0.
.TP
.B ndbuf_write_u8(ndbuf_t *b, uint8_t val)
Write one unsigned 8bit value to the current buffer position from
.I val
and advance the buffer cursor by one byte. Returned value is the number of bytes written (1) or 0 on error.
.TP
.B ndbuf_write_u16(ndbuf_t *b, uint16_t val)
Writes one unsigned 16bit value, from
.I val
and advance the cursor by two bytes. Returns 2 on success or 0 on error.
.TP
.B ndbuf_write_u32(ndbuf_t *b, uint32_t val)
Write one unsigned 32bit value, from
.I val
and advance the cursor by four bytes. Returns 4 on success or 0 on error.
.TP
.B ndbuf_write_u64(ndbuf_t *b, uint64_t val)
Write one unsigned 64bit value, from
.I val
and advance the cursor by eight bytes. Returns 8 on success or 0 on error.
.TP
.B ndbuf_read_raw(ndbuf_t *b, void *dst, uint32_t len)
Copy
.I len
from
.I dst
to the buffer and advance the cursor by
.I len. The caller must ensure
.I dst
points to memory at least
.I len
bytes long. Returns the number of bytes copied or 0 on error.
.SH RETURN VALUE
On success each function returns the number of bytes read. On error they return 0; no specific
.I errno
value is set.
.SH ERRORS
Functions return 0 when the requested read would exceed the available data, when
.I b
is NULL, or on other internal errors. Callers must validate the return value before using output data.
.SH RATIONALE
None
.SH EXAMPLES
None
.PP
.SH SEE ALSO
.BR ndbuf_read_raw(3),
.BR ndbuf_print(3)
.SH COPYRIGHT
This software licensed under GNU LGPL v2.1 or later. See COPYING for further details.
.PP
(c) Authors of libndbuf 2017-2018 <http://vapaa.xyz>
.SH AUTHOR
Alexander Vdolainen (alex@vapaa.xyz)

1
man/ndbuf_write_u16.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_write_raw.3

1
man/ndbuf_write_u32.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_write_raw.3

1
man/ndbuf_write_u64.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_write_raw.3

1
man/ndbuf_write_u8.3 Symbolic link
View File

@ -0,0 +1 @@
ndbuf_write_raw.3

274
ndbuf.c
View File

@ -2,14 +2,14 @@
* Networking binary buffers pack/unpack library
*
* (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
* (c) Alexander Vdolainen 2017 <alex@vapaa.xyz>
* (c) Alexander Vdolainen 2017, 2018 <alex@vapaa.xyz>
*
* libtbusd is free software: you can redistribute it and/or modify it
* 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.
*
* libtbusd is distributed in the hope that it will be useful, but
* 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.
@ -34,7 +34,7 @@ static inline uint64_t ntohll(uint64_t n)
#ifdef WORDS_BIGENDIAN
return n;
#else /* WORDS_BIGENDIAN */
return (((uint64_t)(n) << 56) | \
return (uint64_t)(((uint64_t)(n) << 56) | \
(((uint64_t)(n) << 40) & 0xff000000000000ULL) | \
(((uint64_t)(n) << 24) & 0xff0000000000ULL) | \
(((uint64_t)(n) << 8) & 0xff00000000ULL) | \
@ -104,16 +104,51 @@ ndbuf_t *ndbuf_new_palloc(uint32_t alen)
return b;
}
ndbuf_t *ndbuf_new_wmops(const struct ndbuf_memops *o, const size_t blk_len)
{
ndbuf_t *b = NULL;
if(!o) return NULL;
else { /* avoid nil calls */
if(!o->alloc || !o->free) return NULL;
}
if(!(b = malloc(sizeof(ndbuf_t)))) return NULL;
else memset(b, 0, sizeof(ndbuf_t));
if(blk_len <= 0) b->blk_size = DEFAULT_PREALLOC_SIZE;
if(!(b->raw = o->alloc(b->blk_size))) {
free(b);
return NULL;
} else {
b->rlength = b->blk_size;
b->ulength = b->curr = 0;
b->mop = o;
b->flags |= NDBUF_UCMO;
}
return b;
}
/* free all allocated space and buffer itself */
void ndbuf_free(ndbuf_t *b)
{
const struct ndbuf_memops *o = NULL;
if(!b) return;
if((b->flags & NDBUF_BURN) && b->raw)
memset(b->raw, 0, b->rlength);
if(b->flags & NDBUF_UCMO) o = b->mop;
if((b->flags & NDBUF_NREA) && b->freebuf) b->freebuf(b->raw);
else if(b->raw) free(b->raw);
if(o) {
if((b->flags & NDBUF_BURN) && o->zero) o->zero((void *)b->raw, b->rlength);
o->free(b->raw);
} else {
if((b->flags & NDBUF_BURN) && b->raw)
memset(b->raw, 0, b->rlength);
if((b->flags & NDBUF_NREA) && b->freebuf) b->freebuf(b->raw);
else if(b->raw) free(b->raw);
}
if(b->flags & NDBUF_BURN) memset(b, 0, sizeof(ndbuf_t));
free(b);
@ -210,23 +245,37 @@ static int __rdb_grow(ndbuf_t *b, uint32_t len)
{
uint32_t rlen;
char *ne = NULL;
const struct ndbuf_memops *o = NULL;
size_t bs = b->blk_size;
if(!len) return -1;
if(b->rlength + len > NDBUF_MAXLENGTH) return -1;
rlen = len +
(len%DEFAULT_PREALLOC_SIZE != 0 ? (DEFAULT_PREALLOC_SIZE - len%DEFAULT_PREALLOC_SIZE) : 0);
if(b->flags & NDBUF_UCMO) o = b->mop;
rlen = len + (len%bs != 0 ? (bs - len%bs) : 0);
if(b->rlength + rlen > NDBUF_MAXLENGTH) rlen = len;
rlen += b->rlength;
if(!(ne = malloc(rlen))) return -1;
if(o) ne = (char *)o->alloc(rlen);
else ne = malloc(rlen);
if(b->flags & NDBUF_BURN) memset(ne, 0, rlen);
if(!ne) return -1;
if(b->flags & NDBUF_BURN) {
if(o) o->zero((void *)ne, rlen);
else memset(ne, 0, rlen);
}
memcpy(ne, b->raw, b->ulength);
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength);
free(b->raw);
if(o) {
if(b->flags & NDBUF_BURN) o->zero((void *)b->raw, b->rlength);
o->free((void *)b->raw);
} else {
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength);
free(b->raw);
}
b->raw = ne;
b->rlength = rlen;
@ -287,12 +336,25 @@ uint32_t ndbuf_write_u64(ndbuf_t *b, uint64_t uu)
return sizeof(uint64_t);
}
static inline int __ndbuf_is_ro(ndbuf_t *b)
{
return (b->flags & NDBUF_RORB) ? 1 : 0;
}
static inline int __ndbuf_is_nrea(ndbuf_t *b)
{
return (b->flags & NDBUF_NREA) ? 1 : 0;
}
/* write raw data with the given length */
uint32_t ndbuf_write_raw(ndbuf_t *b, void *wi, uint32_t len)
{
if(!b || !b->raw) return 0;
if(!wi || !len) return 0;
if(__ndbuf_is_ro(b)) return 0; /* read only buffer */
if(b->ulength + len >= b->rlength) {
if(__ndbuf_is_nrea(b)) return 0; /* non reallocatable buffer */
if(__rdb_grow(b, len)) return 0;
}
@ -306,27 +368,46 @@ uint32_t ndbuf_write_raw(ndbuf_t *b, void *wi, uint32_t len)
uint32_t ndbuf_write_raw_head(ndbuf_t *b, void *wi, uint32_t len)
{
char *ne;
const struct ndbuf_memops *o = NULL;
uint32_t rlen;
size_t bs = b->blk_size;
if(!b || !b->raw) return 0;
if(!wi || !len) return 0;
if(__ndbuf_is_ro(b)) return 0; /* read only buffer */
if(b->ulength + len > b->rlength) {
if(__ndbuf_is_nrea(b)) return 0; /* non reallocatable buffer */
/* allocate a new one and copy it right */
if(b->rlength + len > NDBUF_MAXLENGTH) return -1;
rlen = len +
(len%DEFAULT_PREALLOC_SIZE != 0 ? (DEFAULT_PREALLOC_SIZE - len%DEFAULT_PREALLOC_SIZE) : 0);
rlen = len + (len%bs != 0 ? (bs - len%bs) : 0);
if(b->rlength + rlen > NDBUF_MAXLENGTH) rlen = len;
rlen += b->rlength;
if(!(ne = malloc(rlen))) return -1;
if(b->flags & NDBUF_BURN) memset(ne, 0, rlen);
if(b->flags & NDBUF_UCMO) o = b->mop;
if(o) ne = (char *)o->alloc(rlen);
else ne = malloc(rlen);
if(!ne) return -1;
if(b->flags & NDBUF_BURN) {
if(o) o->zero((void *)ne, rlen);
else memset(ne, 0, rlen);
}
memcpy((void *)ne + len, b->raw, b->ulength);
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength);
free(b->raw);
if(o) {
if(b->flags & NDBUF_BURN) o->zero((void *)b->raw, b->rlength);
o->free((void *)b->raw);
} else {
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength);
free(b->raw);
}
b->raw = ne;
b->rlength = rlen;
} else {
@ -339,8 +420,14 @@ uint32_t ndbuf_write_raw_head(ndbuf_t *b, void *wi, uint32_t len)
}
/* parse */
#define __is_moless(x) ((x) & NDBUF_MOLS) ? 1 : 0
#define __is_usermo(x) ((x) & NDBUF_UCMO) ? 1 : 0
int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
{
register uint32_t fo = b->flags;
register uint32_t len;
uint32_t clen;
va_list ap_copy;
union {
uint8_t *_u8;
@ -352,7 +439,6 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
ndbuf_t **_rdb;
} d;
const char *t, *last;
uint32_t len, clen;
int r, count;
va_copy(ap_copy, ap);
@ -393,18 +479,26 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
r = -1;
break;
}
/* FIXME: Document the following line in manpages %limits% */
if(clen > NDBUF_MAXLENGTH) goto __errrbread;
if((*d._cstr = malloc(clen + sizeof(char))) == NULL) {
r = -ENOMEM;
break;
if(__is_moless(fo)) {
*d._cstr = b->raw + b->curr;
} else {
if(__is_usermo(fo)) *d._cstr = b->mop->alloc(clen + sizeof(char));
else *d._cstr = malloc(clen + sizeof(char));
if(*d._cstr == NULL) {
r = -ENOMEM;
break;
}
len = ndbuf_read_raw(b, *d._cstr, clen);
if(len != clen) {
free(*d._cstr);
goto __errrbread;
}
(*d._cstr)[len] = '\0';
d._cstr = NULL;
}
len = ndbuf_read_raw(b, *d._cstr, clen);
if(len != clen) {
free(*d._cstr);
goto __errrbread;
}
(*d._cstr)[len] = '\0';
d._cstr = NULL;
r = 0;
break;
case 'p':
@ -414,14 +508,20 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
*d._dp = NULL;
count++;
if((*d._dp = malloc(clen)) == NULL) {
r = -ENOMEM;
break;
}
len = ndbuf_read_raw(b, *d._dp, clen);
if(len != clen) {
free(*d._dp);
goto __errrbread;
if(__is_moless(fo)) {
*d._dp = b->raw + b->curr;
} else {
if(__is_usermo(fo)) *d._dp = b->mop->alloc(clen);
else *d._dp = malloc(clen);
if(*d._dp == NULL) {
r = -ENOMEM;
break;
}
len = ndbuf_read_raw(b, *d._dp, clen);
if(len != clen) {
free(*d._dp);
goto __errrbread;
}
}
d._dp = NULL;
r = 0;
@ -435,19 +535,25 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
r = -1;
break;
}
if((*d._dp = malloc(clen)) == NULL) {
r = -ENOMEM;
break;
}
len = ndbuf_read_raw(b, *d._dp, clen);
if(len != clen) {
free(*d._dp);
goto __errrbread;
if(__is_moless(fo)) {
*d._dp = b->raw + b->curr;
} else {
if(__is_usermo(fo)) *d._dp = b->mop->alloc(clen);
else *d._dp = malloc(clen);
if(*d._dp == NULL) {
r = -ENOMEM;
break;
}
len = ndbuf_read_raw(b, *d._dp, clen);
if(len != clen) {
free(*d._dp);
goto __errrbread;
}
}
d._dp = NULL;
r = 0;
break;
case 'R':
case 'R': /* FIXME: what about moless and user defined ops ? */
d._rdb = va_arg(ap, ndbuf_t **);
*d._rdb = NULL;
@ -498,9 +604,14 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
break;
case 's':
d._cstr = va_arg(ap_copy, char **);
if(*d._cstr) {
memset(*d._cstr, 0, strlen(*d._cstr));
free(*d._cstr);
if(*d._cstr && !__is_moless(fo)) {
if(__is_usermo(fo)) {
b->mop->zero(*d._cstr, strlen(*d._cstr));
b->mop->free(*d._cstr);
} else {
memset(*d._cstr, 0, strlen(*d._cstr));
free(*d._cstr);
}
}
break;
case 'R':
@ -511,7 +622,10 @@ int ndbuf_escan_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
(void)va_arg(ap_copy, size_t);
case 'P':
d._dp = va_arg(ap_copy, void **);
if(*d._dp) free(*d._dp);
if(*d._dp && !__is_moless(fo)) {
if(__is_usermo(fo)) b->mop->free(*d._dp);
else free(*d._dp);
}
break;
default:
(void)va_arg(ap_copy, void *);
@ -552,6 +666,8 @@ uint32_t ndbuf_print_va(ndbuf_t *b, const char *fmt, int argc, va_list ap)
uint32_t len = 0, clen;
int r, count;
if(__ndbuf_is_ro(b)) return 0; /* read only buffer */
for(t = fmt, count = 0; *t != '\0'; t++, count++) {
if(count > argc && argc != -1) return 0;
switch(*t) {
@ -705,6 +821,8 @@ void ndbuf_setflags(ndbuf_t *b, int af)
{
if(!b) return;
if(((af & NDBUF_BURN) && (b->flags & NDBUF_UCMO)) && !b->mop->zero) return;
b->flags |= af;
return;
@ -715,6 +833,8 @@ void ndbuf_exflags(ndbuf_t *b, int nf)
{
if(!b) return;
if(b->flags & NDBUF_UCMO) nf |= NDBUF_UCMO;
b->flags = nf;
return;
@ -749,24 +869,43 @@ int ndbuf_cmp(ndbuf_t *b1, ndbuf_t *b2)
/* 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
* TODO: ? make this buffer non reallocable ?
*/
int ndbuf_memopt(ndbuf_t *b)
{
uint32_t len;
size_t bs = b->blk_size;
char *ne;
const struct ndbuf_memops *o = NULL;
if(!b || !b->raw) return EINVAL;
if((b->rlength - b->ulength) > DEFAULT_PREALLOC_SIZE) {
if((b->rlength - b->ulength) > bs) {
len = b->ulength +
(b->ulength%DEFAULT_PREALLOC_SIZE != 0 ?
(DEFAULT_PREALLOC_SIZE - b->ulength%DEFAULT_PREALLOC_SIZE) : 0);
if(!(ne = malloc(len))) return ENOMEM;
(b->ulength%bs != 0 ? (bs - b->ulength%bs) : 0);
if(b->flags & NDBUF_UCMO) o = b->mop;
if(o) ne = (char *)o->alloc(len);
else ne = malloc(len);
if(!ne) return ENOMEM;
if(b->flags & NDBUF_BURN) {
if(o) o->zero((void *)ne, len);
else memset(ne, 0, len);
}
if(b->flags & NDBUF_BURN) memset(ne, 0, len);
memcpy(ne, b->raw, b->ulength);
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->ulength);
free(b->raw);
if(o) {
if(b->flags & NDBUF_BURN) o->zero((void *)b->raw, b->rlength);
o->free((void *)b->raw);
} else {
if(b->flags & NDBUF_BURN) memset(b->raw, 0, b->rlength);
free(b->raw);
}
b->raw = ne;
b->rlength = len;
}
@ -774,4 +913,21 @@ int ndbuf_memopt(ndbuf_t *b)
return 0;
}
void ndbuf_free_item(ndbuf_t *b, void *ip, size_t is)
{
if(!b || !ip) return;
if(__is_moless(b->flags)) return;
if(__is_usermo(b->flags)) {
if((b->flags & NDBUF_BURN) && (is > 0)) b->mop->zero(ip, is);
b->mop->free(ip);
} else {
if((b->flags & NDBUF_BURN) && (is > 0)) memset(ip, 0, is);
free(ip);
}
return;
}
#undef DEFAULT_PREALLOC_SIZE