mirror of
https://github.com/faye/websocket-driver-ruby.git
synced 2025-11-01 13:59:38 +00:00
117 lines
2.5 KiB
C
117 lines
2.5 KiB
C
#include "read_buffer.h"
|
|
|
|
|
|
struct wsd_Chunk {
|
|
uint64_t length;
|
|
uint8_t *data;
|
|
};
|
|
|
|
wsd_Chunk *wsd_Chunk_create(uint64_t length, uint8_t *data)
|
|
{
|
|
wsd_Chunk *chunk = calloc(1, sizeof(wsd_Chunk));
|
|
if (chunk == NULL) return NULL;
|
|
|
|
chunk->data = calloc(length, sizeof(uint8_t));
|
|
if (chunk->data == NULL) {
|
|
free(chunk);
|
|
return NULL;
|
|
}
|
|
|
|
chunk->length = length;
|
|
memcpy(chunk->data, data, length);
|
|
|
|
return chunk;
|
|
}
|
|
|
|
void wsd_Chunk_destroy(wsd_Chunk *chunk)
|
|
{
|
|
if (chunk == NULL) return;
|
|
|
|
wsd_clear_pointer(free, chunk->data);
|
|
|
|
free(chunk);
|
|
}
|
|
|
|
|
|
struct wsd_ReadBuffer {
|
|
wsd_Queue *queue;
|
|
uint64_t capacity;
|
|
uint64_t cursor;
|
|
};
|
|
|
|
wsd_ReadBuffer *wsd_ReadBuffer_create()
|
|
{
|
|
wsd_ReadBuffer *buffer = calloc(1, sizeof(wsd_ReadBuffer));
|
|
if (buffer == NULL) return NULL;
|
|
|
|
buffer->queue = wsd_Queue_create();
|
|
if (buffer->queue == NULL) {
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
buffer->capacity = 0;
|
|
buffer->cursor = 0;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void wsd_ReadBuffer_destroy(wsd_ReadBuffer *buffer)
|
|
{
|
|
if (buffer == NULL) return;
|
|
|
|
wsd_Queue_each(buffer->queue, (wsd_Queue_cb)wsd_Chunk_destroy);
|
|
|
|
wsd_clear_pointer(wsd_Queue_destroy, buffer->queue);
|
|
|
|
free(buffer);
|
|
}
|
|
|
|
uint64_t wsd_ReadBuffer_push(wsd_ReadBuffer *buffer, uint64_t length, uint8_t *data)
|
|
{
|
|
wsd_Chunk *chunk = wsd_Chunk_create(length, data);
|
|
if (chunk == NULL) return 0;
|
|
|
|
if (wsd_Queue_push(buffer->queue, chunk) != 1) {
|
|
wsd_Chunk_destroy(chunk);
|
|
return 0;
|
|
}
|
|
|
|
buffer->capacity += length;
|
|
return length;
|
|
}
|
|
|
|
int wsd_ReadBuffer_has_capacity(wsd_ReadBuffer *buffer, uint64_t length)
|
|
{
|
|
return buffer->capacity >= length;
|
|
}
|
|
|
|
uint64_t wsd_ReadBuffer_read(wsd_ReadBuffer *buffer, uint64_t length, uint8_t *target)
|
|
{
|
|
uint64_t offset = 0;
|
|
|
|
if (buffer->capacity < length) return 0;
|
|
|
|
while (offset < length) {
|
|
wsd_Chunk *chunk = wsd_Queue_peek(buffer->queue);
|
|
|
|
uint64_t available = chunk->length - buffer->cursor;
|
|
uint64_t required = length - offset;
|
|
uint64_t take_bytes = (available < required) ? available : required;
|
|
|
|
memcpy(target + offset, chunk->data + buffer->cursor, take_bytes);
|
|
offset += take_bytes;
|
|
|
|
if (take_bytes == available) {
|
|
buffer->cursor = 0;
|
|
wsd_Chunk_destroy(chunk);
|
|
wsd_Queue_shift(buffer->queue);
|
|
} else {
|
|
buffer->cursor += take_bytes;
|
|
}
|
|
}
|
|
|
|
buffer->capacity -= length;
|
|
return length;
|
|
}
|