BUFFER

Flexible buffer management, idea from openssh/buffer.c. More...

Functions

Bufferbuffer_new (size_t blocksize, char *name)
 Create a new buffer. More...
 
Bufferbuffer_new_str (char *name)
 Create a new string buffer. More...
 
Bufferbuffer_new_buf (char *name, void *data, size_t datasize)
 Create a new buffer from existing data. More...
 
void buffer_free (Buffer *b)
 Clears and frees the Buffer. More...
 
void buffer_clear (Buffer *b)
 Clears the Buffer. More...
 
void buffer_rewind (Buffer *b)
 Put read offset back to start. More...
 
void buffer_add (Buffer *b, const void *data, size_t len)
 Add data to the buffer. More...
 
void buffer_add_buf (Buffer *dst, Buffer *src)
 Add data to the buffer. More...
 
void buffer_add_str (Buffer *b, const char *fmt,...)
 Add a formated string to the buffer. More...
 
void buffer_add_hex (Buffer *b, void *data, size_t len)
 Add data as hex string to the buffer. More...
 
int buffer_done (Buffer *b)
 Tell if there are no more bytes to read. More...
 
size_t buffer_get_chunk (Buffer *b, void *buf, size_t len)
 Read some chunk of data from the Buffer. More...
 
size_t buffer_get_chunk_tobuf (Buffer *b, Buffer *dst, size_t len)
 Read some chunk of data from the Buffer and add to another Buffer. More...
 
byte * buffer_get (Buffer *b)
 Read the whole Buffer content. More...
 
char * buffer_get_str (Buffer *b)
 Read the whole Buffer content as string. More...
 
byte * buffer_get_remainder (Buffer *b)
 Read the remaining data after current read offset. More...
 
size_t buffer_extract (Buffer *b, void *buf, size_t offset, size_t len)
 Read some data inside the Buffer. More...
 
size_t buffer_fwd_offset (Buffer *b, size_t fwdby)
 Forward read offset of given buffer. More...
 
void buffer_dump (const Buffer *b)
 Dump the Buffer contents to stderr in hex form. More...
 
void buffer_info (const Buffer *b)
 Print Buffer counters to stderr. More...
 
size_t buffer_size (const Buffer *b)
 Tell how much data there is in the buffer available. More...
 
size_t buffer_left (const Buffer *b)
 Tell how much data is left to read in the Buffer. More...
 
uint8_t buffer_get8 (Buffer *b)
 Read 1 byte (8 bit) number from a Buffer. More...
 
uint16_t buffer_get16 (Buffer *b)
 Read 2 bytes (16 bit) number from a Buffer. More...
 
uint32_t buffer_get32 (Buffer *b)
 Read 4 byte (32 bit) number from a Buffer. More...
 
uint64_t buffer_get64 (Buffer *b)
 Read 8 byte (64 bit) from a Buffer. More...
 
uint16_t buffer_get16na (Buffer *b)
 Read 2 bytes (16 bit) number from a Buffer, converted to host endian. More...
 
uint32_t buffer_get32na (Buffer *b)
 Read 4 byte (32 bit) number from a Buffer, converted to host endian. More...
 
uint64_t buffer_get64na (Buffer *b)
 Read 8 byte (64 bit) from a Buffer, converted to host endian. More...
 
uint8_t buffer_last8 (Buffer *b)
 Read the last 1 byte (8 bit) number from a Buffer. More...
 
uint16_t buffer_last16 (Buffer *b)
 Read the last 2 byte (16 bit) number from a Buffer. More...
 
uint32_t buffer_last32 (Buffer *b)
 Read the last 4 byte (32 bit) number from a Buffer. More...
 
uint64_t buffer_last64 (Buffer *b)
 Read the last 8 byte (64 bit) number from a Buffer. More...
 
size_t buffer_fd_read (Buffer *b, FILE *in, size_t len)
 Read data from a file directly into a Buffer. More...
 
void buffer_add8 (Buffer *b, uint8_t v)
 Write a 1 byte (8 bit) number in binary form into the buffer. More...
 
void buffer_add16 (Buffer *b, uint16_t v)
 Write a 2 byte (16 bit) number in binary form into the buffer. More...
 
void buffer_add32 (Buffer *b, uint32_t v)
 Write a 4 byte (32 bit) number in binary form into the buffer. More...
 
void buffer_add64 (Buffer *b, uint64_t v)
 Write a 8 byte (64 bit) number in binary form into the buffer. More...
 
void buffer_add16be (Buffer *b, uint16_t v)
 Write a 2 byte (16 bit) number in binary form into the buffer, converted to big endian. More...
 
void buffer_add32be (Buffer *b, uint32_t v)
 Write a 4 byte (32 bit) number in binary form into the buffer, converted to big endian. More...
 
void buffer_add64be (Buffer *b, uint64_t v)
 Write a 8 byte (64 bit) number in binary form into the buffer, converted to big endian. More...
 

Detailed Description

Flexible buffer management, idea from openssh/buffer.c.

This class allows us to dissect buffers into parts at will whithout the hassle of boundary checking in each and every line. Therefore it is more secure, since this system wraps all this stuff from us, so in case we're attemt to overflow a buffer or the like, the buffer functions will catch this, warn us and die.

Function Documentation

void buffer_add ( Buffer b,
const void *  data,
size_t  len 
)

Add data to the buffer.

Adds data of the size len to the buffer and resizes the buffer, if neccessary. The write position ('end' field) will be updated accordingly.

Data will be copied, you can free() the given pointer after copying..

Parameters
[in]bThe Buffer object.
[out]dataArbitrary data to add to the Buffer.
[in]lenThe size of the data to add in Bytes.
void buffer_add16 ( Buffer b,
uint16_t  v 
)

Write a 2 byte (16 bit) number in binary form into the buffer.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint16_t to write to the buffer.
void buffer_add16be ( Buffer b,
uint16_t  v 
)

Write a 2 byte (16 bit) number in binary form into the buffer, converted to big endian.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint16_t to write to the buffer.
void buffer_add32 ( Buffer b,
uint32_t  v 
)

Write a 4 byte (32 bit) number in binary form into the buffer.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint32_t to write to the buffer.
void buffer_add32be ( Buffer b,
uint32_t  v 
)

Write a 4 byte (32 bit) number in binary form into the buffer, converted to big endian.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint32_t to write to the buffer.
void buffer_add64 ( Buffer b,
uint64_t  v 
)

Write a 8 byte (64 bit) number in binary form into the buffer.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint64_t to write to the buffer.
void buffer_add64be ( Buffer b,
uint64_t  v 
)

Write a 8 byte (64 bit) number in binary form into the buffer, converted to big endian.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint64_t to write to the buffer.
void buffer_add8 ( Buffer b,
uint8_t  v 
)

Write a 1 byte (8 bit) number in binary form into the buffer.

Parameters
[out]bThe Buffer object to write to.
[in]vThe uint8_t to write to the buffer.
void buffer_add_buf ( Buffer dst,
Buffer src 
)

Add data to the buffer.

Adds data from the given Buffer src to the buffer and resizes the buffer, if neccessary. The write position ('end' field) will be updated accordingly.

Data will be copied, you can buffer_free() the given src Buffer after the copying.

Parameters
[out]dstThe destination Buffer object to copy data into.
[in]srcThe source Buffer object to copy data from.
void buffer_add_hex ( Buffer b,
void *  data,
size_t  len 
)

Add data as hex string to the buffer.

Adds data of the size len to the buffer and resizes the buffer, if neccessary. The write position ('end' field) will be updated accordingly. Each byte will be put in its HEX form into the buffer (%02x).

Data will be copied, you can free() the given pointer after copying..

Parameters
[in]bThe Buffer object.
[in]dataArbitrary data to add as hex into the Buffer.
[in]lenThe size of the data to add in Bytes.
void buffer_add_str ( Buffer b,
const char *  fmt,
  ... 
)

Add a formated string to the buffer.

Use printf() like syntax to add a formatted string to the buffer. Refer to the documentation of printf() for details.

Data will be copied, you can free() the given format string and params after copying.

Example:

Buffer *x = buffer_new_str("test");
buffer_add_str(x, "There are %d elements left in %s\n", 4, "list");
Parameters
[in]bThe Buffer object.
[in]fmtThe printf() compatible format description.
[in]...A variable number of arguments for the format string.
void buffer_clear ( Buffer b)

Clears the Buffer.

This clears the buffer by filling it with zeroes and resetting all counters. Memory will not be free'd. Called from buffer_free() before free'ing memory.

Parameters
[in]bThe Buffer object.
int buffer_done ( Buffer b)

Tell if there are no more bytes to read.

This functions tells if the EOF of the buffer is reached during read operations (no more data to read left).

Parameters
[in]bThe Buffer object.
Returns
Returns 1 of EOF has been reached or 0 if there are more data left to read.
void buffer_dump ( const Buffer b)

Dump the Buffer contents to stderr in hex form.

Parameters
[in]bThe Buffer object to dump.
size_t buffer_extract ( Buffer b,
void *  buf,
size_t  offset,
size_t  len 
)

Read some data inside the Buffer.

Same as buffer_get() but fetch some data chunk from somewhere in the middle of the buffer.

The returned pointer has to be allocated by the caller to at least a size of len bytes.

The read offset will be left untouched by this function.

Example: suppose you've got a buffer with the following content:

AAAABBBBCCCC

Then:

[..]
byte g[4];
buffer_extract(b, g, 4, 4); // => g now contains 'BBBB'
Parameters
[in]bThe Buffer object to read from.
[out]bufThe buffer to copy data to.
[in]offsetWhere to start copying.
[in]lenHow mush data to copy.
Returns
Returns the size of bytes read. Returns 0 in case of an overflow, which can be catched with fatals_ifany().
size_t buffer_fd_read ( Buffer b,
FILE *  in,
size_t  len 
)

Read data from a file directly into a Buffer.

This function reads in len bytes from the FILE stream 'in' into the Buffer. The file must already be opened by the caller.

Parameters
[in,out]bThe Buffer object to read from.
[in]inThe FILE stream to read from.
[in]lenThe number of bytes to read.
Returns
Returns the number of bytes read or 0 in case of an error or EOF. Use feof() and ferror() to check this afterwards.
void buffer_free ( Buffer b)

Clears and frees the Buffer.

This clears the buffer by filling it with zeroes and frees any allocated memory, including the Buffer object itself. Use this function instead of directly calling free(Buffer).

Parameters
[in]bThe Buffer object.
size_t buffer_fwd_offset ( Buffer b,
size_t  fwdby 
)

Forward read offset of given buffer.

Use to ignore a couple of bytes.

Parameters
[in]bThe Buffer object to read from.
[in]fwdbyBytes to forward read offset.
Returns
Returns the size of bytes forwarded. Returns 0 in case of an overflow, which can be catched with fatals_ifany().
byte* buffer_get ( Buffer b)

Read the whole Buffer content.

This function returns the whole buffer contents as a pointer to the internal data member (Buffer->buf). The returned pointer is allocated and filled with data up to buffer_size(Buffer), however, the allocated memory might be more than size, in fact it will be a multitude of Buffer-blocksize.

Don't free() the pointer directly, use buffer_free() always.

Parameters
[in]bThe Buffer object to read from.
Returns
Pointer to the buffer data storage.
uint16_t buffer_get16 ( Buffer b)

Read 2 bytes (16 bit) number from a Buffer.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint16_t.
uint16_t buffer_get16na ( Buffer b)

Read 2 bytes (16 bit) number from a Buffer, converted to host endian.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint16_t.
uint32_t buffer_get32 ( Buffer b)

Read 4 byte (32 bit) number from a Buffer.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint32_t.
uint32_t buffer_get32na ( Buffer b)

Read 4 byte (32 bit) number from a Buffer, converted to host endian.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint32_t.
uint64_t buffer_get64 ( Buffer b)

Read 8 byte (64 bit) from a Buffer.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint64_t.
uint64_t buffer_get64na ( Buffer b)

Read 8 byte (64 bit) from a Buffer, converted to host endian.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint64_t.
uint8_t buffer_get8 ( Buffer b)

Read 1 byte (8 bit) number from a Buffer.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint8_t.
size_t buffer_get_chunk ( Buffer b,
void *  buf,
size_t  len 
)

Read some chunk of data from the Buffer.

Read some chunk of data from the Buffer, starting from current read offset til len.

Example: suppose you've got a buffer with the following content:

AAAABBBBCCCC

Then the following code would:

byte g[4];
buffer_get_chunk(b, g, 4); // => g now contains 'AAAA'
buffer_get_chunk(b, g, 4); // => g now contains 'BBBB'
buffer_get_chunk(b, g, 4); // => g now contains 'CCCC'

In order to catch buffer overflow, check the return value, which will be 0 in case of errors. See also: fatals_ifany(), buffer_done() and buffer_left().

Parameters
[in]bThe Buffer object to read from.
[out]bufThe destination pointer where the data will be copied to. This pointer must be allocated by the caller properly and it must have at least a size of len.
[in]lenThe number of bytes to read from the Buffer.
Returns
Returns the size of bytes read, 0 in case an error occurred.
size_t buffer_get_chunk_tobuf ( Buffer b,
Buffer dst,
size_t  len 
)

Read some chunk of data from the Buffer and add to another Buffer.

Works identical to buffer_get_chunk() but copies the requested chunk directly into the Buffer dst, which will be resized properly if needed.

Parameters
[in]bThe Buffer object to read from.
[out]dstThe Buffer object to write to.
[in]lenThe number of bytes to read from the Buffer.
Returns
Returns the size of bytes read, 0 in case an error occurred.
byte* buffer_get_remainder ( Buffer b)

Read the remaining data after current read offset.

Fetch whatever is left in the buffer. This works like buffer_get() but instead doesn't return everything, but only the part of the buffer, which follows after the current read offset.

The returned pointer will be allocated by buffer_get_remainder() with a size of buffer_left(). It's up to the caller to free() the returned pointer later on.

Example: suppose you've got a buffer with the following content:

AAAABBBBCCCC

Then:

[..]
byte g[4];
byte *r = NULL;
buffer_get_chunk(b, g, 4); // => g now contains 'AAAA'
size_t rs = buffer_left(b); // => rs = 8
r = buffer_get_remainder(b); // => r now contains 'BBBBCCCC' and has a size of 8
memset(r, 0, rs); // zerofill r
free(r); // done with it
Parameters
[in]bThe Buffer object to read from.
Returns
Pointer to the remaining chunk of data (copy).
char* buffer_get_str ( Buffer b)

Read the whole Buffer content as string.

Access the Buffer content as string (char *).

The returned pointer is allocated and filled with data up to buffer_size(Buffer), however, the allocated memory might be more than size, in fact it will be a multitude of Buffer-blocksize.

The byte after buffer_size(Buffer) will be a \0.

Don't free() the pointer directly, use buffer_free() always.

Sample usage:

[..]
fprintf(stdout, "Our buffer content: %s\n", buffer_get_str(b));
Parameters
[in]bThe Buffer object to read from.
Returns
Pointer to the buffer data storage.
void buffer_info ( const Buffer b)

Print Buffer counters to stderr.

Parameters
[in]bThe Buffer object to print infos about.
uint16_t buffer_last16 ( Buffer b)

Read the last 2 byte (16 bit) number from a Buffer.

Doesn't increment offset.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint16_t.
uint32_t buffer_last32 ( Buffer b)

Read the last 4 byte (32 bit) number from a Buffer.

Doesn't increment offset.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint32_t.
uint64_t buffer_last64 ( Buffer b)

Read the last 8 byte (64 bit) number from a Buffer.

Doesn't increment offset.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint64_t.
uint8_t buffer_last8 ( Buffer b)

Read the last 1 byte (8 bit) number from a Buffer.

Doesn't increment offset.

Parameters
[in]bThe Buffer object to read from.
Returns
a uint8_t.
size_t buffer_left ( const Buffer b)

Tell how much data is left to read in the Buffer.

Use this function to check if it's ok to read more bytes from to buffer to avoid buffer overflows.

Example: suppose you've got a buffer with the following content:

AAAABBBBCCCC

Then:

[..]
byte g[4];
byte x[16];
buffer_get_chunk(b, g, 4); // => g now contains 'BBBB'
if(buffer_left(b) >= 16) // => will return 8 and therefore fail
buffer_get_chunk(b, x, 16);
else
printf("not enough data"); // => will be printed
Parameters
[in]bThe Buffer object to get the size from.
Returns
The number of bytes left to read from the Buffer.
Buffer* buffer_new ( size_t  blocksize,
char *  name 
)

Create a new buffer.

Create a new buffer, initially alloc'd to blocksize and zero-filled.

Parameters
[in]blocksizeInitial blocksize. The smaller the more often the buffer will be resized. Choose with care.
[in]nameA name for the Buffer. Just used for debugging purposes or in error messages.
Returns
Returns a new Buffer object.
Buffer* buffer_new_buf ( char *  name,
void *  data,
size_t  datasize 
)

Create a new buffer from existing data.

Create a new buffer, but don't allocate memory nor copy data. Instead the provided data pointer will be used as internal storage directly.

This kind of buffer can be used to put the Buffer API into use with existing data from other sources. In most cases you'll use it for reading. However, please be aware, that it can be used for writing as well and in this case the data pointer maybe resized (by calling realloc()).

When calling buffer_free() on this Buffer, the memory pointed to by the given data pointer will not be free'd and remains accessible. It's the responsibility of the caller to do so.

Example using mmap(2):

#include <stdio.h>
#include <pcp.h>
#include <sys/mman.h>
FILE *RFD;
size_t rs;
Buffer *rb;
byte *chunk;
void *r;
if((RFD = fopen("README", "rb")) == NULL) {
fprintf(stderr, "oops, could not open README!\n");
return 1;
}
fseek(RFD, 0, SEEK_END);
rs = ftell(RFD);
fseek(RFD, 0, SEEK_SET);
void *r = mmap(NULL, rs, PROT_READ, 0, fileno(RFD), 0);
*rb = buffer_new_buf("r", r, rs);
size_t blocksize = 36;
void *chunk = malloc(blocksize);
while(buffer_done(rb) != 1) {
if(buffer_left(rb) < blocksize)
blocksize = buffer_left(rb);
buffer_get_chunk(rb, chunk, blocksize);
_dump("chunk", chunk, blocksize); // or do something else with it
}
munmap(r, rs);
fclose(RFD);
Parameters
[in]nameA name for the Buffer. Just used for debugging purposes or in error messages.
[in]dataThe data pointer to use by the buffer.
[in]datasizeThe size of the data.
Returns
Returns a new Buffer object.
Buffer* buffer_new_str ( char *  name)

Create a new string buffer.

Create a new buffer, initially alloc'd to a blocksize of 32 bytes and zero-filled. The buffer will be a string buffer. See buffer_get_str().

Parameters
[in]nameA name for the Buffer. Just used for debugging purposes or in error messages.
Returns
Returns a new Buffer object.
void buffer_rewind ( Buffer b)

Put read offset back to start.

This function sets the read offset counter back to 0 (start of the buffer).

Parameters
[in]bThe Buffer object.
size_t buffer_size ( const Buffer b)

Tell how much data there is in the buffer available.

This function returns the number of bytes stored in the buffer so far. Please note, that the actual allocation might be bigger, because we always allocate memory blockwise.

Parameters
[in]bThe Buffer object to get the size from.
Returns
The number of bytes stored in the Buffer.