1/***
2  This file is part of PulseAudio.
3
4  Copyright 2008 Colin Guthrie
5  Copyright 2007 Lennart Poettering
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as
9  published by the Free Software Foundation; either version 2.1 of the
10  License, or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public
18  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <string.h>
26
27#include <pulse/xmalloc.h>
28
29#include <pulsecore/hashmap.h>
30#include <pulsecore/strbuf.h>
31#include <pulsecore/core-util.h>
32
33#include "headerlist.h"
34
35struct header {
36    char *key;
37    void *value;
38    size_t nbytes;
39};
40
41#define MAKE_HASHMAP(p) ((pa_hashmap*) (p))
42#define MAKE_HEADERLIST(p) ((pa_headerlist*) (p))
43
44static void header_free(struct header *hdr) {
45    pa_assert(hdr);
46
47    pa_xfree(hdr->key);
48    pa_xfree(hdr->value);
49    pa_xfree(hdr);
50}
51
52pa_headerlist* pa_headerlist_new(void) {
53    return MAKE_HEADERLIST(pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) header_free));
54}
55
56void pa_headerlist_free(pa_headerlist* p) {
57    pa_hashmap_free(MAKE_HASHMAP(p));
58}
59
60int pa_headerlist_puts(pa_headerlist *p, const char *key, const char *value) {
61    struct header *hdr;
62    bool add = false;
63
64    pa_assert(p);
65    pa_assert(key);
66
67    if (!(hdr = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
68        hdr = pa_xnew(struct header, 1);
69        hdr->key = pa_xstrdup(key);
70        add = true;
71    } else
72        pa_xfree(hdr->value);
73
74    hdr->value = pa_xstrdup(value);
75    hdr->nbytes = strlen(value)+1;
76
77    if (add)
78        pa_hashmap_put(MAKE_HASHMAP(p), hdr->key, hdr);
79
80    return 0;
81}
82
83int pa_headerlist_putsappend(pa_headerlist *p, const char *key, const char *value) {
84    struct header *hdr;
85    bool add = false;
86
87    pa_assert(p);
88    pa_assert(key);
89
90    if (!(hdr = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
91        hdr = pa_xnew(struct header, 1);
92        hdr->key = pa_xstrdup(key);
93        hdr->value = pa_xstrdup(value);
94        add = true;
95    } else {
96        void *newval = pa_sprintf_malloc("%s%s", (char*)hdr->value, value);
97        pa_xfree(hdr->value);
98        hdr->value = newval;
99    }
100    hdr->nbytes = strlen(hdr->value)+1;
101
102    if (add)
103        pa_hashmap_put(MAKE_HASHMAP(p), hdr->key, hdr);
104
105    return 0;
106}
107
108const char *pa_headerlist_gets(pa_headerlist *p, const char *key) {
109    struct header *hdr;
110
111    pa_assert(p);
112    pa_assert(key);
113
114    if (!(hdr = pa_hashmap_get(MAKE_HASHMAP(p), key)))
115        return NULL;
116
117    if (hdr->nbytes <= 0)
118        return NULL;
119
120    if (((char*) hdr->value)[hdr->nbytes-1] != 0)
121        return NULL;
122
123    if (strlen((char*) hdr->value) != hdr->nbytes-1)
124        return NULL;
125
126    return (char*) hdr->value;
127}
128
129int pa_headerlist_remove(pa_headerlist *p, const char *key) {
130    pa_assert(p);
131    pa_assert(key);
132
133    return pa_hashmap_remove_and_free(MAKE_HASHMAP(p), key);
134}
135
136const char *pa_headerlist_iterate(pa_headerlist *p, void **state) {
137    struct header *hdr;
138
139    if (!(hdr = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
140        return NULL;
141
142    return hdr->key;
143}
144
145char *pa_headerlist_to_string(pa_headerlist *p) {
146    const char *key;
147    void *state = NULL;
148    pa_strbuf *buf;
149
150    pa_assert(p);
151
152    buf = pa_strbuf_new();
153
154    while ((key = pa_headerlist_iterate(p, &state))) {
155
156        const char *v;
157
158        if ((v = pa_headerlist_gets(p, key)))
159            pa_strbuf_printf(buf, "%s: %s\r\n", key, v);
160    }
161
162    return pa_strbuf_to_string_free(buf);
163}
164
165int pa_headerlist_contains(pa_headerlist *p, const char *key) {
166    pa_assert(p);
167    pa_assert(key);
168
169    if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
170        return 0;
171
172    return 1;
173}
174