// Written by retoor@molodetz.nl // A ring buffer implementation in C that provides functionalities such as // creating a new buffer, freeing, resetting, writing data, pushing data, // popping data, matching options and more. It efficiently manages dynamic // memory to handle data of varying sizes and applies basic buffer manipulation techniques. // This code includes the utility "rmalloc.h". It is assumed that this file // contains custom memory management functions which are not specified here. // MIT License // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #ifndef RBUFFER_H #define RBUFFER_H #include "rmalloc.h" #include #include #include #include #include typedef struct rbuffer_t { unsigned char *data; unsigned char *_data; size_t size; size_t pos; bool eof; } rbuffer_t; rbuffer_t *rbuffer_new(unsigned char *data, size_t size); void rbuffer_free(rbuffer_t *rfb); void rbuffer_reset(rbuffer_t *rfb); void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size); size_t rbuffer_push(rbuffer_t *rfb, unsigned char data); unsigned char rbuffer_pop(rbuffer_t *rfb); unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore); void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size); void rbuffer_set(rbuffer_t *rfb, const unsigned char *data, size_t size) { if (rfb->_data) { free(rfb->_data); rfb->_data = NULL; rfb->data = NULL; rfb->eof = true; } if (size) { rfb->_data = (unsigned char *)malloc(size); memcpy(rfb->_data, data, size); rfb->data = rfb->_data; rfb->eof = false; } rfb->size = size; rfb->pos = 0; } rbuffer_t *rbuffer_new(unsigned char *data, size_t size) { rbuffer_t *rfb = (rbuffer_t *)malloc(sizeof(rbuffer_t)); if (size) { rfb->_data = (unsigned char *)malloc(size); memcpy(rfb->_data, data, size); rfb->eof = false; } else { rfb->_data = NULL; rfb->eof = true; } rfb->size = size; rfb->pos = 0; rfb->data = rfb->_data; return rfb; } void rbuffer_free(rbuffer_t *rfb) { if (rfb->_data) { free(rfb->_data); } free(rfb); } size_t rbuffer_push(rbuffer_t *rfb, unsigned char data) { if (rfb->pos < rfb->size) { rfb->_data[rfb->pos++] = data; return 1; } rfb->_data = realloc(rfb->_data, rfb->size ? rfb->size + 1 : rfb->size + 2); rfb->_data[rfb->pos++] = data; rfb->size++; return rfb->pos; } void rbuffer_write(rbuffer_t *rfb, const unsigned char *data, size_t size) { for (size_t i = 0; i < size; i++) { rbuffer_push(rfb, data[i]); } } unsigned char rbuffer_peek(rbuffer_t *rfb) { if (rfb->pos != rfb->size) { return rfb->_data[rfb->pos]; } rfb->eof = true; return EOF; } unsigned char rbuffer_pop(rbuffer_t *rfb) { if (rfb->pos < rfb->size) { unsigned char result = rfb->_data[rfb->pos]; rfb->pos++; rfb->data++; if (rfb->pos == rfb->size) { rfb->eof = true; } return result; } rfb->eof = true; return EOF; } void rbuffer_reset(rbuffer_t *rfb) { rfb->data = rfb->_data; rfb->pos = 0; } unsigned char ustrncmp(const unsigned char *s1, const unsigned char *s2, size_t n) { return strncmp((const char *)s1, (const char *)s2, n); } size_t ustrlen(const unsigned char *s) { return strlen((const char *)s); } unsigned char *rbuffer_to_string(rbuffer_t *rfb) { unsigned char *result = rfb->_data; rfb->_data = NULL; rfb->data = NULL; rbuffer_free(rfb); return result; } unsigned char *rbuffer_match_option(rbuffer_t *rfb, char *options) { char *option = NULL; char options_cpy[1024] = {0}; strcpy(options_cpy, options); char *memory = options_cpy; while ((option = strtok_r(option == NULL ? memory : NULL, "|", &memory)) != NULL) { size_t option_length = strlen(option); if (option_length > rfb->size - rfb->pos) { continue; } if (!strcmp(option, "\\d") && *rfb->data >= '0' && *rfb->data <= '9') { return rfb->data; } if (rfb->size - rfb->pos >= 5 && !strcmp(option, "\\b") && ((!ustrncmp(rfb->data, (unsigned char *)"true", 4) || !ustrncmp(rfb->data, (unsigned char *)"false", 5)))) { return rfb->data; } if (!ustrncmp(rfb->data, (unsigned char *)option, option_length)) { return rfb->data; } } return NULL; } unsigned char *rbuffer_expect(rbuffer_t *rfb, char *options, char *ignore) { while (rfb->pos < rfb->size) { if (rbuffer_match_option(rfb, options) != NULL) { return rfb->data; } if (rbuffer_match_option(rfb, ignore)) { printf("SKIP:%s\n", rfb->data); rbuffer_pop(rfb); continue; } break; } return NULL; } unsigned char *rbuffer_consume(rbuffer_t *rfb, char *options, char *ignore) { unsigned char *result = NULL; if ((result = rbuffer_expect(rfb, options, ignore)) != NULL) { rbuffer_pop(rfb); } return result; } #endif