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