2 This file is part of avahi.
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 #include <sys/types.h>
29 #include <avahi-common/malloc.h>
34 typedef struct TXTRecordInternal {
35 uint8_t *buffer, *malloc_buffer;
36 size_t size, max_size;
39 #define INTERNAL_PTR(txtref) (* (TXTRecordInternal**) (txtref))
40 #define INTERNAL_PTR_CONST(txtref) (* (const TXTRecordInternal* const *) (txtref))
42 void DNSSD_API TXTRecordCreate(
53 /* Apple's API design is flawed in so many ways, including the
54 * fact that it isn't compatible with 64 bit processors. To work
55 * around this we need some magic here which involves allocating
56 * our own memory. Please, Apple, do your homework next time
57 * before designing an API! */
59 if ((t = avahi_new(TXTRecordInternal, 1))) {
61 t->max_size = buffer ? length : (size_t)0;
63 t->malloc_buffer = NULL;
66 /* If we were unable to allocate memory, we store a NULL pointer
67 * and return a NoMemory error later, is somewhat unclean, but
69 INTERNAL_PTR(txtref) = t;
72 void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtref) {
78 t = INTERNAL_PTR(txtref);
82 avahi_free(t->malloc_buffer);
85 /* Just in case ... */
86 INTERNAL_PTR(txtref) = NULL;
89 static int make_sure_fits_in(TXTRecordInternal *t, size_t size) {
95 if (t->size + size <= t->max_size)
98 nsize = t->size + size + 100;
103 if (!(n = avahi_realloc(t->malloc_buffer, nsize)))
106 if (!t->malloc_buffer && t->size)
107 memcpy(n, t->buffer, t->size);
109 t->buffer = t->malloc_buffer = n;
115 static int remove_key(TXTRecordInternal *t, const char *key) {
121 key_len = strlen(key);
122 assert(key_len <= 0xFF);
127 while (i < t->size) {
129 /* Does the item fit in? */
130 assert(*p <= t->size - i - 1);
132 /* Key longer than buffer */
133 if (key_len > t->size - i - 1)
137 strncmp(key, (char*) p+1, key_len) == 0 &&
138 (key_len == *p || p[1+key_len] == '=')) {
142 /* Key matches, so let's remove it */
145 memmove(p, p + 1 + *p, t->size - i - *p -1);
160 DNSServiceErrorType DNSSD_API TXTRecordSetValue(
161 TXTRecordRef *txtref,
166 TXTRecordInternal *t;
177 if (*key == 0 || strchr(key, '=') || l > 0xFF) /* Empty or invalid key */
178 return kDNSServiceErr_Invalid;
180 if (!(t = INTERNAL_PTR(txtref)))
181 return kDNSServiceErr_NoMemory;
183 n = l + (value ? length + 1 : 0);
186 return kDNSServiceErr_Invalid;
188 if (make_sure_fits_in(t, 1 + n) < 0)
189 return kDNSServiceErr_NoMemory;
193 p = t->buffer + t->size;
195 *(p++) = (uint8_t) n;
204 memcpy(p, value, length);
205 t->size += length + 1;
208 assert(t->size <= t->max_size);
210 return kDNSServiceErr_NoError;
213 DNSServiceErrorType DNSSD_API TXTRecordRemoveValue(TXTRecordRef *txtref, const char *key) {
214 TXTRecordInternal *t;
222 if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
223 return kDNSServiceErr_Invalid;
225 if (!(t = INTERNAL_PTR(txtref)))
226 return kDNSServiceErr_NoError;
228 found = remove_key(t, key);
230 return found ? kDNSServiceErr_NoError : kDNSServiceErr_NoSuchKey;
233 uint16_t DNSSD_API TXTRecordGetLength(const TXTRecordRef *txtref) {
234 const TXTRecordInternal *t;
240 if (!(t = INTERNAL_PTR_CONST(txtref)))
243 assert(t->size <= 0xFFFF);
244 return (uint16_t) t->size;
247 const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtref) {
248 const TXTRecordInternal *t;
254 if (!(t = INTERNAL_PTR_CONST(txtref)) || !t->buffer)
260 static const uint8_t *find_key(const uint8_t *buffer, size_t size, const char *key) {
265 key_len = strlen(key);
267 assert(key_len <= 0xFF);
274 /* Does the item fit in? */
275 if (*p > size - i - 1)
278 /* Key longer than buffer */
279 if (key_len > size - i - 1)
283 strncmp(key, (const char*) p+1, key_len) == 0 &&
284 (key_len == *p || p[1+key_len] == '=')) {
286 /* Key matches, so let's return it */
299 int DNSSD_API TXTRecordContainsKey (
313 if (!(find_key(buffer, size, key)))
319 const void * DNSSD_API TXTRecordGetValuePtr(
323 uint8_t *value_len) {
335 if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
340 if (!(p = find_key(buffer, size, key)))
370 uint16_t DNSSD_API TXTRecordGetCount(
372 const void *buffer) {
390 /* Does the item fit in? */
391 if (*p > size - i - 1)
406 DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex(
413 const void **value) {
418 DNSServiceErrorType ret = kDNSServiceErr_Invalid;
432 /* Does the item fit in? */
433 if (*p > size - i - 1)
440 d = memchr(p+1, '=', *p);
443 l = d ? d - p - 1 : *p;
446 ret = kDNSServiceErr_NoMemory;
450 strncpy(key, (const char*) p + 1, l);
455 *value_len = *p - l - 1;
468 return kDNSServiceErr_NoError;