1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-09-22 04:15:54 -04:00

Feature: Added a very basic module to build strings from individual parts

This commit is contained in:
Philipp Schafft 2022-09-17 12:45:39 +00:00
parent 167f626dcd
commit c4edf52ef8
4 changed files with 337 additions and 0 deletions

View File

@ -135,6 +135,10 @@ typedef struct hmac_tag hmac_t;
typedef struct mount_identifier_tag mount_identifier_t;
/* ---[ string_renderer.[ch] ]--- */
typedef struct string_renderer_tag string_renderer_t;
/* ---[ refobject.[ch] ]--- */
typedef struct refobject_base_tag refobject_base_t;
@ -157,6 +161,7 @@ typedef void * refobject_t;
/* --- [ For libigloo ]--- */
#define igloo_RO_APPTYPES \
igloo_RO_TYPE(string_renderer_t) \
igloo_RO_TYPE(module_t) \
igloo_RO_TYPE(module_container_t)

280
src/string_renderer.c Normal file
View File

@ -0,0 +1,280 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2022 , Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "icecasttypes.h"
#include <igloo/ro.h>
#include <igloo/error.h>
#include "string_renderer.h"
#include "util.h"
#include "logging.h"
#define CATMODULE "string-renderer"
struct string_renderer_tag {
igloo_ro_full_t __parent;
/* config */
const char *record_separator;
const char *kv_separator;
bool allow_null_key;
bool allow_null_value;
string_renderer_encoding_t encoding;
/* state */
bool list_start;
char *buffer;
size_t fill;
size_t len;
};
static void __string_renderer_free(igloo_ro_t self)
{
string_renderer_t *renderer = igloo_ro_to_type(self, string_renderer_t);
free(renderer->buffer);
}
static igloo_error_t __string_renderer_new(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap)
{
string_renderer_t *renderer = igloo_ro_to_type(self, string_renderer_t);
renderer->list_start = false;
renderer->record_separator = ", ";
renderer->kv_separator = "=";
renderer->allow_null_key = true;
renderer->allow_null_value = true;
renderer->encoding = STRING_RENDERER_ENCODING_PLAIN;
return igloo_ERROR_NONE;
}
igloo_RO_PUBLIC_TYPE(string_renderer_t, igloo_ro_full_t,
igloo_RO_TYPEDECL_FREE(__string_renderer_free),
igloo_RO_TYPEDECL_NEW(__string_renderer_new)
);
static igloo_error_t string_renderer_append_raw(string_renderer_t *self, const char *string, ssize_t len)
{
if (len < 0)
len = strlen(string);
if (self->len < (self->fill + len + 1)) {
size_t new_len = self->len + len + 1 + 64; /* allocate more than we need to avoid re-allocating every time */
char *n = realloc(self->buffer, new_len);
if (!n)
return igloo_ERROR_NOMEM;
self->buffer = n;
self->len = new_len;
}
memcpy(self->buffer + self->fill, string, len);
self->fill += len;
return igloo_ERROR_NONE;
}
igloo_error_t string_renderer_start_list(string_renderer_t *self, const char *record_separator, const char *kv_separator, bool allow_null_key, bool allow_null_value, string_renderer_encoding_t encoding)
{
if (!self)
return igloo_ERROR_FAULT;
self->list_start = true;
self->record_separator = record_separator;
self->kv_separator = kv_separator;
self->allow_null_key = allow_null_key;
self->allow_null_value = allow_null_value;
if (encoding != STRING_RENDERER_ENCODING_DEFAULT) {
self->encoding = encoding;
}
return igloo_ERROR_NONE;
}
igloo_error_t string_renderer_end_list(string_renderer_t *self)
{
/* no-op */
return igloo_ERROR_NONE;
}
igloo_error_t string_renderer_add_string_with_options(string_renderer_t *self, const char *string, bool allow_null, string_renderer_encoding_t encoding)
{
if (!self)
return igloo_ERROR_FAULT;
if (!string && !allow_null) {
return igloo_ERROR_INVAL;
}
if (encoding == STRING_RENDERER_ENCODING_DEFAULT) {
encoding = self->encoding;
}
switch (encoding) {
case STRING_RENDERER_ENCODING_PLAIN:
if (!string)
return igloo_ERROR_NONE;
return string_renderer_append_raw(self, string, -1);
break;
case STRING_RENDERER_ENCODING_URI:
if (!string) {
return igloo_ERROR_NONE;
} else {
char *x = util_url_escape(string);
igloo_error_t err;
if (!x)
return igloo_ERROR_NOMEM;
err = string_renderer_append_raw(self, x, -1);
free(x);
return err;
}
break;
default:
return igloo_ERROR_INVAL;
}
/* this should never be reached */
return igloo_ERROR_GENERIC;
}
igloo_error_t string_renderer_add_int_with_options(string_renderer_t *self, long long int val, bool allow_zero, bool allow_negative, string_renderer_encoding_t encoding)
{
if (!self)
return igloo_ERROR_FAULT;
if (val == 0 && !allow_zero) {
return igloo_ERROR_INVAL;
}
if (val < 0 && !allow_negative) {
return igloo_ERROR_INVAL;
}
if (encoding == STRING_RENDERER_ENCODING_DEFAULT) {
encoding = self->encoding;
}
switch (encoding) {
case STRING_RENDERER_ENCODING_PLAIN:
case STRING_RENDERER_ENCODING_URI:
{
char buffer[64];
int ret = snprintf(buffer, sizeof(buffer), "%lli", val);
if (ret < 1 || ret > (int)sizeof(buffer))
return igloo_ERROR_GENERIC;
return string_renderer_append_raw(self, buffer, ret);
}
break;
default:
return igloo_ERROR_INVAL;
}
/* this should never be reached */
return igloo_ERROR_GENERIC;
}
static igloo_error_t string_renderer_add_kv_key_only(string_renderer_t *self, const char *key, string_renderer_encoding_t encoding)
{
if (!self)
return igloo_ERROR_FAULT;
if (!key && !self->allow_null_key) {
return igloo_ERROR_INVAL;
}
if (encoding == STRING_RENDERER_ENCODING_DEFAULT) {
encoding = self->encoding;
}
if (self->list_start) {
self->list_start = false;
} else {
igloo_error_t err = string_renderer_append_raw(self, self->record_separator, -1);
if (err != igloo_ERROR_NONE)
return err;
}
return string_renderer_add_string_with_options(self, key, true, encoding);
}
igloo_error_t string_renderer_add_kv_with_options(string_renderer_t *self, const char *key, const char *value, string_renderer_encoding_t key_encoding, bool allow_null_value, bool allow_empty_value)
{
igloo_error_t err;
if (!self)
return igloo_ERROR_FAULT;
if (!value && !allow_null_value && !self->allow_null_value) {
return igloo_ERROR_INVAL;
}
if (value && !*value && !allow_empty_value) {
return igloo_ERROR_INVAL;
}
err = string_renderer_add_kv_key_only(self, key, key_encoding);
if (err != igloo_ERROR_NONE)
return err;
err = string_renderer_append_raw(self, self->kv_separator, -1);
if (err != igloo_ERROR_NONE)
return err;
return string_renderer_add_string_with_options(self, value, allow_null_value, STRING_RENDERER_ENCODING_DEFAULT);
}
igloo_error_t string_renderer_add_ki_with_options(string_renderer_t *self, const char *key, long long int value, string_renderer_encoding_t key_encoding, bool allow_zero, bool allow_negative)
{
igloo_error_t err;
if (!self)
return igloo_ERROR_FAULT;
if (value == 0 && !allow_zero) {
return igloo_ERROR_INVAL;
}
if (value < 0 && !allow_negative) {
return igloo_ERROR_INVAL;
}
err = string_renderer_add_kv_key_only(self, key, key_encoding);
if (err != igloo_ERROR_NONE)
return err;
err = string_renderer_append_raw(self, self->kv_separator, -1);
if (err != igloo_ERROR_NONE)
return err;
return string_renderer_add_int_with_options(self, value, allow_zero, allow_negative, STRING_RENDERER_ENCODING_DEFAULT);
}
const char * string_renderer_to_string_zero_copy(string_renderer_t *self)
{
if (!self)
return NULL;
/* add a \0 to the end */
if (string_renderer_append_raw(self, "\0", 1) != igloo_ERROR_NONE)
return NULL;
/* but do not count it as fill */
self->fill--;
return self->buffer;
}

46
src/string_renderer.h Normal file
View File

@ -0,0 +1,46 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2022 , Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __STRING_RENDERER_H__
#define __STRING_RENDERER_H__
#include <stdbool.h>
#include <igloo/typedef.h>
#include <igloo/error.h>
#include "icecasttypes.h"
igloo_RO_FORWARD_TYPE(string_renderer_t);
typedef enum {
STRING_RENDERER_ENCODING_DEFAULT,
STRING_RENDERER_ENCODING_PLAIN,
STRING_RENDERER_ENCODING_URI
} string_renderer_encoding_t;
/* all functions are NOT thread safe */
igloo_error_t string_renderer_start_list(string_renderer_t *self, const char *record_separator, const char *kv_separator, bool allow_null_key, bool allow_null_value, string_renderer_encoding_t encoding);
#define string_renderer_start_list_formdata(self) string_renderer_start_list((self), "&", "=", false, true, STRING_RENDERER_ENCODING_URI)
igloo_error_t string_renderer_end_list(string_renderer_t *self);
igloo_error_t string_renderer_add_string_with_options(string_renderer_t *self, const char *string, bool allow_null, string_renderer_encoding_t encoding);
#define string_renderer_add_string(self,string) string_renderer_add_string_with_options((self), (string), false, STRING_RENDERER_ENCODING_PLAIN)
igloo_error_t string_renderer_add_int_with_options(string_renderer_t *self, long long int val, bool allow_zero, bool allow_negative, string_renderer_encoding_t encoding);
#define string_renderer_add_int(self,val) string_renderer_add_int_with_options((self), (val), true, true, STRING_RENDERER_ENCODING_PLAIN)
igloo_error_t string_renderer_add_kv_with_options(string_renderer_t *self, const char *key, const char *value, string_renderer_encoding_t key_encoding, bool allow_null_value, bool allow_empty_value);
#define string_renderer_add_kv(self,key,value) string_renderer_add_kv_with_options((self), (key), (value), STRING_RENDERER_ENCODING_DEFAULT, true, true)
igloo_error_t string_renderer_add_ki_with_options(string_renderer_t *self, const char *key, long long int value, string_renderer_encoding_t key_encoding, bool allow_zero, bool allow_negative);
#define string_renderer_add_ki(self,key,value) string_renderer_add_ki_with_options((self), (key), (value), STRING_RENDERER_ENCODING_DEFAULT, true, true)
/* the pointer becomes invalid by calling ANY of the other functions defined here */
const char * string_renderer_to_string_zero_copy(string_renderer_t *self);
#endif

View File

@ -27,5 +27,11 @@ ctest_refobject_test_LDADD = \
icecast-refobject.o
check_PROGRAMS += ctest_refobject.test
ctest_string_renderer_test_SOURCES = tests/ctest_string_renderer.c
ctest_string_renderer_test_LDADD = \
icecast-util_string.o \
icecast-string_renderer.o
check_PROGRAMS += ctest_string_renderer.test
# Add all programs to TESTS
TESTS = $(check_PROGRAMS)