From eaaaec91a10f760446445ffdd7f05583c67e6a99 Mon Sep 17 00:00:00 2001 From: Kai Elwert Date: Sat, 14 Aug 2010 13:57:49 +0200 Subject: [PATCH] Introduce DAAP sort-headers helpers --- src/httpd_daap.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 90273b21..7ff611b9 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2010 Julien BLACHE + * Copyright (C) 2010 Kai Elwert * * Adapted from mt-daapd: * Copyright (C) 2003-2007 Ron Pedde @@ -33,6 +34,9 @@ #include #include #include +#include + +#include #include #include "evhttp/evhttp.h" @@ -89,6 +93,14 @@ struct dmap_field_map { ssize_t gri_offset; }; +struct sort_ctx { + struct evbuffer *headerlist; + int16_t mshc; + uint32_t mshi; + uint32_t mshn; + uint32_t misc_mshn; +}; + static const struct dmap_field dmap_abal = { "abal", "daap.browsealbumlisting", DMAP_TYPE_LIST }; static const struct dmap_field dmap_abar = { "abar", "daap.browseartistlisting", DMAP_TYPE_LIST }; @@ -227,6 +239,10 @@ static const struct dmap_field dmap_msas = { "msas", "dmap.authenticationschemes static const struct dmap_field dmap_msau = { "msau", "dmap.authenticationmethod", DMAP_TYPE_UBYTE }; static const struct dmap_field dmap_msbr = { "msbr", "dmap.supportsbrowse", DMAP_TYPE_UBYTE }; static const struct dmap_field dmap_msdc = { "msdc", "dmap.databasescount", DMAP_TYPE_UINT }; +static const struct dmap_field dmap_mshl = { "mshl", "dmap.sortingheaderlisting", DMAP_TYPE_UINT }; +static const struct dmap_field dmap_mshc = { "mshc", "dmap.sortingheaderchar", DMAP_TYPE_SHORT }; +static const struct dmap_field dmap_mshi = { "mshi", "dmap.sortingheaderindex", DMAP_TYPE_UINT }; +static const struct dmap_field dmap_mshn = { "mshn", "dmap.sortingheadernumber", DMAP_TYPE_UINT }; static const struct dmap_field dmap_msex = { "msex", "dmap.supportsextensions", DMAP_TYPE_UBYTE }; static const struct dmap_field dmap_msix = { "msix", "dmap.supportsindex", DMAP_TYPE_UBYTE }; static const struct dmap_field dmap_mslr = { "mslr", "dmap.loginrequired", DMAP_TYPE_UBYTE }; @@ -847,6 +863,139 @@ dmap_add_field(struct evbuffer *evbuf, const struct dmap_field *df, char *strval } +/* DAAP sort headers helpers */ +static struct sort_ctx * +daap_sort_context_new(void) +{ + struct sort_ctx *ctx; + int ret; + + ctx = (struct sort_ctx *)malloc(sizeof(struct sort_ctx)); + if (!ctx) + { + DPRINTF(E_LOG, L_DAAP, "Out of memory for sorting context\n"); + + return NULL; + } + + memset(ctx, 0, sizeof(struct sort_ctx)); + + ctx->headerlist = evbuffer_new(); + if (!ctx->headerlist) + { + DPRINTF(E_LOG, L_DAAP, "Could not create evbuffer for DAAP sort headers list\n"); + + free(ctx); + return NULL; + } + + ret = evbuffer_expand(ctx->headerlist, 512); + if (ret < 0) + { + DPRINTF(E_LOG, L_DAAP, "Could not expand evbuffer for DAAP sort headers list\n"); + + evbuffer_free(ctx->headerlist); + free(ctx); + return NULL; + } + + ctx->mshc = -1; + + return ctx; +} + +static void +daap_sort_context_free(struct sort_ctx *ctx) +{ + evbuffer_free(ctx->headerlist); + free(ctx); +} + +static int +daap_sort_build(struct sort_ctx *ctx, char *str) +{ + uint8_t *ret; + size_t len; + char fl; + + len = strlen(str); + ret = u8_normalize(UNINORM_NFD, (uint8_t *)str, len, NULL, &len); + if (!ret) + { + DPRINTF(E_LOG, L_DAAP, "Could not normalize string for sort header\n"); + + return -1; + } + + fl = ret[0]; + free(ret); + + if (isascii(fl) && isalpha(fl)) + { + fl = toupper(fl); + + /* Init */ + if (ctx->mshc == -1) + ctx->mshc = fl; + + if (fl == ctx->mshc) + ctx->mshn++; + else + { + dmap_add_container(ctx->headerlist, "mlit", 34); + dmap_add_short(ctx->headerlist, "mshc", ctx->mshc); /* 10 */ + dmap_add_int(ctx->headerlist, "mshi", ctx->mshi); /* 12 */ + dmap_add_int(ctx->headerlist, "mshn", ctx->mshn); /* 12 */ + + DPRINTF(E_DBG, L_DAAP, "Added sort header: mshc = %c, mshi = %u, mshn = %u fl %c\n", ctx->mshc, ctx->mshi, ctx->mshn, fl); + + ctx->mshi = ctx->mshi + ctx->mshn; + ctx->mshn = 1; + ctx->mshc = fl; + } + } + else + { + /* Non-ASCII, goes to misc category */ + ctx->misc_mshn++; + } + + return 0; +} + +static int +daap_sort_finalize(struct sort_ctx *ctx, struct evbuffer *evbuf) +{ + int ret; + + /* Add current entry, if any */ + if (ctx->mshc != -1) + { + dmap_add_container(ctx->headerlist, "mlit", 34); + dmap_add_short(ctx->headerlist, "mshc", ctx->mshc); /* 10 */ + dmap_add_int(ctx->headerlist, "mshi", ctx->mshi); /* 12 */ + dmap_add_int(ctx->headerlist, "mshn", ctx->mshn); /* 12 */ + + ctx->mshi = ctx->mshi + ctx->mshn; + + DPRINTF(E_DBG, L_DAAP, "Added sort header: mshc = %c, mshi = %u, mshn = %u (final)\n", ctx->mshc, ctx->mshi, ctx->mshn); + } + + /* Add misc category */ + dmap_add_container(ctx->headerlist, "mlit", 34); + dmap_add_short(ctx->headerlist, "mshc", '0'); /* 10 */ + dmap_add_int(ctx->headerlist, "mshi", ctx->mshi); /* 12 */ + dmap_add_int(ctx->headerlist, "mshn", ctx->misc_mshn); /* 12 */ + + dmap_add_container(evbuf, "mshl", EVBUFFER_LENGTH(ctx->headerlist)); + ret = evbuffer_add_buffer(evbuf, ctx->headerlist); + if (ret < 0) + return -1; + + return 0; +} + + static void get_query_params(struct evkeyvalq *query, int *sort_headers, struct query_params *qp) {