4 This file is part of avahi.
6 avahi is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 avahi is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14 Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with avahi; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <sys/types.h>
31 #include <avahi-common/malloc.h>
36 typedef struct TXTRecordInternal {
37 uint8_t *buffer, *malloc_buffer;
38 size_t size, max_size;
41 #define INTERNAL_PTR(txtref) (* (TXTRecordInternal**) (txtref))
42 #define INTERNAL_PTR_CONST(txtref) (* (const TXTRecordInternal* const *) (txtref))
44 void DNSSD_API TXTRecordCreate(
55 /* Apple's API design is flawed in so many ways, including the
56 * fact that it isn't compatible with 64 bit processors. To work
57 * around this we need some magic here which involves allocating
58 * our own memory. Please, Apple, do your homework next time
59 * before designing an API! */
61 if ((t = avahi_new(TXTRecordInternal, 1))) {
63 t->max_size = buffer ? length : (size_t)0;
65 t->malloc_buffer = NULL;
68 /* If we were unable to allocate memory, we store a NULL pointer
69 * and return a NoMemory error later, is somewhat unclean, but
71 INTERNAL_PTR(txtref) = t;
74 void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtref) {
80 t = INTERNAL_PTR(txtref);
84 avahi_free(t->malloc_buffer);
87 /* Just in case ... */
88 INTERNAL_PTR(txtref) = NULL;
91 static int make_sure_fits_in(TXTRecordInternal *t, size_t size) {
97 if (t->size + size <= t->max_size)
100 nsize = t->size + size + 100;
105 if (!(n = avahi_realloc(t->malloc_buffer, nsize)))
108 if (!t->malloc_buffer && t->size)
109 memcpy(n, t->buffer, t->size);
111 t->buffer = t->malloc_buffer = n;
117 static int remove_key(TXTRecordInternal *t, const char *key) {
123 key_len = strlen(key);
124 assert(key_len <= 0xFF);
129 while (i < t->size) {
131 /* Does the item fit in? */
132 assert(*p <= t->size - i - 1);
134 /* Key longer than buffer */
135 if (key_len > t->size - i - 1)
139 strncmp(key, (char*) p+1, key_len) == 0 &&
140 (key_len == *p || p[1+key_len] == '=')) {
144 /* Key matches, so let's remove it */
147 memmove(p, p + 1 + *p, t->size - i - *p -1);
162 DNSServiceErrorType DNSSD_API TXTRecordSetValue(
163 TXTRecordRef *txtref,
168 TXTRecordInternal *t;
179 if (*key == 0 || strchr(key, '=') || l > 0xFF) /* Empty or invalid key */
180 return kDNSServiceErr_Invalid;
182 if (!(t = INTERNAL_PTR(txtref)))
183 return kDNSServiceErr_NoMemory;
185 n = l + (value ? length + 1 : 0);
188 return kDNSServiceErr_Invalid;
190 if (make_sure_fits_in(t, 1 + n) < 0)
191 return kDNSServiceErr_NoMemory;
195 p = t->buffer + t->size;
197 *(p++) = (uint8_t) n;
206 memcpy(p, value, length);
207 t->size += length + 1;
210 assert(t->size <= t->max_size);
212 return kDNSServiceErr_NoError;
215 DNSServiceErrorType DNSSD_API TXTRecordRemoveValue(TXTRecordRef *txtref, const char *key) {
216 TXTRecordInternal *t;
224 if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
225 return kDNSServiceErr_Invalid;
227 if (!(t = INTERNAL_PTR(txtref)))
228 return kDNSServiceErr_NoError;
230 found = remove_key(t, key);
232 return found ? kDNSServiceErr_NoError : kDNSServiceErr_NoSuchKey;
235 uint16_t DNSSD_API TXTRecordGetLength(const TXTRecordRef *txtref) {
236 const TXTRecordInternal *t;
242 if (!(t = INTERNAL_PTR_CONST(txtref)))
245 assert(t->size <= 0xFFFF);
246 return (uint16_t) t->size;
249 const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtref) {
250 const TXTRecordInternal *t;
256 if (!(t = INTERNAL_PTR_CONST(txtref)) || !t->buffer)
262 static const uint8_t *find_key(const uint8_t *buffer, size_t size, const char *key) {
267 key_len = strlen(key);
269 assert(key_len <= 0xFF);
276 /* Does the item fit in? */
277 if (*p > size - i - 1)
280 /* Key longer than buffer */
281 if (key_len > size - i - 1)
285 strncmp(key, (const char*) p+1, key_len) == 0 &&
286 (key_len == *p || p[1+key_len] == '=')) {
288 /* Key matches, so let's return it */
301 int DNSSD_API TXTRecordContainsKey (
315 if (!(find_key(buffer, size, key)))
321 const void * DNSSD_API TXTRecordGetValuePtr(
325 uint8_t *value_len) {
337 if (*key == 0 || strchr(key, '=') || strlen(key) > 0xFF) /* Empty or invalid key */
342 if (!(p = find_key(buffer, size, key)))
372 uint16_t DNSSD_API TXTRecordGetCount(
374 const void *buffer) {
392 /* Does the item fit in? */
393 if (*p > size - i - 1)
408 DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex(
415 const void **value) {
420 DNSServiceErrorType ret = kDNSServiceErr_Invalid;
434 /* Does the item fit in? */
435 if (*p > size - i - 1)
442 d = memchr(p+1, '=', *p);
445 l = d ? d - p - 1 : *p;
448 ret = kDNSServiceErr_NoMemory;
452 strncpy(key, (const char*) p + 1, l);
457 *value_len = *p - l - 1;
470 return kDNSServiceErr_NoError;