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:
parent
167f626dcd
commit
c4edf52ef8
@ -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
280
src/string_renderer.c
Normal 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
46
src/string_renderer.h
Normal 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
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user