/*
- * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdio.h>
-#include <strings.h>
#include <string.h>
+#include "common.h"
+#include "encoding.h"
-/* For FreeBSD */
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
+int
+build_hostname(char *buf, size_t buflen,
+ const char *data, const size_t datalen,
+ const char *topdomain, struct encoder *encoder, int maxlen)
+{
+ size_t space;
+ char *b;
-#define SPACING 63
-#define ENC_CHUNK 8
-#define RAW_CHUNK 5
+ space = MIN((size_t)maxlen, buflen) - strlen(topdomain) - 8;
+ /* 8 = 5 max header length + 1 dot before topdomain + 2 safety */
-static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-";
-static const char padder[] = " 1234";
-static char reverse32[128];
-static int reverse_init = 0;
+ if (!encoder->places_dots())
+ space -= (space / 57); /* space for dots */
-/* Eat 5 bytes from src, write 8 bytes to dest */
-static void
-encode_chunk(char *dest, const char *src)
-{
- unsigned char c;
+ memset(buf, 0, buflen);
- *dest++ = base32[(*src & 0xF8) >> 3]; /* 1111 1000 first byte */
+ encoder->encode(buf, &space, data, datalen);
- c = (*src++ & 0x07) << 2; /* 0000 0111 first byte */
- c |= ((*src & 0xC0) >> 6); /* 1100 0000 second byte */
- *dest++ = base32[(int) c];
+ if (!encoder->places_dots())
+ inline_dotify(buf, buflen);
- *dest++ = base32[(*src & 0x3E) >> 1]; /* 0011 1110 second byte */
+ b = buf;
+ b += strlen(buf);
- c = (*src++ & 0x01) << 4; /* 0000 0001 second byte */
- c |= ((*src & 0xF0) >> 4); /* 1111 0000 third byte */
- *dest++ = base32[(int) c];
-
- c = (*src++ & 0x0F) << 1; /* 0000 1111 third byte */
- c |= ((*src & 0x80) >> 7); /* 1000 0000 fourth byte */
- *dest++ = base32[(int) c];
-
- *dest++ = base32[(*src & 0x7C) >> 2]; /* 0111 1100 fourth byte */
+ /* move b back one step to see if the dot is there */
+ b--;
+ if (*b != '.')
+ *++b = '.';
+ b++;
+ /* move b ahead of the string so we can copy to it */
- c = (*src++ & 0x03) << 3; /* 0000 0011 fourth byte */
- c |= ((*src & 0xE0) >> 5); /* 1110 0000 fifth byte */
- *dest++ = base32[(int) c];
+ strncpy(b, topdomain, strlen(topdomain)+1);
- *dest++ = base32[*src++ & 0x1F]; /* 0001 1111 fifth byte */
+ return space;
}
-/* Eat 8 bytes from src, write 5 bytes to dest */
-static void
-decode_chunk(char *dest, char *src)
+int
+unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
{
- unsigned char c;
- int i;
-
- if (!reverse_init) {
- for (i = 0; i < 32; i++) {
- c = base32[i];
- reverse32[(int) c] = i;
- }
- reverse_init = 1;
- }
-
- c = reverse32[(int) *src++] << 3; /* Take bits 11111 from byte 1 */
- c |= (reverse32[(int) *src] & 0x1C) >> 2; /* Take bits 11100 from byte 2 */
- *dest++ = c;
-
- c = (reverse32[(int) *src++] & 0x3) << 6; /* Take bits 00011 from byte 2 */
- c |= reverse32[(int) *src++] << 1; /* Take bits 11111 from byte 3 */
- c |= (reverse32[(int) *src] & 0x10) >> 4; /* Take bits 10000 from byte 4 */
- *dest++ = c;
-
- c = (reverse32[(int) *src++] & 0xF) << 4; /* Take bits 01111 from byte 4 */
- c |= (reverse32[(int) *src] & 0x1E) >> 1; /* Take bits 11110 from byte 5 */
- *dest++ = c;
-
- c = reverse32[(int) *src++] << 7; /* Take bits 00001 from byte 5 */
- c |= reverse32[(int) *src++] << 2; /* Take bits 11111 from byte 6 */
- c |= (reverse32[(int) *src] & 0x18) >> 3; /* Take bits 11000 from byte 7 */
- *dest++ = c;
-
- c = (reverse32[(int) *src++] & 0x7) << 5; /* Take bits 00111 from byte 7 */
- c |= reverse32[(int) *src++]; /* Take bits 11111 from byte 8 */
- *dest++ = c;
+ if (!enc->eats_dots())
+ datalen = inline_undotify(data, datalen);
+ return enc->decode(buf, &buflen, data, datalen);
}
int
-encode_data(const char *buf, const size_t len, int space, char *dest)
+inline_dotify(char *buf, size_t buflen)
{
- int final;
- int write;
- int realwrite;
- int chunks;
- int leftovers;
- int i;
- char encoded[255];
- char padding[5];
- const char *dp;
- char *pp;
- char *ep;
-
- space -= space / SPACING;
- chunks = (space - 1) / ENC_CHUNK;
- while ((chunks + 1) * ENC_CHUNK + 1 > space) {
- chunks--;
- }
- write = RAW_CHUNK * chunks;
- write = MIN(write, len); /* do not use more bytes than is available; */
- final = (write == len); /* is this the last block? */
- chunks = write / RAW_CHUNK;
- leftovers = write % RAW_CHUNK;
-
- memset(encoded, 0, sizeof(encoded));
- ep = encoded;
- dp = buf;
- for (i = 0; i < chunks; i++) {
- encode_chunk(ep, dp);
- ep += ENC_CHUNK;
- dp += RAW_CHUNK;
- }
- realwrite = ENC_CHUNK * chunks;
- memset(padding, 0, sizeof(padding));
- pp = padding;
- if (leftovers) {
- pp += RAW_CHUNK - leftovers;
- memcpy(pp, dp, leftovers);
-
- pp = padding;
- *ep++ = padder[leftovers];
- encode_chunk(ep, pp);
-
- realwrite += ENC_CHUNK + 1; /* plus padding character */
+ unsigned dots;
+ unsigned pos;
+ unsigned total;
+ char *reader, *writer;
+
+ total = strlen(buf);
+ dots = total / 57;
+
+ writer = buf;
+ writer += total;
+ writer += dots;
+
+ total += dots;
+ if (strlen(buf) + dots > buflen) {
+ writer = buf;
+ writer += buflen;
+ total = buflen;
}
- ep = encoded;
- if (len > 0) {
- for (i = 1; i <= realwrite; i++) {
- if (i % SPACING == 0) {
- *dest++ = '.';
- }
- *dest++ = *ep++;
+
+ reader = writer - dots;
+ pos = (unsigned) (reader - buf) + 1;
+
+ while (dots) {
+ *writer-- = *reader--;
+ pos--;
+ if (pos % 57 == 0) {
+ *writer-- = '.';
+ dots--;
}
}
-
- return write;
+
+ /* return new length of string */
+ return total;
}
int
-decode_data(char *dest, int size, const char *src, char *srcend)
+inline_undotify(char *buf, size_t len)
{
- int len;
- int i;
- int chunks;
- int padded;
- char encoded[255];
- char padding[5];
- int enclen;
- char *pp;
- char *ep;
-
- memset(encoded, 0, sizeof(encoded));
- memset(dest, 0, size);
-
- /* First byte is not encoded */
- *dest++ = *src++;
- len = 1;
-
- ep = encoded;
- enclen = 0;
- while(enclen < sizeof(encoded) && src < srcend) {
- if(*src == '.') {
- src++;
+ unsigned pos;
+ unsigned dots;
+ char *reader, *writer;
+
+ writer = buf;
+ reader = writer;
+
+ pos = 0;
+ dots = 0;
+
+ while (pos < len) {
+ if (*reader == '.') {
+ reader++;
+ pos++;
+ dots++;
continue;
}
-
- *ep++ = *src++;
- enclen++;
- }
- chunks = enclen / 8;
- padded = enclen % 8;
-
- ep = encoded;
- for (i = 0; i < chunks-1; i++) {
- decode_chunk(dest, ep);
- dest += RAW_CHUNK;
- ep += ENC_CHUNK;
- len += RAW_CHUNK;
- }
- /* Read last chunk */
- if (padded) {
- pp = padding;
- padded = *ep++ - '0';
- decode_chunk(pp, ep);
- pp += RAW_CHUNK - padded;
- memcpy(dest, pp, padded);
- len += padded;
- } else {
- decode_chunk(dest, ep);
- len += RAW_CHUNK;
+ *writer++ = *reader++;
+ pos++;
}
- return len;
+ /* return new length of string */
+ return len - dots;
}
-