/* utils.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "gridpix.h"

/* like malloc, but will check return value and scream */
void *xmalloc(size_t size)
{
    void *vp = malloc(size) ;
    
    if (vp == NULL) {
	fprintf(stderr, "panic: cannot allocate %d bytes\n", size) ;
	exit(1) ;
    }
    return (vp) ;
}

/* convert integer from file to memory */
void fromfint(m_int_t *target, f_int_t source)
{
    int i ;
    m_int_t result = 0 ;

    for (i = 0 ; i < sizeof(f_int_t) ; i++)
	result = (result << 8) + source[sizeof(f_int_t)-i-1] ;

    *target = result ;
}

/* convert integer from memory to file */
void tofint(f_int_t *target, m_int_t source)
{
    int i ;

    for (i = 0 ; i < sizeof(f_int_t) ; i++) {
	(*target)[i] = source & 0xff ;
	source >>= 8 ;
    }
}

/* returns gpxtype */
int readheader(struct gridpix *gp, FILE *fp)
{
    char magic[4] ;
    struct gridheader1 gh1 ;		/* type 1 */
    struct gridheader2 gh2 ;		/* type 2 */
    int gpxtype = 0 ;
    int i ;

    if (fread(magic, sizeof(magic), 1, fp) < 1) {
	perror("fread") ;
	exit(1) ;
    }

    if (!strncmp(magic, Magic1, sizeof(magic))) {
	gpxtype = 1 ;
    }
    else if (!strncmp(magic, Magic2, sizeof(magic))) {
	gpxtype = 2 ;
    }
    else {
	fprintf(stderr, "error: magic number wrong\n") ;
	exit(1) ;
    }

    /* just for the heck of it */
    memcpy(&gh1.magic, magic, sizeof(magic));
    memcpy(&gh2.magic, magic, sizeof(magic));
    memcpy(&gp->header.magic, magic, sizeof(magic));

    if (gpxtype == 1) {
	if (fread(&gh1.headersize,
		  sizeof(gh1) - sizeof(magic), 1, fp) < 1) {
	    perror("fread") ;
	    exit(1) ;
	}
	gp->header.headersize = gh1.headersize ;
	gp->header.width = gh1.width ;
	gp->header.height = gh1.height ;
	gp->header.layers = gh1.layers ;
	gp->header.tilewidth = gh1.tilewidth ;
	gp->header.tileheight = gh1.tileheight ;
	gp->header.ratio = gh1.ratio ;
	gp->header.numfiles = gh1.numfiles ;
	for (i = 0 ; i < MaxLayers ; i++)
	    gp->header.layersize[i] = gh1.layersize[i] ;
    }
    else {
	/* type 2 */
	if (fread(&gh2.headersize,
		  sizeof(gh2) - sizeof(magic), 1, fp) < 1) {
	    perror("fread") ;
	    exit(1) ;
	}
	fromfint(&gp->header.headersize, gh2.headersize) ;
	fromfint(&gp->header.width, gh2.width) ;
	fromfint(&gp->header.height, gh2.height) ;
	fromfint(&gp->header.layers, gh2.layers) ;
	fromfint(&gp->header.tilewidth, gh2.tilewidth) ;
	fromfint(&gp->header.tileheight, gh2.tileheight) ;
	fromfint(&gp->header.ratio, gh2.ratio) ;
	fromfint(&gp->header.numfiles, gh2.numfiles) ;
	for (i = 0 ; i < MaxLayers ; i++)
	    fromfint(&gp->header.layersize[i], gh2.layersize[i]) ;
    }

    return gpxtype ;
}

/* always writes type 2 gridpix file, returns 0 for success */
int writeheader(struct gridpix *gp, FILE *fp)
{
    struct gridheader2 gh2 ;		/* type 2 */
    f_int_t	offset ;
    int i ;

    memcpy(&gh2.magic, Magic2, sizeof(gh2.magic));

    tofint(&gh2.headersize, gp->header.headersize) ;
    tofint(&gh2.width, gp->header.width) ;
    tofint(&gh2.height, gp->header.height) ;
    tofint(&gh2.layers, gp->header.layers) ;
    tofint(&gh2.tilewidth, gp->header.tilewidth) ;
    tofint(&gh2.tileheight, gp->header.tileheight) ;
    tofint(&gh2.ratio, gp->header.ratio) ;
    tofint(&gh2.numfiles, gp->header.numfiles) ;
    for (i = 0 ; i < MaxLayers ; i++)
	tofint(&gh2.layersize[i], gp->header.layersize[i]) ;
    tofint(&offset, gp->offsets[0]) ;

    fseek(fp, 0, SEEK_SET) ;
    fwrite(&gh2, sizeof(gh2), 1, fp) ;
    /* don't forget to write the offset of the first file */
    fwrite(&offset, sizeof(offset), 1, fp) ;

    return 0 ;
}
