/********************************************************************** * * geo_set.c -- Public routines for GEOTIFF GeoKey access. * * Written By: Niles D. Ritter. * * copyright (c) 1995 Niles D. Ritter * * Permission granted to use this software, so long as this copyright * notice accompanies any products derived therefrom. * * $Log: geo_set.c,v $ * Revision 1.11 2004/04/27 21:32:33 warmerda * reformat for clarity * * Revision 1.10 2003/07/08 17:31:30 warmerda * cleanup various warnings * * Revision 1.9 2003/01/15 03:37:19 warmerda * avoid warning * * Revision 1.8 2002/09/27 13:05:33 warmerda * allow dynamic set/delete of ASCII tags. ASCIIPARAMS now kept split * * Revision 1.7 2001/05/02 16:48:22 warmerda * fixed a couple bugs in delete code * * Revision 1.6 2001/05/02 13:54:34 warmerda * updated geo_set.c to support deleting tags * * Revision 1.5 1999/05/04 03:09:33 warmerda * avoid warnings * * Revision 1.4 1999/05/03 17:50:31 warmerda * avoid warnings on IRIX * * Revision 1.3 1999/04/28 19:59:38 warmerda * added some doxygen style documentation * * Revision 1.2 1999/03/11 17:39:38 geotiff * Added fix for case where a key is being overwritten. * **********************************************************************/ #include "geotiff.h" /* public interface */ #include "geo_tiffp.h" /* external TIFF interface */ #include "geo_keyp.h" /* private interface */ #include /** This function writes a geokey_t value to a GeoTIFF file. @param gtif The geotiff information handle from GTIFNew(). @param keyID The geokey_t name (such as ProjectedCSTypeGeoKey). This must come from the list of legal geokey_t values (an enumeration) listed below. @param val The val argument is a pointer to the variable into which the value should be read. The type of the variable varies depending on the geokey_t given. While there is no ready mapping of geokey_t values onto types, in general code values are of type short, citations are strings, and everything else is of type double. Note that pointer's to int should never be passed to GTIFKeyGet() for integer values as they will be shorts, and the int's may not be properly initialized (and will be grossly wrong on MSB systems). @param index Indicates how far into the list of values for this geokey to offset. Should normally be zero. @param count Indicates how many values to read. At this time all keys except for strings have only one value, so index should be zero, and count should be one.

The key indicates the key name to be written to the file and should from the geokey_t enumeration (eg. ProjectedCSTypeGeoKey). The full list of possible geokey_t values can be found in geokeys.inc, or in the online documentation for GTIFKeyGet().

The type should be one of TYPE_SHORT, TYPE_ASCII, or TYPE_DOUBLE and will indicate the type of value being passed at the end of the argument list (the key value). The count should be one except for strings when it should be the length of the string (or zero to for this to be computed internally). As a special case a count of -1 can be used to request an existing key be deleted, in which no value is passed.

The actual value is passed at the end of the argument list, and should be a short, a double, or a char * value. Note that short and double values are passed as is, not as pointers.

Note that key values aren't actually flushed to the file until GTIFWriteKeys() is called. Till then the new values are just kept with the GTIF structure.

Example:

    GTIFKeySet(gtif, GTRasterTypeGeoKey, TYPE_SHORT, 1, 
               RasterPixelIsArea);
    GTIFKeySet(gtif, GTCitationGeoKey, TYPE_ASCII, 0, 
               "UTM 11 North / NAD27" );
*/ int GTIFKeySet(GTIF *gtif, geokey_t keyID, tagtype_t type, int count,...) { va_list ap; int index = gtif->gt_keyindex[ keyID ]; int newvalues = 0; GeoKey *key; char *data = NULL; char *val = NULL; pinfo_t sval; double dval; va_start(ap, count); /* pass singleton keys by value */ if (count>1 && type!=TYPE_ASCII) { val = va_arg(ap, char*); } else if( count == -1 ) { /* delete the indicated tag */ va_end(ap); if( index < 1 ) return 0; if (gtif->gt_keys[index].gk_type == TYPE_ASCII) { _GTIFFree (gtif->gt_keys[index].gk_data); } while( index < gtif->gt_num_keys ) { _GTIFmemcpy( gtif->gt_keys + index, gtif->gt_keys + index + 1, sizeof(GeoKey) ); gtif->gt_keyindex[gtif->gt_keys[index].gk_key] = index; index++; } gtif->gt_num_keys--; gtif->gt_nshorts -= sizeof(KeyEntry)/sizeof(pinfo_t); gtif->gt_keyindex[keyID] = 0; gtif->gt_flags |= FLAG_FILE_MODIFIED; return 1; } else switch (type) { case TYPE_SHORT: sval=(pinfo_t) va_arg(ap, int); val=(char *)&sval; break; case TYPE_DOUBLE: dval=va_arg(ap, dblparam_t); val=(char *)&dval; break; case TYPE_ASCII: val=va_arg(ap, char*); count = strlen(val) + 1; /* force = string length */ break; default: assert( FALSE ); break; } va_end(ap); /* We assume here that there are no multi-valued SHORTS ! */ if (index) { /* Key already exists */ key = gtif->gt_keys+index; if (type!=key->gk_type || count > key->gk_count) { /* need to reset data pointer */ key->gk_type = type; key->gk_count = count; key->gk_size = _gtiff_size[ type ]; newvalues = 1; } } else { /* We need to create the key */ if (gtif->gt_num_keys == MAX_KEYS) return 0; key = gtif->gt_keys + ++gtif->gt_num_keys; index = gtif->gt_num_keys; gtif->gt_keyindex[ keyID ] = index; key->gk_key = keyID; key->gk_type = type; key->gk_count = count; key->gk_size = _gtiff_size[ type ]; if (gtif->gt_keymin > keyID) gtif->gt_keymin=keyID; if (gtif->gt_keymax < keyID) gtif->gt_keymax=keyID; newvalues = 1; } if (newvalues) { switch (type) { case TYPE_SHORT: if (count > 1) return 0; data = (char *)&key->gk_data; /* store value *in* data */ break; case TYPE_DOUBLE: key->gk_data = (char *)(gtif->gt_double + gtif->gt_ndoubles); data = key->gk_data; gtif->gt_ndoubles += count; break; case TYPE_ASCII: break; default: va_end(ap); return 0; } gtif->gt_nshorts += sizeof(KeyEntry)/sizeof(pinfo_t); } /* this fixes a bug where if a request is made to write a duplicate key, we must initialize the data to a valid value. Bryan Wells (bryan@athena.bangor.autometric.com) */ else /* no new values, but still have something to write */ { switch (type) { case TYPE_SHORT: if (count > 1) return 0; data = (char *)&key->gk_data; /* store value *in* data */ break; case TYPE_DOUBLE: data = key->gk_data; break; case TYPE_ASCII: break; default: return 0; } } switch (type) { case TYPE_ASCII: /* throw away existing data and allocate room for new data */ if (key->gk_data != 0) { _GTIFFree(key->gk_data); } key->gk_data = (char *)_GTIFcalloc(count); key->gk_count = count; data = key->gk_data; break; default: break; } _GTIFmemcpy(data, val, count*key->gk_size); gtif->gt_flags |= FLAG_FILE_MODIFIED; return 1; }