From 43bc709b48fdb15f148f36945ebcdffac33e7f2e Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Mon, 9 Jul 2018 09:29:54 +0000 Subject: [PATCH] Feature: Added new resource match system --- src/Makefile.am | 2 + src/resourcematch.c | 193 ++++++++++++++++++++++++++++++++++++++++++++ src/resourcematch.h | 37 +++++++++ 3 files changed, 232 insertions(+) create mode 100644 src/resourcematch.c create mode 100644 src/resourcematch.h diff --git a/src/Makefile.am b/src/Makefile.am index 61e94508..6281f7d1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ bin_PROGRAMS = icecast noinst_HEADERS = \ icecasttypes.h \ admin.h \ + resourcematch.h \ main.h \ cfgfile.h \ logging.h \ @@ -69,6 +70,7 @@ icecast_SOURCES = \ xslt.c \ fserve.c \ admin.c \ + resourcematch.c \ md5.c \ matchfile.c \ tls.c \ diff --git a/src/resourcematch.c b/src/resourcematch.c new file mode 100644 index 00000000..8d57d8d7 --- /dev/null +++ b/src/resourcematch.c @@ -0,0 +1,193 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "resourcematch.h" + +static size_t count_groups(const char *pattern) +{ + size_t ret = 0; + + while (*pattern) { + for (; *pattern && *pattern != '%'; pattern++); + + if (!*pattern) { + return ret; + } + + pattern++; + + if (!*pattern) + return ret; + + if (*pattern != '%') + ret++; + + pattern++; + } + + return ret; +} + +static resourcematch_extract_t * allocate_extract(const char *pattern) +{ + size_t groups = count_groups(pattern); + resourcematch_extract_t *ret; + + ret = calloc(1, sizeof(*ret)); + if (!ret) + return NULL; + + ret->groups = groups; + ret->group = calloc(groups, sizeof(*ret->group)); + + return ret; +} + +static void strip_common_prefix(const char **pattern, const char **string) +{ + const char *p = *pattern; + const char *s = *string; + + for (; *p && *p != '%' && *p == *s; p++, s++); + + *pattern = p; + *string = s; +} + +static inline void setup_group(resourcematch_extract_t *extract, size_t idx, char type) +{ + if (!extract) + return; + + extract->group[idx].type = type; + extract->group[idx].raw = NULL; +} + +static inline resourcematch_result_t match_lli(const char **string, resourcematch_extract_t *extract, size_t idx, int base) +{ + long long int ret; + char *endptr; + + errno = 0; + ret = strtoll(*string, &endptr, base); + if (errno != 0) + return RESOURCEMATCH_ERROR; + + if (extract) { + extract->group[idx].result.lli = ret; + } + + *string = endptr; + + return RESOURCEMATCH_MATCH; +} + +resourcematch_result_t resourcematch_match(const char *pattern, const char *string, resourcematch_extract_t **extract) +{ + resourcematch_result_t ret; + resourcematch_extract_t *matches = NULL; + size_t idx = 0; + + if (!pattern || !string) + return RESOURCEMATCH_ERROR; + + if (extract) { + matches = allocate_extract(pattern); + if (!matches) + return RESOURCEMATCH_NOMATCH; + } + + while (1) { + strip_common_prefix(&pattern, &string); + + if (!*pattern && !*string) { + if (extract) + *extract = matches; + + return RESOURCEMATCH_MATCH; + } else if (!*pattern || !*string) { + if (extract) + resourcematch_extract_free(matches); + + return RESOURCEMATCH_NOMATCH; + } + + if (*pattern != '%') { + if (extract) + resourcematch_extract_free(matches); + + return RESOURCEMATCH_NOMATCH; + } + + pattern++; + + switch (*pattern) { + case '%': + if (*string == '%') { + string++; + } else { + if (extract) + resourcematch_extract_free(matches); + + return RESOURCEMATCH_NOMATCH; + } + break; +#define _test_int(type,base) \ + case (type): \ + setup_group(matches, idx, *pattern); \ +\ + ret = match_lli(&string, matches, idx, (base)); \ + if (ret != RESOURCEMATCH_MATCH) { \ + if (extract) \ + resourcematch_extract_free(matches); \ +\ + return ret; \ + } \ + idx++; \ + break; + + _test_int('i', 0); + _test_int('d', 10); + _test_int('x', 16); + _test_int('o', 8); + + default: + if (extract) + resourcematch_extract_free(matches); + + return RESOURCEMATCH_ERROR; + break; + } + + pattern++; + } +} + +void resourcematch_extract_free(resourcematch_extract_t *extract) +{ + size_t i; + + if (!extract) + return; + + for (i = 0; i < extract->groups; i++) { + free(extract->group[i].raw); + } + + free(extract->group); + free(extract); +} diff --git a/src/resourcematch.h b/src/resourcematch.h new file mode 100644 index 00000000..534b6874 --- /dev/null +++ b/src/resourcematch.h @@ -0,0 +1,37 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifndef __RESOURCEMATCH_H__ +#define __RESOURCEMATCH_H__ + +#include + +typedef enum { + RESOURCEMATCH_ERROR, + RESOURCEMATCH_MATCH, + RESOURCEMATCH_NOMATCH +} resourcematch_result_t; + +typedef struct { + char type; + char *raw; + union { + const char *string; + long long int lli; + } result; +} resourcematch_group_t; + +typedef struct { + size_t groups; + resourcematch_group_t *group; +} resourcematch_extract_t; + +resourcematch_result_t resourcematch_match(const char *pattern, const char *string, resourcematch_extract_t **extract); +void resourcematch_extract_free(resourcematch_extract_t *extract); + +#endif