diff --git a/src/httpd.c b/src/httpd.c index bb9d800b..1fc84024 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -1555,7 +1555,7 @@ httpd_basic_auth(struct evhttp_request *req, const char *user, const char *passw auth += strlen("Basic "); - authuser = b64_decode(auth); + authuser = (char *)b64_decode(NULL, auth); if (!authuser) { DPRINTF(E_LOG, L_HTTPD, "Could not decode Authentication header\n"); diff --git a/src/inputs/pipe.c b/src/inputs/pipe.c index ae5a1c83..ba5cd849 100644 --- a/src/inputs/pipe.c +++ b/src/inputs/pipe.c @@ -285,7 +285,7 @@ dmapval(const char s[4]) } static void -parse_progress(struct input_metadata *m, char *progress) +handle_progress(struct input_metadata *m, char *progress) { char *s; char *ptr; @@ -315,7 +315,7 @@ parse_progress(struct input_metadata *m, char *progress) } static void -parse_volume(const char *volume) +handle_volume(const char *volume) { char *volume_next; float airplay_volume; @@ -355,7 +355,7 @@ parse_volume(const char *volume) // returns 1 on metadata found, 0 on nothing, -1 on error static int -parse_item(struct input_metadata *m, const char *item) +handle_item(struct input_metadata *m, const char *item) { mxml_node_t *xml; mxml_node_t *haystack; @@ -363,9 +363,11 @@ parse_item(struct input_metadata *m, const char *item) const char *s; uint32_t type; uint32_t code; + char **dstptr; char *progress; char *volume; - char **data; + uint8_t *data; + int data_len; int ret; ret = 0; @@ -399,17 +401,17 @@ parse_item(struct input_metadata *m, const char *item) } if (code == dmapval("asal")) - data = &m->album; + dstptr = &m->album; else if (code == dmapval("asar")) - data = &m->artist; + dstptr = &m->artist; else if (code == dmapval("minm")) - data = &m->title; + dstptr = &m->title; else if (code == dmapval("asgn")) - data = &m->genre; + dstptr = &m->genre; else if (code == dmapval("prgr")) - data = &progress; + dstptr = &progress; else if (code == dmapval("pvol")) - data = &volume; + dstptr = &volume; else goto out_nothing; @@ -418,11 +420,8 @@ parse_item(struct input_metadata *m, const char *item) { pthread_mutex_lock(&pipe_metadata_lock); - if (data != &progress && data != &volume) - free(*data); - - *data = b64_decode(s); - if (!*data) + data = b64_decode(&data_len, s); + if (!data) { DPRINTF(E_LOG, L_PLAYER, "Base64 decode of '%s' failed\n", s); @@ -430,17 +429,24 @@ parse_item(struct input_metadata *m, const char *item) goto out_error; } - DPRINTF(E_DBG, L_PLAYER, "Read Shairport metadata (type=%8x, code=%8x): '%s'\n", type, code, *data); + DPRINTF(E_DBG, L_PLAYER, "Read Shairport metadata (type=%8x, code=%8x, len=%d): '%s'\n", type, code, data_len, (char *)data); - if (data == &progress) + if (dstptr == &progress) { - parse_progress(m, progress); - free(*data); + progress = (char *)data; + handle_progress(m, progress); + free(data); } - else if (data == &volume) + else if (dstptr == &volume) { - parse_volume(volume); - free(*data); + volume = (char *)data; + handle_volume(volume); + free(data); + } + else + { + free(*dstptr); // If m->x is already set, free it + *dstptr = (char *)data; } pthread_mutex_unlock(&pipe_metadata_lock); @@ -480,7 +486,7 @@ extract_item(struct evbuffer *evbuf) } static int -pipe_metadata_parse(struct input_metadata *m, struct evbuffer *evbuf) +pipe_metadata_handle(struct input_metadata *m, struct evbuffer *evbuf) { char *item; int found; @@ -489,7 +495,7 @@ pipe_metadata_parse(struct input_metadata *m, struct evbuffer *evbuf) found = 0; while ((item = extract_item(evbuf))) { - ret = parse_item(m, item); + ret = handle_item(m, item); free(item); if (ret < 0) return -1; @@ -662,7 +668,7 @@ pipe_metadata_read_cb(evutil_socket_t fd, short event, void *arg) return; } - ret = pipe_metadata_parse(&pipe_metadata_parsed, pipe_metadata_buf); + ret = pipe_metadata_handle(&pipe_metadata_parsed, pipe_metadata_buf); if (ret < 0) { pipe_metadata_watch_del(NULL); diff --git a/src/misc.c b/src/misc.c index 3eef4154..77cf1b98 100644 --- a/src/misc.c +++ b/src/misc.c @@ -43,6 +43,8 @@ #include #include +#include + #include "logger.h" #include "conffile.h" #include "misc.h" @@ -771,161 +773,52 @@ two_str_hash(const char *a, const char *b) return hash; } -static unsigned char b64_decode_table[256]; - -char * -b64_decode(const char *b64) +uint8_t * +b64_decode(int *dstlen, const char *src) { - char *str; - const unsigned char *iptr; - unsigned char *optr; - unsigned char c; + uint8_t *out; int len; - int i; + int ret; - if (b64_decode_table[0] == 0) + len = AV_BASE64_DECODE_SIZE(strlen(src)); + + CHECK_NULL(L_MISC, out = calloc(1, len)); + + ret = av_base64_decode(out, src, len); + if (ret < 0) { - memset(b64_decode_table, 0xff, sizeof(b64_decode_table)); - - /* Base64 encoding: A-Za-z0-9+/ */ - for (i = 0; i < 26; i++) - { - b64_decode_table['A' + i] = i; - b64_decode_table['a' + i] = i + 26; - } - - for (i = 0; i < 10; i++) - b64_decode_table['0' + i] = i + 52; - - b64_decode_table['+'] = 62; - b64_decode_table['/'] = 63; - - /* Stop on '=' */ - b64_decode_table['='] = 100; /* > 63 */ + free(out); + return NULL; } - len = strlen(b64); + if (dstlen) + *dstlen = ret; - CHECK_NULL(L_MISC, str = malloc(len)); - - memset(str, 0, len); - - iptr = (const unsigned char *)b64; - optr = (unsigned char *)str; - i = 0; - - while (len) - { - if (*iptr == '=') - break; - - c = b64_decode_table[*iptr]; - if (c > 63) - { - iptr++; - len--; - continue; - } - - switch (i) - { - case 0: - optr[0] = c << 2; - break; - case 1: - optr[0] |= c >> 4; - optr[1] = c << 4; - break; - case 2: - optr[1] |= c >> 2; - optr[2] = c << 6; - break; - case 3: - optr[2] |= c; - break; - } - - i++; - if (i == 4) - { - optr += 3; - i = 0; - } - - len--; - iptr++; - } - - return str; -} - -static const char b64_encode_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static void -b64_encode_block(const uint8_t *in, char *out, int len) -{ - out[0] = b64_encode_table[in[0] >> 2]; - - out[2] = out[3] = '='; - - if (len == 1) - out[1] = b64_encode_table[((in[0] & 0x03) << 4)]; - else - { - out[1] = b64_encode_table[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)]; - - if (len == 2) - out[2] = b64_encode_table[((in[1] & 0x0f) << 2)]; - else - { - out[2] = b64_encode_table[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)]; - out[3] = b64_encode_table[in[2] & 0x3f]; - } - } -} - -static void -b64_encode_full_block(const uint8_t *in, char *out) -{ - out[0] = b64_encode_table[in[0] >> 2]; - out[1] = b64_encode_table[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)]; - out[2] = b64_encode_table[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)]; - out[3] = b64_encode_table[in[2] & 0x3f]; + return out; } char * -b64_encode(const uint8_t *in, size_t len) +b64_encode(const uint8_t *src, int srclen) { - char *encoded; char *out; + int len; + char *ret; - /* 3 in chars -> 4 out chars */ - encoded = (char *)malloc(len + (len / 3) + 4 + 1); - if (!encoded) - return NULL; + len = AV_BASE64_SIZE(srclen); - out = encoded; + CHECK_NULL(L_MISC, out = calloc(1, len)); - while (len >= 3) + ret = av_base64_encode(out, len, src, srclen); + if (!ret) { - b64_encode_full_block(in, out); - - len -= 3; - in += 3; - out += 4; + free(out); + return NULL; } - if (len > 0) - { - b64_encode_block(in, out, len); - out += 4; - } - - out[0] = '\0'; - - return encoded; + return out; } + /* * MurmurHash2, 64-bit versions, by Austin Appleby * diff --git a/src/misc.h b/src/misc.h index 619a6ee6..1de944e3 100644 --- a/src/misc.h +++ b/src/misc.h @@ -133,11 +133,11 @@ djb_hash(const void *data, size_t len); int64_t two_str_hash(const char *a, const char *b); -char * -b64_decode(const char *b64); +uint8_t * +b64_decode(int *dstlen, const char *src); char * -b64_encode(const uint8_t *in, size_t len); +b64_encode(const uint8_t *src, int srclen); uint64_t murmur_hash64(const void *key, int len, uint32_t seed);