Blame src/util.c

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