/**********************************************************************
 *
 *  geo_tiffp.c  Private TIFF interface module for GEOTIFF
 *
 *    This module implements the interface between the GEOTIFF
 *    tag parser and the TIFF i/o module. The current setup
 *    relies on the "libtiff" code, but if you use your own
 *    TIFF reader software, you may replace the module implementations
 *    here with your own calls. No "libtiff" dependencies occur
 *    anywhere else in this code.
 *
 * copyright (c) 1995   Niles D. Ritter
 *
 * Permission granted to use this software, so long as this copyright
 * notice accompanies any products derived therefrom.
 *
 **********************************************************************/

#include "geotiff.h"    /* public GTIFF interface */

#include "geo_tiffp.h"  /* Private TIFF interface */
#include "geo_keyp.h"   /* Private GTIFF interface */

/* tiff size array global */
gsize_t _gtiff_size[] = { 0, 1, 2, 4, 8, 1, 4, 8, 1, 2, 4, 1 };

static int        _GTIFGetField (tiff_t *tif, pinfo_t tag, int *count, void *value );
static int        _GTIFSetField (tiff_t *tif, pinfo_t tag, int  count, void *value );
static tagtype_t  _GTIFTagType  (tiff_t *tif, pinfo_t tag);

/*
 * Set up default TIFF handlers.
 */
void _GTIFSetDefaultTIFF(TIFFMethod *method)
{
	if (!method) return;

	method->get = _GTIFGetField;
	method->set = _GTIFSetField;
	method->type = _GTIFTagType;
}

gdata_t _GTIFcalloc(gsize_t size)
{
    gdata_t data=(gdata_t)_TIFFmalloc((tsize_t)size);
	if (data) _TIFFmemset((tdata_t)data,0,(tsize_t)size);
	return data;
}

gdata_t _GTIFrealloc(gdata_t ptr, gsize_t size)
{
    return _TIFFrealloc((tdata_t)ptr, (tsize_t) size);
}

void _GTIFmemcpy(gdata_t out,gdata_t in,gsize_t size)
{
	_TIFFmemcpy((tdata_t)out,(tdata_t)in,(tsize_t)size);
}

void _GTIFFree(gdata_t data)
{
	if (data) _TIFFfree((tdata_t)data);
}



/* returns the value of TIFF tag <tag>, or if
 * the value is an array, returns an allocated buffer
 * containing the values. Allocate a copy of the actual
 * buffer, sized up for updating.
 */
static int _GTIFGetField (tiff_t *tif, pinfo_t tag, int *count, void *val )
{
	int status;
	unsigned short scount=0;
	char *tmp;
	const gsize_t size = _gtiff_size[_GTIFTagType (tif,tag)];

	if (_GTIFTagType(tif,  tag) == TYPE_ASCII)
	{
		status = TIFFGetField((TIFF *)tif,tag,&tmp);
		if (!status) return status;
		scount = (unsigned short) (strlen(tmp)+1);
	}
	else status = TIFFGetField((TIFF *)tif,tag,&scount,&tmp);
	if (!status) return status;

	*count = scount;

	char *value = (char *)_GTIFcalloc( (scount+MAX_VALUES)*size);
	if (!value) return 0;

	_TIFFmemcpy( value, tmp,  size * scount);

	*(char **)val = value;
	return status;
}

/*
 * Set a GeoTIFF TIFF field.
 */
static int _GTIFSetField (tiff_t *tif, pinfo_t tag, int count, void *value )
{
	const unsigned short scount = (unsigned short) count;

	int status;
	/* libtiff ASCII uses null-delimiter */
	if (_GTIFTagType(tif,  tag) == TYPE_ASCII)
		status = TIFFSetField((TIFF *)tif,tag,value);
	else
		status = TIFFSetField((TIFF *)tif,tag,scount,value);
	return status;
}


/*
 *  This routine is supposed to return the TagType of the <tag>
 *  TIFF tag. Unfortunately, "libtiff" does not provide this
 *  service by default, so we just have to "know" what type of tags
 *  we've got, and how many. We only define the ones Geotiff
 *  uses here, and others return UNKNOWN. The "tif" parameter
 *  is provided for those TIFF implementations that provide
 *  for tag-type queries.
 */
static tagtype_t  _GTIFTagType  (tiff_t *tif, pinfo_t tag)
{
	(void) tif; /* dummy reference */

	tagtype_t ttype;
	switch (tag)
	{
		case GTIFF_ASCIIPARAMS:    ttype=TYPE_ASCII; break;
		case GTIFF_PIXELSCALE:
		case GTIFF_TRANSMATRIX:
		case GTIFF_TIEPOINTS:
		case GTIFF_DOUBLEPARAMS:   ttype=TYPE_DOUBLE; break;
		case GTIFF_GEOKEYDIRECTORY: ttype=TYPE_SHORT; break;
		default: ttype = TYPE_UNKNOWN;
	}

	return ttype;
}
