c-capnproto/capn-stream.c
Baruch Even 24ec009d67 Use constants where possible
The hdr variable gets the same constants as value but it is easier to
understand that the constants are used than the hdr which needs to be
traced to the value it received.
2014-08-06 22:28:24 +03:00

191 lines
3.5 KiB
C

/* vim: set sw=8 ts=8 sts=8 noet: */
#include "capn.h"
#include <string.h>
#ifndef min
static int min(int a, int b) { return (a < b) ? a : b; }
#endif
int capn_deflate(struct capn_stream* s) {
if (s->avail_in % 8) {
return CAPN_MISALIGNED;
}
while (s->avail_in) {
int i, sz;
uint8_t hdr = 0;
uint8_t *p;
if (!s->avail_out)
return CAPN_NEED_MORE;
if (s->raw > 0) {
sz = min(s->raw, min(s->avail_in, s->avail_out));
memcpy(s->next_out, s->next_in, sz);
s->next_out += sz;
s->next_in += sz;
s->avail_out -= sz;
s->avail_in -= sz;
s->raw -= sz;
continue;
}
if (s->avail_in < 8)
return CAPN_NEED_MORE;
sz = 0;
for (i = 0; i < 8; i++) {
if (s->next_in[i]) {
sz ++;
hdr |= 1 << i;
}
}
switch (sz) {
case 0:
if (s->avail_out < 2)
return CAPN_NEED_MORE;
s->next_out[0] = 0;
for (sz = 1; sz < min(s->avail_in/8, 256); sz++) {
if (((uint64_t*) s->next_in)[sz] != 0) {
break;
}
}
s->next_out[1] = (uint8_t) (sz-1);
s->next_in += sz*8;
s->avail_in -= sz*8;
s->next_out += 2;
s->avail_out -= 2;
continue;
case 8:
if (s->avail_out < 10)
return CAPN_NEED_MORE;
s->next_out[0] = 0xFF;
memcpy(s->next_out+1, s->next_in, 8);
s->next_in += 8;
s->avail_in -= 8;
s->raw = min(s->avail_in, 256*8);
if ((p = (uint8_t*) memchr(s->next_in, 0, s->raw)) != NULL) {
s->raw = (p - s->next_in) & ~7;
}
s->next_out[9] = (uint8_t) (s->raw/8);
s->next_out += 10;
s->avail_out -= 10;
continue;
default:
if (s->avail_out < 1 + sz)
return CAPN_NEED_MORE;
*(s->next_out++) = hdr;
for (i = 0; i < 8; i++) {
if (s->next_in[i]) {
*(s->next_out++) = s->next_in[i];
}
}
s->avail_out -= sz + 1;
s->next_in += 8;
s->avail_in -= 8;
continue;
}
}
return 0;
}
int capn_inflate(struct capn_stream* s) {
if (s->avail_out % 8) {
return CAPN_MISALIGNED;
}
while (s->avail_out) {
int i, sz;
uint8_t hdr;
if (s->zeros > 0) {
sz = min(s->avail_out, s->zeros);
memset(s->next_out, 0, sz);
s->next_out += sz;
s->avail_out -= sz;
s->zeros -= sz;
continue;
}
if (s->raw > 0) {
if (s->avail_in == 0)
return CAPN_NEED_MORE;
sz = min(min(s->avail_out, s->raw), s->avail_in);
memcpy(s->next_out, s->next_in, sz);
s->next_in += sz;
s->next_out += sz;
s->avail_in -= sz;
s->avail_out -= sz;
s->raw -= sz;
continue;
}
if (s->avail_in == 0)
return 0;
else if (s->avail_in < 2)
return CAPN_NEED_MORE;
switch (s->next_in[0]) {
case 0xFF:
/* 0xFF is followed by 8 bytes raw, followed by
* a byte with length in words to read raw */
if (s->avail_in < 10)
return CAPN_NEED_MORE;
memcpy(s->next_out, s->next_in+1, 8);
s->raw = (int) s->next_in[9] * 8;
s->next_in += 10;
s->avail_in -= 10;
s->next_out += 8;
s->avail_out -= 8;
continue;
case 0x00:
/* 0x00 is followed by a single byte indicating
* the count of consecutive zero value words
* minus 1 */
s->zeros = (int) (s->next_in[1] + 1) * 8;
s->next_in += 2;
s->avail_in -= 2;
continue;
default:
sz = 0;
hdr = s->next_in[1];
for (i = 0; i < 8; i++) {
if (hdr & (1 << i))
sz++;
}
if (s->avail_in < 2 + sz)
return CAPN_NEED_MORE;
s->next_in += 2;
for (i = 0; i < 8; i++) {
if (hdr & (1 << i)) {
*(s->next_out++) = *(s->next_in++);
} else {
*(s->next_out++) = 0;
}
}
s->avail_out -= 8;
s->avail_in -= 2 + sz;
continue;
}
}
return 0;
}