Implement buffer reader functions

This functionality allows us to read data out of a buffer without
irrevocably consuming it.  We read what we can, and when we're done we
throw the reader away.

The plan is to read as much of a stream of data as is available, and if
we can't read a complete message, we simply toss the reader away and
try again when we get more data.  I think that perhaps this strategy
might be easier than coming up with a state machine to parse the stream.

Please do not advance the underlying buffer while trying to use a
reader.
This commit is contained in:
Alex Mayfield 2017-02-15 21:11:19 -05:00
parent b5302fee81
commit 056cdff7ce
2 changed files with 118 additions and 7 deletions

View file

@ -121,22 +121,125 @@ void Buffer_Clear(buffer_t *buf)
}
//
// Create a new buffer reader
// Create a new buffer reader.
//
// WARNING: This reader will invalidate if the underlying buffer changes.
// Use it, then delete it before you touch the underlying buffer again.
//
buffer_reader_t *NewReader(buffer_t* buffer)
{
buffer_reader_t *reader = malloc(sizeof(buffer_reader_t));
reader->buffer = buffer;
reader->pos = 0;
reader->pos = buffer->data;
return reader;
}
//
// Delete a buffer reader
// Delete a buffer reader.
//
void DeleteReader(buffer_reader_t *reader)
{
free(reader);
}
//
// Count the number of bytes read thus far.
//
int Reader_BytesRead(buffer_reader_t *reader)
{
return reader->pos - reader->buffer->data;
}
//
// Read an unsigned byte from a buffer.
//
boolean Reader_ReadInt8(buffer_reader_t *reader, uint8_t *out)
{
byte *data, *data_end;
int len = Buffer_Data(reader->buffer, &data);
data_end = data + len;
if (data_end - reader->pos < 1)
{
return false;
}
*out = (uint8_t)*reader->pos;
reader->pos += 1;
return true;
}
//
// Read an unsigned short from a buffer.
//
boolean Reader_ReadInt16(buffer_reader_t *reader, uint16_t *out)
{
byte *data, *data_end, *dp;
int len = Buffer_Data(reader->buffer, &data);
data_end = data + len;
dp = reader->pos;
if (data_end - reader->pos < 2)
{
return false;
}
*out = (uint16_t)((dp[0] << 8) | dp[1]);
reader->pos += 2;
return true;
}
//
// Read an unsigned int from a buffer.
//
boolean Reader_ReadInt32(buffer_reader_t *reader, uint32_t *out)
{
byte *data, *data_end, *dp;
int len = Buffer_Data(reader->buffer, &data);
data_end = data + len;
dp = reader->pos;
if (data_end - reader->pos < 4)
{
return false;
}
*out = (uint32_t)((dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3]);
reader->pos += 4;
return true;
}
//
// Read a string from a buffer.
//
char *Reader_ReadString(buffer_reader_t *reader)
{
byte *data, *data_start, *data_end, *dp;
int len = Buffer_Data(reader->buffer, &data);
data_start = reader->pos;
data_end = data + len;
dp = reader->pos;
while (dp < data_end && *dp != '\0')
{
dp++;
}
if (dp >= data_end)
{
// Didn't see a null terminator, not a complete string.
return NULL;
}
reader->pos = dp + 1;
return (char*)data_start;
}

View file

@ -32,7 +32,7 @@ typedef struct {
typedef struct {
buffer_t *buffer;
int pos;
byte *pos;
} buffer_reader_t;
buffer_t *NewBuffer();
@ -42,5 +42,13 @@ boolean Buffer_Push(buffer_t *buf, const void *data, int len);
void Buffer_Shift(buffer_t *buf, int len);
void Buffer_Clear(buffer_t *buf);
buffer_reader_t *NewReader(buffer_t* buffer);
void DeleteReader(buffer_reader_t *reader);
int Reader_BytesRead(buffer_reader_t *reader);
boolean Reader_ReadInt8(buffer_reader_t *reader, uint8_t *out);
boolean Reader_ReadInt16(buffer_reader_t *reader, uint16_t *out);
boolean Reader_ReadInt32(buffer_reader_t *reader, uint32_t *out);
char *Reader_ReadString(buffer_reader_t *reader);
#endif