Blame base64.c

Packit 272fb1
/*
Packit 272fb1
 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
Packit 272fb1
 *
Packit 272fb1
 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
Packit 272fb1
 */
Packit 272fb1
/*
Packit 272fb1
 * These base64 routines are derived from the metamail-2.7 sources which
Packit 272fb1
 * state the following copyright notice:
Packit 272fb1
 *
Packit 272fb1
 * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
Packit 272fb1
 *
Packit 272fb1
 * Permission to use, copy, modify, and distribute this material 
Packit 272fb1
 * for any purpose and without fee is hereby granted, provided 
Packit 272fb1
 * that the above copyright notice and this permission notice 
Packit 272fb1
 * appear in all copies, and that the name of Bellcore not be 
Packit 272fb1
 * used in advertising or publicity pertaining to this 
Packit 272fb1
 * material without the specific, prior written permission 
Packit 272fb1
 * of an authorized representative of Bellcore.  BELLCORE 
Packit 272fb1
 * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
Packit 272fb1
 * OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
Packit 272fb1
 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
Packit 272fb1
 */
Packit 272fb1
Packit 272fb1
#ifndef lint
Packit 272fb1
#ifdef	DOSCCS
Packit 272fb1
static char sccsid[] = "@(#)base64.c	2.14 (gritter) 4/21/06";
Packit 272fb1
#endif
Packit 272fb1
#endif /* not lint */
Packit 272fb1
Packit 272fb1
/*
Packit 272fb1
 * Mail -- a mail program
Packit 272fb1
 *
Packit 272fb1
 * base64 functions
Packit 272fb1
 */
Packit 272fb1
Packit 272fb1
#include "rcv.h"
Packit 272fb1
#include "extern.h"
Packit 272fb1
Packit 272fb1
static const char b64table[] =
Packit 272fb1
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit 272fb1
static const signed char b64index[] = {
Packit 272fb1
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
Packit 272fb1
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
Packit 272fb1
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
Packit 272fb1
	52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
Packit 272fb1
	-1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
Packit 272fb1
	15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
Packit 272fb1
	-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
Packit 272fb1
	41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
Packit 272fb1
};
Packit 272fb1
Packit 272fb1
#define char64(c)  ((c) < 0 ? -1 : b64index[(int)(c)])
Packit 272fb1
Packit 272fb1
static signed char *ctob64(unsigned char *p, int pad);
Packit 272fb1
Packit 272fb1
/*
Packit 272fb1
 * Convert three characters to base64.
Packit 272fb1
 */
Packit 272fb1
static signed char *
Packit 272fb1
ctob64(unsigned char *p, int pad)
Packit 272fb1
{
Packit 272fb1
	static signed char b64[4];
Packit 272fb1
Packit 272fb1
	b64[0] = b64table[p[0] >> 2];
Packit 272fb1
	b64[1] = b64table[((p[0] & 0x3) << 4) | ((p[1] & 0xF0) >> 4)];
Packit 272fb1
	if (pad == 2) {
Packit 272fb1
		b64[1] = b64table[(p[0] & 0x3) << 4];
Packit 272fb1
		b64[2] = b64[3] = '=';
Packit 272fb1
	} else if (pad == 1) {
Packit 272fb1
		b64[2] = b64table[((p[1] & 0xF) << 2)];
Packit 272fb1
		b64[3] = '=';
Packit 272fb1
	} else {
Packit 272fb1
		b64[2] = b64table[((p[1] & 0xF) << 2) | ((p[2] & 0xC0) >> 6)];
Packit 272fb1
		b64[3] = b64table[p[2] & 0x3F];
Packit 272fb1
	}
Packit 272fb1
	return b64;
Packit 272fb1
}
Packit 272fb1
Packit 272fb1
char *
Packit 272fb1
strtob64(const char *p)
Packit 272fb1
{
Packit 272fb1
	return memtob64(p, strlen(p));
Packit 272fb1
}
Packit 272fb1
Packit 272fb1
char *
Packit 272fb1
memtob64(const void *vp, size_t isz)
Packit 272fb1
{
Packit 272fb1
	char	q[3];
Packit 272fb1
	const char	*p = vp;
Packit 272fb1
	signed char	*h;
Packit 272fb1
	size_t	c = 0;
Packit 272fb1
	int	i, l = 0, sz = 0, pads;
Packit 272fb1
	char	*rs = NULL;
Packit 272fb1
Packit 272fb1
	if (isz == 0) {
Packit 272fb1
		rs = smalloc(1);
Packit 272fb1
		*rs = '\0';
Packit 272fb1
		return rs;
Packit 272fb1
	}
Packit 272fb1
	do {
Packit 272fb1
		for (pads = 2, i = 0; i <= 2; i++, pads--) {
Packit 272fb1
			q[i] = p[c++];
Packit 272fb1
			if (c == isz)
Packit 272fb1
				break;
Packit 272fb1
		}
Packit 272fb1
		h = ctob64((unsigned char *)q, pads);
Packit 272fb1
		if (l + 5 >= sz)
Packit 272fb1
			rs = srealloc(rs, sz = l + 100);
Packit 272fb1
		for (i = 0; i < 4; i++)
Packit 272fb1
			rs[l++] = h[i];
Packit 272fb1
	} while (c < isz);
Packit 272fb1
	rs[l] = '\0';
Packit 272fb1
	return rs;
Packit 272fb1
}
Packit 272fb1
Packit 272fb1
/*
Packit 272fb1
 * Write to a file converting to base64. The input must be aligned
Packit 272fb1
 * e.g. at 972 character bounds.
Packit 272fb1
 */
Packit 272fb1
size_t
Packit 272fb1
mime_write_tob64(struct str *in, FILE *fo, int is_header)
Packit 272fb1
{
Packit 272fb1
	char *p, *upper, q[3];
Packit 272fb1
	signed char *h;
Packit 272fb1
	int i, l, pads;
Packit 272fb1
	size_t sz;
Packit 272fb1
Packit 272fb1
	sz = 0;
Packit 272fb1
	upper = in->s + in->l;
Packit 272fb1
	for (p = in->s, l = 0; p < upper; ) {
Packit 272fb1
		for (pads = 2, i = 0; i <= 2; i++, pads--) {
Packit 272fb1
			q[i] = *p++;
Packit 272fb1
			if (p == upper)
Packit 272fb1
				break;
Packit 272fb1
		}
Packit 272fb1
		h = ctob64((unsigned char *)q, pads);
Packit 272fb1
		fwrite(h, sizeof(char), 4, fo);
Packit 272fb1
		sz += 4, l += 4;
Packit 272fb1
		if (l >= 71) {
Packit 272fb1
			putc('\n', fo), sz++;
Packit 272fb1
			l = 0;
Packit 272fb1
		}
Packit 272fb1
	}
Packit 272fb1
	if (l != 0 && !is_header) {
Packit 272fb1
		putc('\n', fo), sz++;
Packit 272fb1
	}
Packit 272fb1
	return sz;
Packit 272fb1
}
Packit 272fb1
Packit 272fb1
/*
Packit 272fb1
 * Decode from base64.
Packit 272fb1
 */
Packit 272fb1
void 
Packit 272fb1
mime_fromb64(struct str *in, struct str *out, int is_text)
Packit 272fb1
{
Packit 272fb1
	char *p, *q, *upper;
Packit 272fb1
	signed char c, d, e, f, g;
Packit 272fb1
	int done = 0, newline = 0;
Packit 272fb1
Packit 272fb1
	out->s = smalloc(in->l * 3 / 4 + 2);
Packit 272fb1
	out->l = 0;
Packit 272fb1
	upper = in->s + in->l;
Packit 272fb1
	for (p = in->s, q = out->s; p < upper; ) {
Packit 272fb1
		while (c = *p++, whitechar(c));
Packit 272fb1
		if (p >= upper) break;
Packit 272fb1
		if (done) continue;
Packit 272fb1
		while (d = *p++, whitechar(d));
Packit 272fb1
		if (p >= upper) break;
Packit 272fb1
		while (e = *p++, whitechar(e));
Packit 272fb1
		if (p >= upper) break;
Packit 272fb1
		while (f = *p++, whitechar(f));
Packit 272fb1
		if (c == '=' || d == '=') {
Packit 272fb1
			done = 1;
Packit 272fb1
			continue;
Packit 272fb1
		}
Packit 272fb1
		c = char64(c);
Packit 272fb1
		d = char64(d);
Packit 272fb1
		g = ((c << 2) | ((d & 0x30) >> 4));
Packit 272fb1
		if (is_text) {
Packit 272fb1
			if (g == '\r') {
Packit 272fb1
				newline = 1;
Packit 272fb1
			} else if (g == '\n' && newline) {
Packit 272fb1
				q--;
Packit 272fb1
				out->l--;
Packit 272fb1
				newline = 0;
Packit 272fb1
			} else {
Packit 272fb1
				newline = 0;
Packit 272fb1
			}
Packit 272fb1
		}
Packit 272fb1
		*q++ = g;
Packit 272fb1
		out->l++;
Packit 272fb1
		if (e == '=') {
Packit 272fb1
			done = 1;
Packit 272fb1
		} else {
Packit 272fb1
			e = char64(e);
Packit 272fb1
			g = (((d & 0xF) << 4) | ((e & 0x3C) >> 2));
Packit 272fb1
			if (is_text) {
Packit 272fb1
				if (g == '\r') {
Packit 272fb1
					newline = 1;
Packit 272fb1
				} else if (g == '\n' && newline) {
Packit 272fb1
					q--;
Packit 272fb1
					out->l--;
Packit 272fb1
					newline = 0;
Packit 272fb1
				} else {
Packit 272fb1
					newline = 0;
Packit 272fb1
				}
Packit 272fb1
			}
Packit 272fb1
			*q++ = g;
Packit 272fb1
			out->l++;
Packit 272fb1
			if (f == '=') {
Packit 272fb1
				done = 1;
Packit 272fb1
			} else {
Packit 272fb1
				f = char64(f);
Packit 272fb1
				g = (((e & 0x03) << 6) | f);
Packit 272fb1
				if (is_text) {
Packit 272fb1
					if (g == '\r') {
Packit 272fb1
						newline = 1;
Packit 272fb1
					} else if (g == '\n' && newline) {
Packit 272fb1
						q--;
Packit 272fb1
						out->l--;
Packit 272fb1
						newline = 0;
Packit 272fb1
					} else {
Packit 272fb1
						newline = 0;
Packit 272fb1
					}
Packit 272fb1
				}
Packit 272fb1
				*q++ = g;
Packit 272fb1
				out->l++;
Packit 272fb1
			}
Packit 272fb1
		}
Packit 272fb1
	}
Packit 272fb1
	return;
Packit 272fb1
}
Packit 272fb1
Packit 272fb1
/*
Packit 272fb1
 * Buffer the base64 input so mime_fromb64 gets always multiples of
Packit 272fb1
 * 4 characters.
Packit 272fb1
 * As we have only one buffer, this function is not reentrant.
Packit 272fb1
 */
Packit 272fb1
void
Packit 272fb1
mime_fromb64_b(struct str *in, struct str *out, int is_text, FILE *f)
Packit 272fb1
{
Packit 272fb1
	static signed char b[4];
Packit 272fb1
	static int n;
Packit 272fb1
	static FILE *f_b = (FILE *)-1;
Packit 272fb1
	signed char c;
Packit 272fb1
	int i;
Packit 272fb1
	struct str nin;
Packit 272fb1
Packit 272fb1
	nin.s = smalloc(in->l + n);
Packit 272fb1
	if (n != 0 && f_b == f) {
Packit 272fb1
		for (nin.l = 0; nin.l < n; nin.l++)
Packit 272fb1
			nin.s[nin.l] = b[nin.l];
Packit 272fb1
	} else {
Packit 272fb1
		nin.l = 0;
Packit 272fb1
		n = 0;
Packit 272fb1
	}
Packit 272fb1
Packit 272fb1
	for (i = 0; i <= in->l; i++) {
Packit 272fb1
		c = in->s[i];
Packit 272fb1
		if (char64(c) == -1 && c != '=')
Packit 272fb1
			continue;
Packit 272fb1
		b[n] = nin.s[nin.l++] = c;
Packit 272fb1
		if (n >= 3)
Packit 272fb1
			n = 0;
Packit 272fb1
		else
Packit 272fb1
			n++;
Packit 272fb1
	}
Packit 272fb1
	nin.l -= n;
Packit 272fb1
	mime_fromb64(&nin, out, is_text);
Packit 272fb1
	free(nin.s);
Packit 272fb1
	f_b = f;
Packit 272fb1
}