#define RPLX_FILE_MIN_VERSION 0
#define RPLX_FILE_MAX_VERSION 0
#ifndef FILEDEBUG
#define FILEDEBUG 0
#else
#define FILEDEBUG 1
#endif
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <sys/param.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#if defined(__linux__)
#if !defined(__clang__)
#include <stdio.h>
#endif
#endif
#include "ktable.h"
#include "config.h"
#include "file.h"
static int write_int (FILE *out, int i) {
unsigned char str[4];
unsigned int iun = i;
str[3] = (iun >> 24) & 0xFF;
str[2] = (iun >> 16) & 0xFF;
str[1] = (iun >> 8) & 0xFF;
str[0] = iun & 0xFF;
return (fwrite(str, 4, 1, out) == 1);
}
static int read_int (FILE *in, int *i) {
unsigned char str[4];
size_t items_read = fread(str, 4, 1, in);
unsigned int iun = str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24);
*i = iun;
return (items_read == 1);
}
static int read_newline(FILE *stream) {
char dummy[1];
if (fread(dummy, 1, 1, stream) != 1) return FILE_ERR_READ;
if (dummy[0] != '\n') return FILE_ERR_READ;
return FILE_OK;
}
#define write_newline(stream) { \
written = fwrite("\n", 1, 1, (stream)); \
if (written != 1) return FILE_ERR_WRITE; \
}
int file_save (const char *filename, Chunk *chunk) {
FILE *out;
size_t bytes, written;
int ok;
out = fopen(filename, "wb");
if (!out) return FILE_ERR_NOFILE;
written = fwrite(FILE_MAGIC_NUMBER, sizeof(FILE_MAGIC_NUMBER), 1, out);
if (written != 1) return FILE_ERR_WRITE;
Ktable *kt = chunk->ktable;
assert( kt );
assert( kt->block );
assert( kt->blocknext > 0 );
assert( kt->elements );
assert( kt->size > 0 );
assert( kt->next > 0 );
#if FILEDEBUG
fprintf(stderr, "file_save: number of ktable entries is %d\n", kt->next - 1);
#endif
ok = write_int(out, kt->next - 1);
if (!ok) return FILE_ERR_WRITE;
#if FILEDEBUG
fprintf(stderr, "file_save: size of ktable block is %d\n", kt->blocknext);
#endif
ok = write_int(out, kt->blocknext);
if (!ok) return FILE_ERR_WRITE;
write_newline(out);
bytes = kt->next * sizeof(Ktable_element);
written = fwrite(kt->elements, bytes, 1, out);
if (written != 1) return FILE_ERR_WRITE;
write_newline(out);
written = fwrite(kt->block, kt->blocknext, 1, out);
if (written != 1) return FILE_ERR_WRITE;
write_newline(out);
#if FILEDEBUG
fprintf(stderr, "file_save: number of instructions is %zu\n", chunk->codesize);
#endif
ok = write_int(out, chunk->codesize);
#if FILEDEBUG
fprintf(stderr, "file_save: saved instruction size %s\n", ok ? "ok" : "ERROR");
#endif
if (!ok) return FILE_ERR_WRITE;
written = fwrite(chunk->code, sizeof(Instruction), chunk->codesize, out);
if (written != chunk->codesize) return FILE_ERR_WRITE;
#if FILEDEBUG
fprintf(stderr, "file_save: number of instructions written is %zu\n", written);
#endif
write_newline(out);
fclose(out);
return FILE_OK;
}
int file_load (const char *filename, Chunk *chunk) {
FILE *in;
size_t len;
int n, ok, blocksize;
size_t bytes;
char magic[sizeof(FILE_MAGIC_NUMBER)];
in = fopen(filename, "rb");
if (!in) return FILE_ERR_NOFILE;
len = fread(magic, sizeof(FILE_MAGIC_NUMBER), 1, in);
if (len != 1) return FILE_ERR_READ;
if (strncmp(magic, FILE_MAGIC_NUMBER, sizeof(FILE_MAGIC_NUMBER)) != 0)
return FILE_ERR_MAGIC_NUMBER;
#if FILEDEBUG
fprintf(stderr, "file_load: magic number ok\n");
#endif
ok = read_int(in, &n);
if (!ok) return FILE_ERR_READ;
if ((n < 0) || (n > MAX_CAPLISTSIZE)) return FILE_ERR_KTABLE_LEN;
#if FILEDEBUG
fprintf(stderr, "file_load: number of ktable entries is %d\n", n);
#endif
ok = read_int(in, &blocksize);
if (!ok) return FILE_ERR_READ;
#if FILEDEBUG
fprintf(stderr, "file_load: size of ktable block is %d\n", blocksize);
#endif
if ((blocksize < 0) || (blocksize > MAX_INSTLEN_BYTES)) return FILE_ERR_KTABLE_SIZE;
if (read_newline(in) < 0) return FILE_ERR_READ;
Ktable *kt = ktable_new(n, blocksize);
kt->blocksize = blocksize;
kt->size = n;
kt->next = n + 1;
bytes = (n+1) * sizeof(Ktable_element);
ok = fread(kt->elements, bytes, 1, in);
#if FILEDEBUG
fprintf(stderr, "file_load: read of elements %s\n",
(ok != -1) ? "succeeded" : "failed");
#endif
if (ok != 1) return FILE_ERR_READ;
if (read_newline(in) < 0) return FILE_ERR_READ;
ok = fread(kt->block, kt->blocksize, 1, in);
#if FILEDEBUG
fprintf(stderr, "file_load: read of block %s\n",
(ok != -1) ? "succeeded" : "failed");
#endif
if (ok != 1) return FILE_ERR_READ;
kt->blocknext = kt->blocksize;
if (read_newline(in) < 0) return FILE_ERR_READ;
ok = read_int(in, &n);
if (ok != 1) return FILE_ERR_READ;
bytes = n * sizeof(Instruction);
#if FILEDEBUG
fprintf(stderr, "file_load: number of instructions is %d, bytes is %zu\n", n, bytes);
#endif
if ((n < 0) || (bytes > MAX_INSTLEN_BYTES)) return FILE_ERR_INST_LEN;
Instruction *buf = (Instruction *) malloc((size_t) bytes);
if (!buf) return FILE_ERR_MEM;
len = fread((char *)buf, sizeof(Instruction), n, in);
if (len != (size_t) n) return FILE_ERR_READ;
#if FILEDEBUG
fprintf(stderr, "file_load: number of instructions read is %d\n", n);
#endif
if (read_newline(in) < 0) return FILE_ERR_READ;
chunk->codesize = (size_t) n;
chunk->code = buf;
chunk->ktable = kt;
chunk->rpl_major = 0;
chunk->rpl_minor = 0;
chunk->file_version = 0;
chunk->filename = strndup(filename, MAXPATHLEN);
fclose(in);
return FILE_OK;
}