Blame src/util.c

Packit Service 102f81
/* util.c: libshout utility/portability functions
Packit Service 102f81
 *
Packit Service 102f81
 *  Copyright (C) 2002-2003 the Icecast team <team@icecast.org>
Packit Service 102f81
 *
Packit Service 102f81
 *  This library is free software; you can redistribute it and/or
Packit Service 102f81
 *  modify it under the terms of the GNU Library General Public
Packit Service 102f81
 *  License as published by the Free Software Foundation; either
Packit Service 102f81
 *  version 2 of the License, or (at your option) any later version.
Packit Service 102f81
 *
Packit Service 102f81
 *  This library is distributed in the hope that it will be useful,
Packit Service 102f81
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 102f81
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 102f81
 *  Library General Public License for more details.
Packit Service 102f81
 *
Packit Service 102f81
 *  You should have received a copy of the GNU Library General Public
Packit Service 102f81
 *  License along with this library; if not, write to the Free
Packit Service 102f81
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 102f81
 */
Packit Service 102f81
Packit Service 102f81
#ifdef HAVE_CONFIG_H
Packit Service 102f81
 #include <config.h>
Packit Service 102f81
#endif
Packit Service 102f81
Packit Service 102f81
#include <stdio.h>
Packit Service 102f81
#include <string.h>
Packit Service 102f81
#include <stdlib.h>
Packit Service 102f81
Packit Service 102f81
#include <sys/types.h>
Packit Service 102f81
#ifdef HAVE_SYS_SOCKET_H
Packit Service 102f81
#include <sys/socket.h>
Packit Service 102f81
#endif
Packit Service 102f81
#ifdef HAVE_WINSOCK2_H
Packit Service 102f81
#include <winsock2.h>
Packit Service 102f81
#endif
Packit Service 102f81
Packit Service 102f81
#include <shout/shout.h>
Packit Service 102f81
#include "util.h"
Packit Service 102f81
Packit Service 102f81
char *_shout_util_strdup(const char *s)
Packit Service 102f81
{
Packit Service 102f81
	if (!s)
Packit Service 102f81
		return NULL;
Packit Service 102f81
Packit Service 102f81
	return strdup(s);
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
int _shout_util_read_header(int sock, char *buff, unsigned long len)
Packit Service 102f81
{
Packit Service 102f81
	int read_bytes, ret;
Packit Service 102f81
	unsigned long pos;
Packit Service 102f81
	char c;
Packit Service 102f81
Packit Service 102f81
	read_bytes = 1;
Packit Service 102f81
	pos = 0;
Packit Service 102f81
	ret = 0;
Packit Service 102f81
Packit Service 102f81
	while ((read_bytes == 1) && (pos < (len - 1))) {
Packit Service 102f81
		read_bytes = 0;
Packit Service 102f81
Packit Service 102f81
		if ((read_bytes = recv(sock, &c, 1, 0))) {
Packit Service 102f81
			if (c != '\r')
Packit Service 102f81
				buff[pos++] = c;
Packit Service 102f81
			if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) {
Packit Service 102f81
				ret = 1;
Packit Service 102f81
				break;
Packit Service 102f81
			}
Packit Service 102f81
		} else {
Packit Service 102f81
			break;
Packit Service 102f81
		}
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	if (ret) buff[pos] = '\0';
Packit Service 102f81
Packit Service 102f81
	return ret;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static char base64table[65] = {
Packit Service 102f81
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
Packit Service 102f81
    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
Packit Service 102f81
    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
Packit Service 102f81
    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
Packit Service 102f81
};
Packit Service 102f81
Packit Service 102f81
/* This isn't efficient, but it doesn't need to be */
Packit Service 102f81
char *_shout_util_base64_encode(char *data)
Packit Service 102f81
{
Packit Service 102f81
	int len = strlen(data);
Packit Service 102f81
	char *out = malloc(len*4/3 + 4);
Packit Service 102f81
	char *result = out;
Packit Service 102f81
	int chunk;
Packit Service 102f81
Packit Service 102f81
	while(len > 0) {
Packit Service 102f81
		chunk = (len >3)?3:len;
Packit Service 102f81
		*out++ = base64table[(*data & 0xFC)>>2];
Packit Service 102f81
		*out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
Packit Service 102f81
Packit Service 102f81
		switch(chunk) {
Packit Service 102f81
		case 3:
Packit Service 102f81
			*out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
Packit Service 102f81
			*out++ = base64table[(*(data+2)) & 0x3F];
Packit Service 102f81
			break;
Packit Service 102f81
		case 2:
Packit Service 102f81
			*out++ = base64table[((*(data+1) & 0x0F)<<2)];
Packit Service 102f81
			*out++ = '=';
Packit Service 102f81
			break;
Packit Service 102f81
		case 1:
Packit Service 102f81
			*out++ = '=';
Packit Service 102f81
			*out++ = '=';
Packit Service 102f81
			break;
Packit Service 102f81
		}
Packit Service 102f81
		data += chunk;
Packit Service 102f81
		len -= chunk;
Packit Service 102f81
	}
Packit Service 102f81
	*out = 0;
Packit Service 102f81
Packit Service 102f81
	return result;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static char urltable[16] = {
Packit Service 102f81
	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
Packit Service 102f81
};
Packit Service 102f81
Packit Service 102f81
static char safechars[256] = {
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
Packit Service 102f81
      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
Packit Service 102f81
      1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
Packit Service 102f81
};
Packit Service 102f81
Packit Service 102f81
/* modified from libshout1, which credits Rick Franchuk <rickf@transpect.net>.
Packit Service 102f81
 * Caller must free result. */
Packit Service 102f81
char *_shout_util_url_encode(const char *data) {
Packit Service 102f81
	const char *p;
Packit Service 102f81
	char *q, *dest;
Packit Service 102f81
	int digit;
Packit Service 102f81
	size_t n;
Packit Service 102f81
Packit Service 102f81
	for (p = data, n = 0; *p; p++) {
Packit Service 102f81
		n++;
Packit Service 102f81
		if (!safechars[(unsigned char)(*p)])
Packit Service 102f81
			n += 2;
Packit Service 102f81
	}
Packit Service 102f81
	if (!(dest = malloc(n+1)))
Packit Service 102f81
		return NULL;
Packit Service 102f81
		
Packit Service 102f81
	for (p = data, q = dest; *p; p++, q++) {
Packit Service 102f81
		if (safechars[(unsigned char)(*p)]) {
Packit Service 102f81
			*q = *p;
Packit Service 102f81
		} else {
Packit Service 102f81
			*q++ = '%';
Packit Service 102f81
			digit = (*p >> 4) & 0xF;
Packit Service 102f81
			*q++ = urltable[digit];
Packit Service 102f81
			digit = *p & 0xf;
Packit Service 102f81
			*q = urltable[digit];
Packit Service 102f81
			n += 2;
Packit Service 102f81
		}
Packit Service 102f81
	}
Packit Service 102f81
	*q = '\0';
Packit Service 102f81
Packit Service 102f81
	return dest;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
util_dict *_shout_util_dict_new(void)
Packit Service 102f81
{
Packit Service 102f81
	return (util_dict *)calloc(1, sizeof(util_dict));
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
void _shout_util_dict_free(util_dict *dict)
Packit Service 102f81
{
Packit Service 102f81
	util_dict *next;
Packit Service 102f81
Packit Service 102f81
	while (dict) {
Packit Service 102f81
		next = dict->next;
Packit Service 102f81
Packit Service 102f81
		if (dict->key)
Packit Service 102f81
			free (dict->key);
Packit Service 102f81
		if (dict->val)
Packit Service 102f81
			free (dict->val);
Packit Service 102f81
		free (dict);
Packit Service 102f81
Packit Service 102f81
		dict = next;
Packit Service 102f81
	}
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
const char *_shout_util_dict_get(util_dict *dict, const char *key)
Packit Service 102f81
{
Packit Service 102f81
	while (dict) {
Packit Service 102f81
		if (dict->key && !strcmp(key, dict->key))
Packit Service 102f81
			return dict->val;
Packit Service 102f81
		dict = dict->next;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	return NULL;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
int _shout_util_dict_set(util_dict *dict, const char *key, const char *val)
Packit Service 102f81
{
Packit Service 102f81
	util_dict *prev;
Packit Service 102f81
Packit Service 102f81
	if (!dict || !key)
Packit Service 102f81
		return SHOUTERR_INSANE;
Packit Service 102f81
Packit Service 102f81
	prev = NULL;
Packit Service 102f81
	while (dict) {
Packit Service 102f81
		if (!dict->key || !strcmp(dict->key, key))
Packit Service 102f81
			break;
Packit Service 102f81
		prev = dict;
Packit Service 102f81
		dict = dict->next;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	if (!dict) {
Packit Service 102f81
		dict = _shout_util_dict_new();
Packit Service 102f81
		if (!dict)
Packit Service 102f81
			return SHOUTERR_MALLOC;
Packit Service 102f81
		if (prev)
Packit Service 102f81
			prev->next = dict;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	if (dict->key)
Packit Service 102f81
		free (dict->val);
Packit Service 102f81
	else if (!(dict->key = strdup(key))) {
Packit Service 102f81
		if (prev)
Packit Service 102f81
			prev->next = NULL;
Packit Service 102f81
		_shout_util_dict_free (dict);
Packit Service 102f81
Packit Service 102f81
		return SHOUTERR_MALLOC;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	dict->val = strdup(val);
Packit Service 102f81
	if (!dict->val) {
Packit Service 102f81
		return SHOUTERR_MALLOC;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	return SHOUTERR_SUCCESS;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
/* given a dictionary, URL-encode each key and val and stringify them in order as
Packit Service 102f81
  key=val&key=val... if val is set, or just key&key if val is NULL.
Packit Service 102f81
  TODO: Memory management needs overhaul. */
Packit Service 102f81
char *_shout_util_dict_urlencode(util_dict *dict, char delim)
Packit Service 102f81
{
Packit Service 102f81
	char *res, *tmp;
Packit Service 102f81
	char *enc;
Packit Service 102f81
	int start = 1;
Packit Service 102f81
Packit Service 102f81
	for (res = NULL; dict; dict = dict->next) {
Packit Service 102f81
		/* encode key */
Packit Service 102f81
		if (!dict->key)
Packit Service 102f81
			continue;
Packit Service 102f81
		if (!(enc = _shout_util_url_encode(dict->key))) {
Packit Service 102f81
			if (res)
Packit Service 102f81
				free(res);
Packit Service 102f81
			return NULL;
Packit Service 102f81
		}
Packit Service 102f81
		if (start) {
Packit Service 102f81
			if (!(res = malloc(strlen(enc) + 1))) {
Packit Service 102f81
				free(enc);
Packit Service 102f81
				return NULL;
Packit Service 102f81
			}
Packit Service 102f81
			sprintf(res, "%s", enc);
Packit Service 102f81
			free(enc);
Packit Service 102f81
			start = 0;
Packit Service 102f81
		} else {
Packit Service 102f81
			if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
Packit Service 102f81
				free(enc);
Packit Service 102f81
				free(res);
Packit Service 102f81
				return NULL;
Packit Service 102f81
			} else
Packit Service 102f81
				res = tmp;
Packit Service 102f81
			sprintf(res + strlen(res), "%c%s", delim, enc);
Packit Service 102f81
			free(enc);
Packit Service 102f81
		}
Packit Service 102f81
Packit Service 102f81
		/* encode value */
Packit Service 102f81
		if (!dict->val)
Packit Service 102f81
			continue;
Packit Service 102f81
		if (!(enc = _shout_util_url_encode(dict->val))) {
Packit Service 102f81
			free(res);
Packit Service 102f81
			return NULL;
Packit Service 102f81
		}
Packit Service 102f81
Packit Service 102f81
		if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
Packit Service 102f81
			free(enc);
Packit Service 102f81
			free(res);
Packit Service 102f81
			return NULL;
Packit Service 102f81
		} else
Packit Service 102f81
			res = tmp;
Packit Service 102f81
		sprintf(res + strlen(res), "=%s", enc);
Packit Service 102f81
		free(enc);
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	return res;
Packit Service 102f81
}