server/src/kernel/binarystore.c

277 lines
6.5 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/* vi: set ts=2:
+-------------------+ Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
| (c) 1998 - 2008 | Katja Zedel <katze@felidae.kn-bremen.de>
+-------------------+
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include "config.h"
#include "textstore.h"
#include "save.h"
#include "version.h"
#include <util/base36.h>
#include <util/log.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <libxml/encoding.h>
#define file(store) (FILE *)((store)->userdata)
#define STREAM_VERSION 2
2011-03-07 08:02:35 +01:00
INLINE_FUNCTION size_t pack_int(int v, char *buffer)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
int sign = (v < 0);
2010-08-08 10:06:34 +02:00
if (sign) {
v = ~v + 1;
sign = 0x40;
}
2011-03-07 08:02:35 +01:00
if (v < 0x40) {
2010-08-08 10:06:34 +02:00
buffer[0] = (char)(v | sign);
return 1;
2011-03-07 08:02:35 +01:00
} else if (v < 0x2000) {
buffer[0] = (char)((v >> 6) | 0x80);
2010-08-08 10:06:34 +02:00
buffer[1] = (char)((v & 0x3F) | sign);
return 2;
2011-03-07 08:02:35 +01:00
} else if (v < 0x100000) {
buffer[0] = (char)(((v >> 13) & 0x7f) | 0x80);
buffer[1] = (char)(((v >> 6) & 0x7f) | 0x80);
2010-08-08 10:06:34 +02:00
buffer[2] = (char)((v & 0x3F) | sign);
return 3;
2011-03-07 08:02:35 +01:00
} else if (v < 0x8000000) {
buffer[0] = (char)(((v >> 20) & 0x7f) | 0x80);
buffer[1] = (char)(((v >> 13) & 0x7f) | 0x80);
buffer[2] = (char)(((v >> 6) & 0x7f) | 0x80);
2010-08-08 10:06:34 +02:00
buffer[3] = (char)((v & 0x3F) | sign);
return 4;
}
2011-03-07 08:02:35 +01:00
buffer[0] = (char)(((v >> 27) & 0x7f) | 0x80);
buffer[1] = (char)(((v >> 20) & 0x7f) | 0x80);
buffer[2] = (char)(((v >> 13) & 0x7f) | 0x80);
buffer[3] = (char)(((v >> 6) & 0x7f) | 0x80);
2010-08-08 10:06:34 +02:00
buffer[4] = (char)((v & 0x3F) | sign);
return 5;
}
2011-03-07 08:02:35 +01:00
INLINE_FUNCTION int unpack_int(const char *buffer)
2010-08-08 10:06:34 +02:00
{
int i = 0, v = 0;
while (buffer[i] & 0x80) {
v = (v << 7) | (buffer[i++] & 0x7f);
}
v = (v << 6) | (buffer[i] & 0x3f);
if (buffer[i] & 0x40) {
v = ~v + 1;
}
return v;
}
2011-03-07 08:02:35 +01:00
static int bin_w_brk(struct storage *store)
2010-08-08 10:06:34 +02:00
{
return 0;
}
2011-03-07 08:02:35 +01:00
static int bin_w_int_pak(struct storage *store, int arg)
2010-08-08 10:06:34 +02:00
{
char buffer[5];
size_t size = pack_int(arg, buffer);
return (int)fwrite(buffer, sizeof(char), size, file(store));
}
2011-03-07 08:02:35 +01:00
static int bin_r_int_pak(struct storage *store)
2010-08-08 10:06:34 +02:00
{
int v = 0;
char ch;
fread(&ch, sizeof(char), 1, file(store));
while (ch & 0x80) {
v = (v << 7) | (ch & 0x7f);
fread(&ch, sizeof(char), 1, file(store));
}
v = (v << 6) | (ch & 0x3f);
if (ch & 0x40) {
v = ~v + 1;
}
return v;
}
2011-03-07 08:02:35 +01:00
static int bin_w_int(struct storage *store, int arg)
2010-08-08 10:06:34 +02:00
{
return (int)fwrite(&arg, sizeof(arg), 1, file(store));
}
2011-03-07 08:02:35 +01:00
static int bin_r_int(struct storage *store)
2010-08-08 10:06:34 +02:00
{
int result;
fread(&result, sizeof(result), 1, file(store));
return result;
}
2011-03-07 08:02:35 +01:00
static int bin_w_flt(struct storage *store, float arg)
2010-08-08 10:06:34 +02:00
{
return (int)fwrite(&arg, sizeof(arg), 1, file(store));
}
2011-03-07 08:02:35 +01:00
static float bin_r_flt(struct storage *store)
2010-08-08 10:06:34 +02:00
{
float result;
fread(&result, sizeof(result), 1, file(store));
return result;
}
2011-03-07 08:02:35 +01:00
static int bin_w_str(struct storage *store, const char *tok)
2010-08-08 10:06:34 +02:00
{
int result;
2011-03-07 08:02:35 +01:00
if (tok == NULL || tok[0] == 0) {
2010-08-08 10:06:34 +02:00
result = store->w_int(store, 0);
} else {
int size = (int)strlen(tok);
result = store->w_int(store, size);
result += (int)fwrite(tok, size, 1, file(store));
}
return result;
}
2011-03-07 08:02:35 +01:00
#define FIX_INVALID_CHARS /* required for data pre-574 */
static char *bin_r_str(struct storage *store)
2010-08-08 10:06:34 +02:00
{
int len;
len = store->r_int(store);
2011-03-07 08:02:35 +01:00
if (len >= 0) {
char *result = malloc(len + 1);
2010-08-08 10:06:34 +02:00
fread(result, sizeof(char), len, file(store));
result[len] = 0;
#ifdef FIX_INVALID_CHARS
{
2011-03-07 08:02:35 +01:00
char *p = strpbrk(result, "\n\r");
2010-08-08 10:06:34 +02:00
while (p) {
2011-03-07 08:02:35 +01:00
log_error(("Invalid character %d in input string \"%s\".\n", *p,
result));
strcpy(p, p + 1);
2010-08-08 10:06:34 +02:00
p = strpbrk(p, "\n\r");
}
}
#endif
return result;
2011-03-07 08:02:35 +01:00
} else if (len < 0) {
2010-08-08 10:06:34 +02:00
log_error(("invalid string-length %d in input.\n", len));
}
return NULL;
}
2011-03-07 08:02:35 +01:00
static void bin_r_str_buf(struct storage *store, char *result, size_t size)
2010-08-08 10:06:34 +02:00
{
int i;
size_t rd, len;
i = store->r_int(store);
2011-03-07 08:02:35 +01:00
assert(i >= 0);
if (i == 0) {
2010-08-08 10:06:34 +02:00
result[0] = 0;
} else {
2011-03-07 08:02:35 +01:00
len = (size_t) i;
rd = MIN(len, size - 1);
2010-08-08 10:06:34 +02:00
fread(result, sizeof(char), rd, file(store));
2011-03-07 08:02:35 +01:00
if (rd < len) {
fseek(file(store), (long)(len - rd), SEEK_CUR);
result[size - 1] = 0;
2010-08-08 10:06:34 +02:00
} else {
result[len] = 0;
}
#ifdef FIX_INVALID_CHARS
{
2011-03-07 08:02:35 +01:00
char *p = strpbrk(result, "\n\r");
2010-08-08 10:06:34 +02:00
while (p) {
2011-03-07 08:02:35 +01:00
log_error(("Invalid character %d in input string \"%s\".\n", *p,
result));
strcpy(p, p + 1);
2010-08-08 10:06:34 +02:00
p = strpbrk(p, "\n\r");
}
}
#endif
}
}
2011-03-07 08:02:35 +01:00
static int bin_w_bin(struct storage *store, void *arg, size_t size)
2010-08-08 10:06:34 +02:00
{
int result;
int len = (int)size;
result = store->w_int(store, len);
2011-03-07 08:02:35 +01:00
if (len > 0) {
2010-08-08 10:06:34 +02:00
result += (int)fwrite(arg, len, 1, file(store));
}
return result;
}
2011-03-07 08:02:35 +01:00
static void bin_r_bin(struct storage *store, void *result, size_t size)
2010-08-08 10:06:34 +02:00
{
int len = store->r_int(store);
2011-03-07 08:02:35 +01:00
if (len > 0) {
if ((size_t) len > size) {
2010-08-08 10:06:34 +02:00
log_error(("destination buffer too small %d %u.\n", len, size));
fseek(file(store), len, SEEK_CUR);
} else {
fread(result, len, 1, file(store));
}
}
}
2011-03-07 08:02:35 +01:00
static int bin_open(struct storage *store, const char *filename, int mode)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *modes[] = { 0, "rb", "wb", "ab" };
FILE *F = fopen(filename, modes[mode]);
2010-08-08 10:06:34 +02:00
store->userdata = F;
2011-03-07 08:02:35 +01:00
store->encoding = XML_CHAR_ENCODING_UTF8; /* always utf8 it is */
2010-08-08 10:06:34 +02:00
if (F) {
2011-03-07 08:02:35 +01:00
if (mode == IO_READ) {
2010-08-08 10:06:34 +02:00
int stream_version = 0;
store->version = bin_r_int(store);
2011-03-07 08:02:35 +01:00
if (store->version >= INTPAK_VERSION) {
2010-08-08 10:06:34 +02:00
stream_version = bin_r_int(store);
}
2011-03-07 08:02:35 +01:00
if (stream_version <= 1) {
2010-08-08 10:06:34 +02:00
store->r_id = bin_r_int;
store->w_id = bin_w_int;
}
2011-03-07 08:02:35 +01:00
if (stream_version == 0) {
2010-08-08 10:06:34 +02:00
store->r_int = bin_r_int;
store->w_int = bin_w_int;
}
2011-03-07 08:02:35 +01:00
} else if (store->encoding == XML_CHAR_ENCODING_UTF8) {
store->version = RELEASE_VERSION;
2010-08-08 10:06:34 +02:00
bin_w_int(store, RELEASE_VERSION);
bin_w_int(store, STREAM_VERSION);
}
}
2011-03-07 08:02:35 +01:00
return (F == NULL);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int bin_close(struct storage *store)
2010-08-08 10:06:34 +02:00
{
return fclose(file(store));
}
const storage binary_store = {
2011-03-07 08:02:35 +01:00
bin_w_brk, /* newline (ignore) */
2010-08-08 10:06:34 +02:00
bin_w_int_pak, bin_r_int_pak, /* int storage */
2011-03-07 08:02:35 +01:00
bin_w_flt, bin_r_flt, /* float storage */
2010-08-08 10:06:34 +02:00
bin_w_int_pak, bin_r_int_pak, /* id storage */
2011-03-07 08:02:35 +01:00
bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */
bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */
bin_w_bin, bin_r_bin, /* binary storage */
2010-08-08 10:06:34 +02:00
bin_open, bin_close,
0, 0, NULL
};