This is a byte stream implementation in C. Its usage and purpose should be evident from main.
Implementation is not finished; this is just start. Comments are still welcome.
.h:
#include <stdint.h>
typedef struct
{
uint8_t * data;
uint32_t length;
uint32_t offset;
} ByteStream;
int32_t BSInitWithSize(ByteStream *bs, uint32_t len);
uint32_t BSNrOfRemainingBytes(ByteStream *bs);
int32_t BSFreeUnderlyingArray(ByteStream *bs);
void BSPrintContents(ByteStream *bs);
void BSRewind(ByteStream *bs);
int32_t BSPutU8(ByteStream *bs, uint8_t v);
int32_t BSGetU8(ByteStream *bs, uint8_t *out);
int32_t BSPutU16LE(ByteStream *bs, uint16_t v);
.c:
#include "ByteStream.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int32_t BSInitWithSize(ByteStream *bs, uint32_t len)
{
if (NULL == bs)
return -1;
// Allocate data array of sufficient length
bs->data = (uint8_t*)malloc(len); // Note: Probably should check return value here
memset(bs->data,0,len); // set values to nil
bs->length = len;
bs->offset = 0;
return 0;
}
uint32_t BSNrOfRemainingBytes(ByteStream *bs)
{
return bs->length - bs->offset;
}
void BSRewind(ByteStream *bs)
{
bs->offset=0;
}
int32_t BSPutU8(ByteStream *bs, uint8_t v)
{
if(BSNrOfRemainingBytes(bs)<1)
return -1;
bs->data[bs->offset]=v;
bs->offset++;
return 0;
}
int32_t BSGetU8(ByteStream *bs, uint8_t *out)
{
if(BSNrOfRemainingBytes(bs)<1)
return -1;
bs->offset++;
*out= bs->data[bs->offset-1];
return 0;
}
int32_t BSPutU16LE(ByteStream *bs, uint16_t v)
{
if(BSNrOfRemainingBytes(bs)<2)
return -1;
// This code compiles on LE machine, so
// copying a integer to buffer will write
// the integer into the buffer in a little endian way
// exactly what this method is supposed to do
// Note: Probably this is not portable
memcpy(&bs->data[bs->offset],&v,2);
bs->offset+=2;
return 0;
}
void BSPrintContents(ByteStream *bs)
{
int i = 0;
for(i=0; i<bs->offset; i++)
{
printf("%02X ",bs->data[i]);
}
}
int32_t BSFreeUnderlyingArray(ByteStream *bs)
{
// Free underlying data array of BS object if it is not NULL
if(NULL != bs->data)
{
free(bs->data);
bs->data=NULL; // Set to NULL
return 0;
}
return -1;
}
main:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C"
{
#include "ByteStream.h"
}
int _tmain(int argc, _TCHAR* argv[])
{
ByteStream b;
memset(&b,0,sizeof(b));
// Init bs
BSInitWithSize(&b,14);
// Add values
for(int i=0;i<12;i++)
{
if(-1 == BSPutU8(&b, (uint8_t)i))
printf("Error putting data \n");
printf("Remaining Free Bytes: %d\n",BSNrOfRemainingBytes(&b));
}
// Rewind
printf("---\n");
BSRewind(&b);
// Print values
for(int i=0;i<12;i++)
{
uint8_t t;
if(-1 == BSGetU8(&b, &t))
{
printf("ERROR Getting value \n");
}
else
printf("Value at %d is %d \n", i, t);
}
// Put short integer in a little endian way
if(-1 == BSPutU16LE(&b,765))
printf("Error putting short \n");
BSPrintContents(&b);
// Free underlying buffer
BSFreeUnderlyingArray(&b);
return 0;
}
In many cases I decided to return error code from functions, and pass return values as out parameters.