/*
 * xtif_dir.c
 *
 * Extended TIFF Directory Tag Support.
 *
 *  You may use this file as a template to add your own
 *  extended tags to the library. Only the parts of the code
 *  marked with "XXX" require modification. Three example tags
 *  are shown; you should replace them with your own.
 *
 *  Author: Niles D. Ritter
 */
 
#include <config.h>
#include <stdio.h>

#include "xtiffiop.h"

/*  Tiff info structure.
 *
 *     Entry format:
 *        { TAGNUMBER, ReadCount, WriteCount, DataType, FIELDNUM, 
 *          OkToChange, PassDirCountOnSet, AsciiName }
 *
 *     For ReadCount, WriteCount, -1 = unknown; used for mult-valued
 *         tags and ASCII.
 */


static const TIFFFieldInfo xtiffFieldInfo[] = {
  { TIFFTAG_COPYRIGHT,    -1, -1, TIFF_ASCII,     FIELD_33432, TRUE, FALSE, "copyright" },

  { TIFFTAG_KDC_33423,    -1, -1, TIFF_ASCII,     FIELD_33423, TRUE, FALSE, "kdc_33423" },
  { TIFFTAG_KDC_33424,     1, -1, TIFF_LONG,      FIELD_33424, TRUE, FALSE, "kdc_33424" },
  { TIFFTAG_KDC_33434,     1, -1, TIFF_RATIONAL,  FIELD_33434, TRUE, FALSE, "kdc_33434" },
  { TIFFTAG_KDC_33437,     1, -1, TIFF_RATIONAL,  FIELD_33437, TRUE, FALSE, "kdc_33437" },
  { TIFFTAG_KDC_34850,     1, -1, TIFF_SHORT,     FIELD_34850, TRUE, FALSE, "kdc_34850" },
  { TIFFTAG_KDC_34859,     1, -1, TIFF_SHORT,     FIELD_34859, TRUE, FALSE, "kdc_34859" },
  { TIFFTAG_KDC_DATETIME, -1, -1, TIFF_ASCII,     FIELD_36867, TRUE, FALSE, "kdc_datetime" },
  { TIFFTAG_KDC_37382,    -1, -1, TIFF_RATIONAL,  FIELD_37382, TRUE, FALSE, "kdc_37382" },
  { TIFFTAG_KDC_37385,     1, -1, TIFF_SHORT,     FIELD_37385, TRUE, FALSE, "kdc_37385" },
  { TIFFTAG_KDC_37386,     1, -1, TIFF_RATIONAL,  FIELD_37386, TRUE, FALSE, "kdc_37386" },
  { TIFFTAG_KDC_37393,     1, -1, TIFF_SHORT,     FIELD_37393, TRUE, FALSE, "kdc_37393" },
  { TIFFTAG_KDC_37398,     4, -1, TIFF_BYTE,      FIELD_37398, TRUE, FALSE, "kdc_37398" },
  { TIFFTAG_KDC_37399,     1, -1, TIFF_SHORT,     FIELD_37399, TRUE, FALSE, "kdc_37399" },
  { TIFFTAG_KDC_33421,     2, -1, TIFF_SHORT,     FIELD_33421, TRUE, FALSE, "kdc_33421" },
  { TIFFTAG_KDC_33422,     4, -1, TIFF_BYTE,      FIELD_33422, TRUE, FALSE, "kdc_33422" },
  { TIFFTAG_KDC_37122,    -1, -1, TIFF_RATIONAL,  FIELD_37122, TRUE, FALSE, "kdc_37122" },
  { TIFFTAG_KDC_37400,    12, -1, TIFF_SRATIONAL, FIELD_37400, TRUE, FALSE, "kdc_37400" }
};
#define	N(a)	(sizeof (a) / sizeof (a[0]))


static void
_XTIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) {

  xtiff *xt = XTIFFDIR(tif);
  XTIFFDirectory *xd = &xt->xtif_dir;

  /* call the inherited method */
  if (PARENT(xt,printdir))
    (PARENT(xt,printdir))(tif,fd,flags);
  
  /* XXX Add field printing here. Replace the three example
   *    tags implemented below with your own.
   */

  if (TIFFFieldSet(tif,FIELD_33432)) {
    _TIFFprintAsciiTag(fd,"Copyright",xd->xd_copyright);
  }

  fprintf(fd,"--KDC Specific Tags--\n");

  if (TIFFFieldSet(tif,FIELD_33423)) {
    _TIFFprintAsciiTag(fd,"Battery Status",xd->xd_kdc_33423);
  }
  if (TIFFFieldSet(tif,FIELD_36867)) {
    _TIFFprintAsciiTag(fd,"Date & Time",xd->xd_kdc_36867);
  }

  if (TIFFFieldSet(tif,FIELD_33424)) {
    fprintf(fd,"  33424: %ld\n", xd->xd_kdc_33424);
  }
  if (TIFFFieldSet(tif,FIELD_33434)) {
    fprintf(fd,"  33434: %ld/%ld\n", xd->xd_kdc_33434[0],xd->xd_kdc_33434[1]);
  }
  if (TIFFFieldSet(tif,FIELD_33437)) {
    fprintf(fd,"  33437: %ld/%ld\n", xd->xd_kdc_33437[0],xd->xd_kdc_33437[1]);
  }
  if (TIFFFieldSet(tif,FIELD_34850)) {
    fprintf(fd,"  34850: %d\n", xd->xd_kdc_34850);
  }
  if (TIFFFieldSet(tif,FIELD_34859)) {
    fprintf(fd,"  34859: %d\n", xd->xd_kdc_34859);
  }
  if (TIFFFieldSet(tif,FIELD_37382)) {
    //    fprintf(fd,"  37382: %ld/%ld\n", xd->xd_kdc_37382[0],xd->xd_kdc_37382[1]);
  }
  if (TIFFFieldSet(tif,FIELD_37385)) {
    fprintf(fd,"  37385: %d\n", xd->xd_kdc_37385);
  }
  if (TIFFFieldSet(tif,FIELD_37386)) {
    //    fprintf(fd,"  37386: %ld/%ld\n", xd->xd_kdc_37386[0],xd->xd_kdc_37386[1]);
  }
  if (TIFFFieldSet(tif,FIELD_37393)) {
    fprintf(fd,"  37393: %d\n", xd->xd_kdc_37393);
  }
  if (TIFFFieldSet(tif,FIELD_37398)) {
    unsigned char* u = (unsigned char*)xd->xd_kdc_37398;
    fprintf(fd,"  37398: %d %d %d %d\n", u[0],u[1],u[2],u[3]);
  }
  if (TIFFFieldSet(tif,FIELD_37399)) {
    fprintf(fd,"  37399: %d\n", xd->xd_kdc_37399);
  }
  if (TIFFFieldSet(tif,FIELD_33421)) {
    fprintf(fd,"  33421: %d %d\n", xd->xd_kdc_33421[0],xd->xd_kdc_33421[1]);
  }
  if (TIFFFieldSet(tif,FIELD_33422)) {
    unsigned char* u = (unsigned char*)xd->xd_kdc_33422;
    fprintf(fd,"  33422: %d %d %d %d\n", u[0],u[1],u[2],u[3]);
  }
  if (TIFFFieldSet(tif,FIELD_37122)) {
    //    fprintf(fd,"  37122: %d\n", xd->xd_kdc_37122);
  }
  if (TIFFFieldSet(tif,FIELD_37400)) {
    fprintf(fd,"  37400: %ld/%ld\n", xd->xd_kdc_37400[0],xd->xd_kdc_37400[1]);
  }

}

static int
_XTIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) {

  xtiff *xt = XTIFFDIR(tif);
  XTIFFDirectory* xd = &xt->xtif_dir;
  int status = 1;
  /*uint32 v32=0;
    int v=0;*/
  /*va_list ap1 = ap;*/
  
  //fprintf(stderr,"_XTIFFVSetField() entered %d\n",tag);

  /* va_start is called by the calling routine */
  
  switch (tag) {
    /* 
     * XXX put your extended tags here; replace the implemented
     *     example tags with your own. 
     */
  case TIFFTAG_KDC_33423:  /*(0x828f) ASCII (2) 6<Full\0\0>*/
    _TIFFsetString(&xd->xd_kdc_33423, va_arg(ap, char*));
    break;
  case TIFFTAG_KDC_33424:  /*(0x8290) LONG (4) 1<1002>*/
    xd->xd_kdc_33424 = va_arg(ap, uint32);
    break;
  case TIFFTAG_KDC_33434:  /*(0x829a) RATIONAL (5) 1<0.01069>*/
//    _TIFFsetLongArray(&xd->xd_kdc_33434, va_arg(ap, uint32*),2);    
    break;
  case TIFFTAG_KDC_33437:  /*(0x829d) RATIONAL (5) 1<2.5>*/
//    _TIFFsetLongArray(&xd->xd_kdc_33437, va_arg(ap, uint32*),2);
    break;
  case TIFFTAG_KDC_34850:  /*(0x8822) SHORT (3) 1<2>*/
    xd->xd_kdc_34850 = va_arg(ap, uint16);
    break;
  case TIFFTAG_KDC_34859:  /*(0x882b) SHORT (3) 1<0>*/
    xd->xd_kdc_34859 = va_arg(ap, uint16);
    break;
  case TIFFTAG_KDC_DATETIME:  /*(0x9003) ASCII (2) 20<1994:03:25 00:00:25\0>*/
    _TIFFsetString(&xd->xd_kdc_36867, va_arg(ap, char*));
    break;
  case TIFFTAG_KDC_37382:  /*(0x9206) RATIONAL (5) 1<0.7>*/
//      _TIFFsetLongArray(&xd->xd_kdc_37382, va_arg(ap, uint32*),2);
    break;
  case TIFFTAG_KDC_37385:  /*(0x9209) SHORT (3) 1<31>*/
    xd->xd_kdc_37385 = va_arg(ap, uint16);
    break;
  case TIFFTAG_KDC_37386:  /*(0x920a) RATIONAL (5) 1<100>*/
//    _TIFFsetLongArray(&xd->xd_kdc_37386, va_arg(ap, uint32*),2);
    break;
  case TIFFTAG_KDC_37393:  /*(0x9211) SHORT (3) 1<1>*/
    xd->xd_kdc_37393 = va_arg(ap, uint16);
    break;
  case TIFFTAG_KDC_37398:  /*(0x9216) BYTE (1) 4<00 00 00 0x1>*/
    _TIFFsetByteArray(&xd->xd_kdc_37398, va_arg(ap, void*),4);
    break;
  case TIFFTAG_KDC_37399:  /*(0x9217) SHORT (3) 1<2>*/
    xd->xd_kdc_37399 = va_arg(ap, uint16);
    break;
  case TIFFTAG_KDC_33421:  /*(0x828d) SHORT (3) 2<2 2>*/
    _TIFFsetShortArray(&xd->xd_kdc_33421, va_arg(ap, uint16*),2);
    break;
  case TIFFTAG_KDC_33422:  /*(0x828e) BYTE (1) 4<0x1 0x2 00 0x1>*/
    _TIFFsetByteArray(&xd->xd_kdc_33422, va_arg(ap, void*),4);
    break;
  case TIFFTAG_KDC_37122:  /*(0x9102) RATIONAL (5) 1<0.75>*/
//    _TIFFsetLongArray(&xd->xd_kdc_37122, va_arg(ap, uint32*),2);
    break;
  case TIFFTAG_KDC_37400:  /*(0x9218) SRATIONAL (10) 12<0 -2.02926 1.04202*/
//    _TIFFsetLongArray(&xd->xd_kdc_37400, va_arg(ap, uint32*),24);
    break;
  case TIFFTAG_COPYRIGHT:
    _TIFFsetString(&xd->xd_copyright, va_arg(ap, char*));
    break;

  default:
    /* call the inherited method */
    return (PARENT(xt,vsetfield))(tif,tag,ap);
    break;
  }
  if (status) {
    /* we have to override the print method here,
     * after the compression tags have gotten to it.
     * This makes sense because the only time we would
     * need the extended print method is if an extended
     * tag is set by the reader.
     */
    if (!(xt->xtif_flags & XTIFFP_PRINT)) {
      PARENT(xt,printdir) =  TIFFMEMBER(tif,printdir);
      TIFFMEMBER(tif,printdir) = _XTIFFPrintDirectory;
      xt->xtif_flags |= XTIFFP_PRINT;
    }
    TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit);
    tif->tif_flags |= TIFF_DIRTYDIRECT;
  }
  va_end(ap);
  return (status);

  /*
 badvalue:
  TIFFError(tif->tif_name, "%d: Bad value for \"%s\"", v,
	    _TIFFFieldWithTag(tif, tag)->field_name);
  va_end(ap);
  return (0);
 badvalue32:
  TIFFError(tif->tif_name, "%ld: Bad value for \"%s\"", v32,
	    _TIFFFieldWithTag(tif, tag)->field_name);
  va_end(ap);
  return (0);
  */
}


static int
_XTIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) {

  xtiff *xt = XTIFFDIR(tif);
  XTIFFDirectory* xd = &xt->xtif_dir;

  switch (tag) {
    /* 
     * XXX put your extended tags here; replace the implemented
     *     example tags with your own.
     */
  case TIFFTAG_KDC_33423:  /*(0x828f) ASCII (2) 6<Full\0\0>*/
    *va_arg(ap, char**) = xd->xd_kdc_33423;
    break;
  case TIFFTAG_KDC_33424:  /*(0x8290) LONG (4) 1<1002>*/
    *va_arg(ap, uint32*) = xd->xd_kdc_33424;
    break;
  case TIFFTAG_KDC_33434:  /*(0x829a) RATIONAL (5) 1<0.01069>*/
    *va_arg(ap, uint32**) = xd->xd_kdc_33434;
    break;
  case TIFFTAG_KDC_33437:  /*(0x829d) RATIONAL (5) 1<2.5>*/
    *va_arg(ap, uint32**) = xd->xd_kdc_33437;
    break;
  case TIFFTAG_KDC_34850:  /*(0x8822) SHORT (3) 1<2>*/
    *va_arg(ap, uint16*) = xd->xd_kdc_34850;
    break;
  case TIFFTAG_KDC_34859:  /*(0x882b) SHORT (3) 1<0>*/
    *va_arg(ap, uint16*) = xd->xd_kdc_34859;
    break;
  case TIFFTAG_KDC_DATETIME:  /*(0x9003) ASCII (2) 20<1994:03:25 00:00:25\0>*/
    *va_arg(ap, char**) = xd->xd_kdc_36867;
    break;
  case TIFFTAG_KDC_37382:  /*(0x9206) RATIONAL (5) 1<0.7>*/
    *va_arg(ap, uint32**) = xd->xd_kdc_37382;
    break;
  case TIFFTAG_KDC_37385:  /*(0x9209) SHORT (3) 1<31>*/
    *va_arg(ap, uint16*) = xd->xd_kdc_37385;
    break;
  case TIFFTAG_KDC_37386:  /*(0x920a) RATIONAL (5) 1<100>*/
    *va_arg(ap, uint32**) = xd->xd_kdc_37386;
    break;
  case TIFFTAG_KDC_37393:  /*(0x9211) SHORT (3) 1<1>*/
    *va_arg(ap, uint16*) = xd->xd_kdc_37393;
    break;
  case TIFFTAG_KDC_37398:  /*(0x9216) BYTE (1) 4<00 00 00 0x1>*/
    *va_arg(ap, void**) = xd->xd_kdc_37398;
    break;
  case TIFFTAG_KDC_37399:  /*(0x9217) SHORT (3) 1<2>*/
    *va_arg(ap, uint16*) = xd->xd_kdc_37399;
    break;
  case TIFFTAG_KDC_33421:  /*(0x828d) SHORT (3) 2<2 2>*/
    *va_arg(ap, uint16**) = xd->xd_kdc_33421; 
    break;
  case TIFFTAG_KDC_33422:  /*(0x828e) BYTE (1) 4<0x1 0x2 00 0x1>*/
    *va_arg(ap, void**) = xd->xd_kdc_33422;
    break;
  case TIFFTAG_KDC_37122:  /*(0x9102) RATIONAL (5) 1<0.75>*/
    *va_arg(ap, uint32**) = xd->xd_kdc_37122; 
    break;
  case TIFFTAG_KDC_37400:  /*(0x9218) SRATIONAL (10) 12<0 -2.02926 1.04202*/
    *va_arg(ap, uint32**) = xd->xd_kdc_37400; 
    break;
  case TIFFTAG_COPYRIGHT:
    *va_arg(ap, char**) = xd->xd_copyright;
    break;

  default:
    /* return inherited method */
    return (PARENT(xt,vgetfield))(tif,tag,ap);
    break;
  }
  return (1);
}

#define	CleanupField(member) {		\
    if (xd->member) {			\
	_TIFFfree(xd->member);		\
	xd->member = 0;			\
    }					\
}
/*
 * Release storage associated with a directory.
 */
static void
_XTIFFFreeDirectory(xtiff* xt) {

  XTIFFDirectory* xd = &xt->xtif_dir;
  
  /* 
   *  XXX - Purge all Your allocated memory except
   *  for the xtiff directory itself. This includes
   *  all fields that require a _TIFFsetXXX call in
   *  _XTIFFVSetField().
   */
  
  CleanupField(xd_kdc_33423);
  CleanupField(xd_kdc_33434);  /* RATIONAL */
  CleanupField(xd_kdc_33437);  /* RATIONAL */
  CleanupField(xd_kdc_36867);
  CleanupField(xd_kdc_37382);  /* RATIONAL */
  CleanupField(xd_kdc_37386);  /* RATIONAL */
  CleanupField(xd_kdc_37398);
  CleanupField(xd_kdc_33421);
  CleanupField(xd_kdc_33422);
  CleanupField(xd_kdc_37122);  /* RATIONAL */
  CleanupField(xd_kdc_37400);  /* 24 x SRATIONAL */
  CleanupField(xd_copyright);
  
}
#undef CleanupField

static void _XTIFFLocalDefaultDirectory(TIFF *tif) {

  xtiff *xt = XTIFFDIR(tif);
  /*XTIFFDirectory* xd = &xt->xtif_dir;*/
  
  /* Install the extended Tag field info */
  _TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
  
  /*
   *  free up any dynamically allocated arrays
   *  before the new directory is read in.
   */
  
  _XTIFFFreeDirectory(xt);	
  _TIFFmemset(xt,0,sizeof(xtiff));
  
  /* Override the tag access methods */
  
  PARENT(xt,vsetfield) =  TIFFMEMBER(tif,vsetfield);
  TIFFMEMBER(tif,vsetfield) = _XTIFFVSetField;
  PARENT(xt,vgetfield) =  TIFFMEMBER(tif,vgetfield);
  TIFFMEMBER(tif,vgetfield) = _XTIFFVGetField;
  
  /* 
   * XXX Set up any default values here.
   */
  
}



/**********************************************************************
 *    Nothing below this line should need to be changed.
 **********************************************************************/

static TIFFExtendProc _ParentExtender;

/*
 *  This is the callback procedure, and is
 *  called by the DefaultDirectory method
 *  every time a new TIFF directory is opened.
 */

static void
_XTIFFDefaultDirectory(TIFF *tif)
{

	xtiff *xt;

	/* Allocate Directory Structure if first time, and install it */
	if (!(tif->tif_flags & XTIFF_INITIALIZED))
	{
		xt = _TIFFmalloc(sizeof(xtiff));
		if (!xt)
		{
			/* handle memory allocation failure here ! */
			return;
		}
		_TIFFmemset(xt,0,sizeof(xtiff));
		/*
		 * Install into TIFF structure.
		 */
		TIFFMEMBER(tif,clientdir) = (tidata_t)xt;
		tif->tif_flags |= XTIFF_INITIALIZED; /* dont do this again! */
	}
	
	/* set up our own defaults */
	_XTIFFLocalDefaultDirectory(tif);

	/* Since an XTIFF client module may have overridden
	 * the default directory method, we call it now to
	 * allow it to set up the rest of its own methods.
         */

	if (_ParentExtender) 
		(*_ParentExtender)(tif);

}

/*
 *  XTIFF Initializer -- sets up the callback
 *   procedure for the TIFF module.
 */

static
void _XTIFFInitialize(void)
{

	static int first_time=1;

	if (! first_time) return; /* Been there. Done that. */
	first_time = 0;
	
	/* Grab the inherited method and install */
	_ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
}


/*
 * Public File I/O Routines.
 */
TIFF*
XTIFFOpen(const char* name, const char* mode)
{

	/* Set up the callback */
	_XTIFFInitialize();	
	
	/* Open the file; the callback will set everything up
	 */
	return TIFFOpen(name, mode);
}

TIFF*
XTIFFFdOpen(int fd, const char* name, const char* mode)
{
	/* Set up the callback */
	_XTIFFInitialize();	

	/* Open the file; the callback will set everything up
	 */
	return TIFFFdOpen(fd, name, mode);
}


void
XTIFFClose(TIFF *tif)
{

	xtiff *xt = XTIFFDIR(tif);

	/* call inherited function first */
	TIFFClose(tif);
	
	/* Free up extended allocated memory */
	_XTIFFFreeDirectory(xt);
	_TIFFfree(xt);
}
