1 : /**********************************************************************
2 : *
3 : * geo_new.c -- Public routines for GEOTIFF GeoKey access.
4 : *
5 : * Written By: Niles D. Ritter.
6 : *
7 : * copyright (c) 1995 Niles D. Ritter
8 : *
9 : * Permission granted to use this software, so long as this copyright
10 : * notice accompanies any products derived therefrom.
11 : *
12 : * 20 June, 1995 Niles D. Ritter New
13 : * 7 July, 1995 Greg Martin Fix index
14 : *
15 : **********************************************************************/
16 :
17 : #include "geotiffio.h" /* public interface */
18 : #include "geo_tiffp.h" /* external TIFF interface */
19 : #include "geo_keyp.h" /* private interface */
20 : #include "geo_simpletags.h"
21 :
22 : /* private local routines */
23 : static int ReadKey(GTIF* gt, TempKeyData* tempData,
24 : KeyEntry* entptr, GeoKey* keyptr);
25 :
26 :
27 : /**********************************************************************
28 : *
29 : * Public Routines
30 : *
31 : **********************************************************************/
32 :
33 :
34 : /**
35 : * Given an open TIFF file, look for GTIF keys and
36 : * values and return GTIF structure.
37 :
38 : This function creates a GeoTIFF information interpretation handle
39 : (GTIF *) based on a passed in TIFF handle originally from
40 : XTIFFOpen(). Even though the argument
41 : (<b>tif</b>) is shown as type <tt>void *</tt>, it is really normally
42 : of type <tt>TIFF *</tt>.<p>
43 :
44 : The returned GTIF handle can be used to read or write GeoTIFF tags
45 : using the various GTIF functions. The handle should be destroyed using
46 : GTIFFree() before the file is closed with TIFFClose().<p>
47 :
48 : If the file accessed has no GeoTIFF keys, an valid (but empty) GTIF is
49 : still returned. GTIFNew() is used both for existing files being read, and
50 : for new TIFF files that will have GeoTIFF tags written to them.<p>
51 :
52 : */
53 :
54 11442 : GTIF* GTIFNew(void *tif)
55 :
56 : {
57 : TIFFMethod default_methods;
58 11442 : _GTIFSetDefaultTIFF( &default_methods );
59 :
60 11442 : return GTIFNewWithMethods( tif, &default_methods );
61 : }
62 :
63 0 : GTIF *GTIFNewSimpleTags( void *tif )
64 :
65 : {
66 : TIFFMethod default_methods;
67 0 : GTIFSetSimpleTagsMethods( &default_methods );
68 :
69 0 : return GTIFNewWithMethods( tif, &default_methods );
70 : }
71 :
72 : /************************************************************************/
73 : /* GTIFNewWithMethods() */
74 : /* */
75 : /* Create a new geotiff, passing in the methods structure to */
76 : /* support not libtiff implementations without replacing the */
77 : /* default methods. */
78 : /************************************************************************/
79 :
80 11442 : GTIF* GTIFNewWithMethods(void *tif, TIFFMethod* methods)
81 : {
82 11442 : GTIF* gt=(GTIF*)0;
83 : int count,bufcount,index;
84 : GeoKey *keyptr;
85 : pinfo_t *data;
86 : KeyEntry *entptr;
87 : KeyHeader *header;
88 : TempKeyData tempData;
89 :
90 11442 : memset( &tempData, 0, sizeof(tempData) );
91 11442 : gt = (GTIF*)_GTIFcalloc( sizeof(GTIF));
92 11442 : if (!gt) goto failure;
93 :
94 : /* install TIFF file and I/O methods */
95 11442 : gt->gt_tif = (tiff_t *)tif;
96 11442 : memcpy( >->gt_methods, methods, sizeof(TIFFMethod) );
97 :
98 : /* since this is an array, GTIF will allocate the memory */
99 26736 : if ( tif == NULL
100 11442 : || !(gt->gt_methods.get)(tif, GTIFF_GEOKEYDIRECTORY, >->gt_nshorts, &data ))
101 : {
102 : /* No ProjectionInfo, create a blank one */
103 3852 : data=(pinfo_t*)_GTIFcalloc((4+MAX_VALUES)*sizeof(pinfo_t));
104 3852 : if (!data) goto failure;
105 3852 : header = (KeyHeader *)data;
106 3852 : header->hdr_version = GvCurrentVersion;
107 3852 : header->hdr_rev_major = GvCurrentRevision;
108 3852 : header->hdr_rev_minor = GvCurrentMinorRev;
109 3852 : gt->gt_nshorts=sizeof(KeyHeader)/sizeof(pinfo_t);
110 : }
111 : else
112 : {
113 : /* resize data array so it can be extended if needed */
114 7590 : data = (pinfo_t*) _GTIFrealloc(data,(4+MAX_VALUES)*sizeof(pinfo_t));
115 : }
116 11442 : gt->gt_short = data;
117 11442 : header = (KeyHeader *)data;
118 :
119 11442 : if (header->hdr_version > GvCurrentVersion) goto failure;
120 11442 : if (header->hdr_rev_major > GvCurrentRevision)
121 : {
122 : /* issue warning */
123 : }
124 :
125 : /* If we got here, then the geokey can be parsed */
126 11442 : count = header->hdr_num_keys;
127 :
128 11442 : if (count * sizeof(KeyEntry) >= (4 + MAX_VALUES) * sizeof(pinfo_t))
129 0 : goto failure;
130 :
131 11442 : gt->gt_num_keys = count;
132 11442 : gt->gt_version = header->hdr_version;
133 11442 : gt->gt_rev_major = header->hdr_rev_major;
134 11442 : gt->gt_rev_minor = header->hdr_rev_minor;
135 :
136 11442 : bufcount = count+MAX_KEYS; /* allow for expansion */
137 :
138 : /* Get the PARAMS Tags, if any */
139 30318 : if (tif == NULL
140 22884 : || !(gt->gt_methods.get)(tif, GTIFF_DOUBLEPARAMS,
141 11442 : >->gt_ndoubles, >->gt_double ))
142 : {
143 7434 : gt->gt_double=(double*)_GTIFcalloc(MAX_VALUES*sizeof(double));
144 7434 : if (!gt->gt_double) goto failure;
145 : }
146 : else
147 : {
148 : /* resize data array so it can be extended if needed */
149 4008 : gt->gt_double = (double*) _GTIFrealloc(gt->gt_double,
150 : (MAX_VALUES)*sizeof(double));
151 : }
152 26774 : if ( tif == NULL
153 11442 : || !(gt->gt_methods.get)(tif, GTIFF_ASCIIPARAMS,
154 : &tempData.tk_asciiParamsLength,
155 : &tempData.tk_asciiParams ))
156 : {
157 3890 : tempData.tk_asciiParams = 0;
158 3890 : tempData.tk_asciiParamsLength = 0;
159 : }
160 : else
161 : {
162 : /* last NULL doesn't count; "|" used for delimiter */
163 15104 : if( tempData.tk_asciiParamsLength > 0
164 15104 : && tempData.tk_asciiParams[tempData.tk_asciiParamsLength-1] == '\0')
165 : {
166 7552 : --tempData.tk_asciiParamsLength;
167 : }
168 : }
169 :
170 : /* allocate space for GeoKey array and its index */
171 11442 : gt->gt_keys = (GeoKey *)_GTIFcalloc( sizeof(GeoKey)*bufcount);
172 11442 : if (!gt->gt_keys) goto failure;
173 11442 : gt->gt_keyindex = (int *)_GTIFcalloc( sizeof(int)*(MAX_KEYINDEX+1));
174 11442 : if (!gt->gt_keyindex) goto failure;
175 :
176 : /* Loop to get all GeoKeys */
177 11442 : entptr = ((KeyEntry *)data) + 1;
178 11442 : keyptr = gt->gt_keys;
179 11442 : gt->gt_keymin = MAX_KEYINDEX;
180 11442 : gt->gt_keymax = 0;
181 62966 : for (index=1; index<=count; index++,entptr++)
182 : {
183 51526 : if (!ReadKey(gt, &tempData, entptr, ++keyptr))
184 2 : goto failure;
185 :
186 : /* Set up the index (start at 1, since 0=unset) */
187 51524 : gt->gt_keyindex[entptr->ent_key] = index;
188 : }
189 :
190 11440 : if( tempData.tk_asciiParams != NULL )
191 7552 : _GTIFFree( tempData.tk_asciiParams );
192 :
193 11440 : return gt;
194 :
195 : failure:
196 : /* Notify of error */
197 2 : if( tempData.tk_asciiParams != NULL )
198 0 : _GTIFFree( tempData.tk_asciiParams );
199 2 : GTIFFree (gt);
200 2 : return (GTIF *)0;
201 : }
202 :
203 : /**********************************************************************
204 : *
205 : * Private Routines
206 : *
207 : **********************************************************************/
208 :
209 : /*
210 : * Given KeyEntry, read in the GeoKey value location and set up
211 : * the Key structure, returning 0 if failure.
212 : */
213 :
214 51526 : static int ReadKey(GTIF* gt, TempKeyData* tempData,
215 : KeyEntry* entptr, GeoKey* keyptr)
216 : {
217 : int offset,count;
218 :
219 51526 : keyptr->gk_key = entptr->ent_key;
220 51526 : keyptr->gk_count = entptr->ent_count;
221 51526 : count = entptr->ent_count;
222 51526 : offset = entptr->ent_val_offset;
223 51526 : if (gt->gt_keymin > keyptr->gk_key) gt->gt_keymin=keyptr->gk_key;
224 51526 : if (gt->gt_keymax < keyptr->gk_key) gt->gt_keymax=keyptr->gk_key;
225 :
226 51526 : if (entptr->ent_location)
227 18352 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,entptr->ent_location);
228 : else
229 33174 : keyptr->gk_type = (gt->gt_methods.type)(gt->gt_tif,GTIFF_GEOKEYDIRECTORY);
230 :
231 51526 : switch (entptr->ent_location)
232 : {
233 : case GTIFF_LOCAL:
234 : /* store value into data value */
235 33174 : *(pinfo_t *)(&keyptr->gk_data) = entptr->ent_val_offset;
236 33174 : break;
237 : case GTIFF_GEOKEYDIRECTORY:
238 0 : keyptr->gk_data = (char *)(gt->gt_short+offset);
239 0 : if (gt->gt_nshorts < offset+count)
240 0 : gt->gt_nshorts = offset+count;
241 0 : break;
242 : case GTIFF_DOUBLEPARAMS:
243 8944 : keyptr->gk_data = (char *)(gt->gt_double+offset);
244 8944 : if (gt->gt_ndoubles < offset+count)
245 0 : gt->gt_ndoubles = offset+count;
246 8944 : break;
247 : case GTIFF_ASCIIPARAMS:
248 18824 : if( offset + count == tempData->tk_asciiParamsLength + 1
249 9408 : && count > 0 )
250 : {
251 : /* some vendors seem to feel they should not use the
252 : terminating '|' char, but do include a terminating '\0'
253 : which we lose in the low level reading code.
254 : If this is the case, drop the extra character */
255 8 : count--;
256 : }
257 18798 : else if (offset < tempData->tk_asciiParamsLength
258 18798 : && offset + count > tempData->tk_asciiParamsLength )
259 : {
260 0 : count = tempData->tk_asciiParamsLength - offset;
261 : /* issue warning... if we could */
262 : }
263 9400 : else if (offset + count > tempData->tk_asciiParamsLength)
264 2 : return (0);
265 :
266 9406 : keyptr->gk_count = MAX(1,count+1);
267 9406 : keyptr->gk_data = (char *) _GTIFcalloc (keyptr->gk_count);
268 :
269 18812 : _GTIFmemcpy (keyptr->gk_data,
270 9406 : tempData->tk_asciiParams + offset, count);
271 9406 : if( keyptr->gk_data[MAX(0,count-1)] == '|' )
272 : {
273 9398 : keyptr->gk_data[MAX(0,count-1)] = '\0';
274 9398 : keyptr->gk_count = count;
275 : }
276 : else
277 8 : keyptr->gk_data[MAX(0,count)] = '\0';
278 9406 : break;
279 : default:
280 0 : return 0; /* failure */
281 : }
282 51524 : keyptr->gk_size = _gtiff_size[keyptr->gk_type];
283 :
284 51524 : return 1; /* success */
285 : }
|