/*
 * Doom PostScript map generator.
 * Copyright James Bonfield, 3/3/94 
 */

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#include "wad.h"

#ifdef BIG_ENDIAN
/*
 * Big endian machines need to swap around the bytes they read in.
 * These include Sun machines.
 */

void swap4(int4 *i) {
    int4 tmp;
    ((char *)&tmp)[0] = ((char *)i)[3];
    ((char *)&tmp)[1] = ((char *)i)[2];
    ((char *)&tmp)[2] = ((char *)i)[1];
    ((char *)&tmp)[3] = ((char *)i)[0];
    *i = tmp;
}

void swap2(int2 *i) {
    int2 tmp;
    ((char *)&tmp)[0] = ((char *)i)[1];
    ((char *)&tmp)[1] = ((char *)i)[0];
    *i = tmp;
}

#else
/*
 * Little endians (eg DECstations, SGI, Alphas) have it easy - they need to
 * do nothing.
 */
#    define swap4(a)
#    define swap2(a)

#endif

struct directory *open_wad(char *file, int *fd, int *size) {
    struct wad_header h;
    struct directory *d;
    int i;

    if (-1 == (*fd = open(file, O_RDONLY))) {
	perror(file);
	return (struct directory *)0;
    }

    (void)read(*fd, &h, sizeof(h));
    swap4(&h.magic);
    swap4(&h.dir_size);
    swap4(&h.dir_off);

    if (NULL == (d = (struct directory *)calloc(h.dir_size, sizeof(*d)))) {
	fprintf(stderr, "Couldn't allocated %d bytes.\n",
		h.dir_size * sizeof(int));
	return (struct directory *)0;
    }

    *size = h.dir_size;

    lseek(*fd, h.dir_off, SEEK_SET);
    (void)read(*fd, d, *size * sizeof(*d));

#ifdef BIG_ENDIAN
    for (i = 0; i < *size; i++) {
	swap4(&d[i].start);
	swap4(&d[i].length);
    }
#endif

    return d;
}

int get_index(struct directory *d, int size, char *name, int start) {
    int i;

    for (i = start; i < size; i++) {
	if (strncmp(d[i].name, name, 8) == 0)
	    return i;
    }

    return 0;
}

linedef *read_linedefs(int fd, struct directory *d, int size, int start,
		       int *num) {
    int index;
    linedef *indexp;
    int i;
    
    index = get_index(d, size, "LINEDEFS", start);
    indexp = (linedef *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(linedef);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i].from_vertex);
	swap2(&indexp[i].to_vertex);
	swap2(&indexp[i].attrib);
	swap2(&indexp[i].type);
	swap2(&indexp[i].trigger);
	swap2(&indexp[i].sidedef1);
	swap2(&indexp[i].sidedef2);
    }
#endif

    return indexp;
}

vertex *read_vertexes(int fd, struct directory *d, int size, int start,
		      int *num) {
    int index;
    vertex *indexp;
    int i;
    
    index = get_index(d, size, "VERTEXES", start);
    indexp = (vertex *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(vertex);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i].x);
	swap2(&indexp[i].y);
    }
#endif

    return indexp;
}

blockmap *read_blockmap(int fd, struct directory *d, int size, int start,
		   int *num) {
    int index;
    blockmap *indexp;
    int i;

    index = get_index(d, size, "BLOCKMAP", start);
    indexp = (blockmap *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(blockmap);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i]);
    }
#endif

    return indexp;
}

sidedef *read_sidedefs(int fd, struct directory *d, int size, int start,
		       int *num) {
    int index;
    sidedef *indexp;
    int i;

    index = get_index(d, size, "SIDEDEFS", start);
    indexp = (sidedef *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(sidedef);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i].x);
	swap2(&indexp[i].y);
	swap2(&indexp[i].sector);
    }
#endif

    return indexp;
}

sector *read_sectors(int fd, struct directory *d, int size, int start,
		    int *num) {
    int index;
    sector *indexp;
    int i;

    index = get_index(d, size, "SECTORS", start);
    indexp = (sector *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(sector);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i].bot_pos);
	swap2(&indexp[i].top_pos);
	swap2(&indexp[i].special);
	swap2(&indexp[i].trigger);
    }
#endif

    return indexp;
}

thing *read_things(int fd, struct directory *d, int size, int start,
		   int *num) {
    int index;
    thing *indexp;
    int i;

    index = get_index(d, size, "THINGS", start);
    indexp = (thing *)malloc(d[index].length);
    lseek(fd, d[index].start, SEEK_SET);
    read(fd, indexp, d[index].length);
    *num = d[index].length / sizeof(thing);
#ifdef BIG_ENDIAN
    for (i = 0; i <*num; i++) {
	swap2(&indexp[i].x);
	swap2(&indexp[i].y);
	swap2(&indexp[i].angle);
	swap2(&indexp[i].type);
	swap2(&indexp[i].attrib);
    }
#endif

    return indexp;
}
