sandi-0.1: csrc/b85.c
// Copyright: (c) Magnus Therning, 2012
// License: BSD3, found in the LICENSE file
#include <assert.h>
#include <string.h>
#include "b85.h"
uint8_t zeroes[] = { 0, 0, 0, 0 };
uint8_t spaces[] = { 0x20, 0x20, 0x20, 0x20 };
void b85_enc_part(uint8_t const *src, size_t srclen,
uint8_t *dst, size_t *dstlen,
uint8_t const **rem, size_t *remlen)
{
assert(src || 0 == srclen);
assert(dst);
assert(dstlen);
assert(rem);
assert(remlen);
size_t od = *dstlen, i;
for(i = 0, *dstlen = 0; i + 4 <= srclen && *dstlen < od; i += 4) {
if(memcmp(src + i, zeroes, 4) == 0) {
dst[*dstlen] = 'z';
*dstlen += 1;
} else if(memcmp(src + i, spaces, 4) == 0) {
dst[*dstlen] = 'y';
*dstlen += 1;
} else {
if(od < *dstlen + 5) goto exit;
uint32_t v = (src[i] << 24) | (src[i+1] << 16) | (src[i+2] << 8) | src[i+3];
dst[*dstlen + 4] = v % 85 + 33; v /= 85;
dst[*dstlen + 3] = v % 85 + 33; v /= 85;
dst[*dstlen + 2] = v % 85 + 33; v /= 85;
dst[*dstlen + 1] = v % 85 + 33; v /= 85;
dst[*dstlen] = v % 85 + 33;
*dstlen += 5;
}
}
exit:
*rem = src + i;
*remlen = srclen - i;
}
int b85_enc_final(uint8_t const *src, size_t srclen,
uint8_t *dst, size_t *dstlen)
{
assert(src || 0 == srclen);
assert(dst);
assert(dstlen);
switch(srclen) {
uint32_t v;
case 0:
*dstlen = 0;
return(0);
break;
case 1:
v = (src[0] << 24) | 1;
v /= 85; v /= 85; v /= 85;
dst[1] = v % 85 + 33; v /= 85;
dst[0] = v % 85 + 33;
*dstlen = 2;
return(0);
break;
case 2:
v = (src[0] << 24) | (src[1] << 16) | 1;
v /= 85; v /= 85;
dst[2] = v % 85 + 33; v /= 85;
dst[1] = v % 85 + 33; v /= 85;
dst[0] = v % 85 + 33;
*dstlen = 3;
return(0);
break;
case 3:
v = (src[0] << 24) | (src[1] << 16) |(src[2] << 8) | 1;
v /= 85;
dst[3] = v % 85 + 33; v /= 85;
dst[2] = v % 85 + 33; v /= 85;
dst[1] = v % 85 + 33; v /= 85;
dst[0] = v % 85 + 33;
*dstlen = 4;
return(0);
break;
default:
return(1);
break;
}
}
static uint8_t const decmap[] = {
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
int b85_dec_part(uint8_t const *src, size_t srclen,
uint8_t *dst, size_t *dstlen,
uint8_t const **rem, size_t *remlen)
{
assert(src || 0 == srclen);
assert(dst);
assert(dstlen);
assert(rem);
assert(remlen);
size_t od = *dstlen, i;
int res = 0;
for(i = 0, *dstlen = 0; i < srclen && *dstlen + 4 <= od; *dstlen += 4) {
switch(src[i]) {
uint32_t o0, o1, o2, o3, o4, v;
case 'z':
dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0;
i++;
break;
case 'y':
dst[*dstlen + 3] = dst[*dstlen + 2] = dst[*dstlen + 1] = dst[*dstlen] = 0x20;
i++;
break;
default:
if(srclen < i + 5) { res = 0; goto exit; }
o0 = decmap[src[i]];
o1 = decmap[src[i + 1]];
o2 = decmap[src[i + 2]];
o3 = decmap[src[i + 3]];
o4 = decmap[src[i + 4]];
if(0x80 & (o0 | o1 | o2 | o3 | o4)) { res = 1; goto exit; }
v = o0 * 52200625; // 85 ** 4
v += o1 * 614125; // 85 ** 3
v += o2 * 7225; // 85 ** 2
v += o3 * 85; // 85 ** 1
v += o4; // 85 ** 0
dst[*dstlen + 3] = v & 0xff; v = v >> 8;
dst[*dstlen + 2] = v & 0xff; v = v >> 8;
dst[*dstlen + 1] = v & 0xff; v = v >> 8;
dst[*dstlen + 0] = v & 0xff;
i += 5;
break;
}
}
exit:
*rem = src + i;
*remlen = srclen - i;
return(res);
}
int b85_dec_final(uint8_t const *src, size_t srclen,
uint8_t *dst, size_t *dstlen)
{
assert(src || 0 == srclen);
assert(dst);
assert(dstlen);
switch(srclen) {
uint32_t o0, o1, o2, o3, o4, v;
case 0:
*dstlen = 0;
return(0);
break;
case 2:
o0 = decmap[src[0]];
o1 = decmap[src[1]];
o2 = decmap['u'];
o3 = decmap['u'];
o4 = decmap['u'];
if(0x80 & ( o0 | o1)) { return(1); }
v = o0 * 52200625; // 85 ** 4
v += o1 * 614125; // 85 ** 3
v += o2 * 7225; // 85 ** 2
v += o3 * 85; // 85 ** 1
v += o4; // 85 ** 0
v = v >> 24;
dst[0] = v & 0xff;
*dstlen = 1;
return(0);
break;
case 3:
o0 = decmap[src[0]];
o1 = decmap[src[1]];
o2 = decmap[src[2]];
o3 = decmap['u'];
o4 = decmap['u'];
if(0x80 & ( o0 | o1 | o2)) { return(1); }
v = o0 * 52200625; // 85 ** 4
v += o1 * 614125; // 85 ** 3
v += o2 * 7225; // 85 ** 2
v += o3 * 85; // 85 ** 1
v += o4; // 85 ** 0
v = v >> 16;
dst[1] = v & 0xff; v = v >> 8;
dst[0] = v & 0xff;
*dstlen = 2;
return(0);
break;
case 4:
o0 = decmap[src[0]];
o1 = decmap[src[1]];
o2 = decmap[src[2]];
o3 = decmap[src[3]];
o4 = decmap['u'];
if(0x80 & ( o0 | o1 | o2 | o3)) { return(1); }
v = o0 * 52200625; // 85 ** 4
v += o1 * 614125; // 85 ** 3
v += o2 * 7225; // 85 ** 2
v += o3 * 85; // 85 ** 1
v += o4; // 85 ** 0
v = v >> 8;
dst[2] = v & 0xff; v = v >> 8;
dst[1] = v & 0xff; v = v >> 8;
dst[0] = v & 0xff;
*dstlen = 3;
return(0);
break;
default:
return(1);
break;
}
}