1 : /******************************************************************************
2 : * $Id: dted_api.c 22606 2011-06-28 20:31:23Z rouault $
3 : *
4 : * Project: DTED Translator
5 : * Purpose: Implementation of DTED/CDED access functions.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "dted_api.h"
31 :
32 : #ifndef AVOID_CPL
33 : CPL_CVSID("$Id: dted_api.c 22606 2011-06-28 20:31:23Z rouault $");
34 : #endif
35 :
36 : static int bWarnedTwoComplement = FALSE;
37 :
38 :
39 : /************************************************************************/
40 : /* DTEDGetField() */
41 : /* */
42 : /* Extract a field as a zero terminated string. Address is */
43 : /* deliberately 1 based so the getfield arguments will be the */
44 : /* same as the numbers in the file format specification. */
45 : /************************************************************************/
46 :
47 : static
48 1640 : char *DTEDGetField( char szResult[81], const char *pachRecord, int nStart, int nSize )
49 :
50 : {
51 1640 : CPLAssert( nSize < 81 );
52 1640 : memcpy( szResult, pachRecord + nStart - 1, nSize );
53 1640 : szResult[nSize] = '\0';
54 :
55 1640 : return szResult;
56 : }
57 :
58 : /************************************************************************/
59 : /* StripLeadingZeros() */
60 : /* */
61 : /* Return a pointer to the first non-zero character in BUF. */
62 : /* BUF must be null terminated. */
63 : /* If buff is all zeros, then it will point to the last non-zero */
64 : /************************************************************************/
65 :
66 984 : static const char* stripLeadingZeros(const char* buf)
67 : {
68 984 : const char* ptr = buf;
69 :
70 : /* Go until we run out of characters or hit something non-zero */
71 :
72 2994 : while( *ptr == '0' && *(ptr+1) != '\0' )
73 : {
74 1026 : ptr++;
75 : }
76 :
77 984 : return ptr;
78 : }
79 :
80 : /************************************************************************/
81 : /* DTEDOpen() */
82 : /************************************************************************/
83 :
84 164 : DTEDInfo * DTEDOpen( const char * pszFilename,
85 : const char * pszAccess,
86 : int bTestOpen )
87 :
88 : {
89 : VSILFILE *fp;
90 : char achRecord[DTED_UHL_SIZE];
91 164 : DTEDInfo *psDInfo = NULL;
92 : double dfLLOriginX, dfLLOriginY;
93 164 : int deg = 0;
94 164 : int min = 0;
95 164 : int sec = 0;
96 164 : int bSwapLatLong = FALSE;
97 : char szResult[81];
98 : int bIsWeirdDTED;
99 : char chHemisphere;
100 : /* -------------------------------------------------------------------- */
101 : /* Open the physical file. */
102 : /* -------------------------------------------------------------------- */
103 300 : if( EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb") )
104 136 : pszAccess = "rb";
105 : else
106 28 : pszAccess = "r+b";
107 :
108 164 : fp = VSIFOpenL( pszFilename, pszAccess );
109 :
110 164 : if( fp == NULL )
111 : {
112 0 : if( !bTestOpen )
113 : {
114 : #ifndef AVOID_CPL
115 0 : CPLError( CE_Failure, CPLE_OpenFailed,
116 : #else
117 : fprintf( stderr,
118 : #endif
119 : "Failed to open file %s.",
120 : pszFilename );
121 : }
122 :
123 0 : return NULL;
124 : }
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* Read, trying to find the UHL record. Skip VOL or HDR */
128 : /* records if they are encountered. */
129 : /* -------------------------------------------------------------------- */
130 : do
131 : {
132 166 : if( VSIFReadL( achRecord, 1, DTED_UHL_SIZE, fp ) != DTED_UHL_SIZE )
133 : {
134 0 : if( !bTestOpen )
135 : {
136 : #ifndef AVOID_CPL
137 0 : CPLError( CE_Failure, CPLE_OpenFailed,
138 : #else
139 : fprintf( stderr,
140 : #endif
141 : "Unable to read header, %s is not DTED.",
142 : pszFilename );
143 : }
144 0 : VSIFCloseL( fp );
145 0 : return NULL;
146 : }
147 :
148 166 : } while( EQUALN(achRecord,"VOL",3) || EQUALN(achRecord,"HDR",3) );
149 :
150 164 : if( !EQUALN(achRecord,"UHL",3) )
151 : {
152 0 : if( !bTestOpen )
153 : {
154 : #ifndef AVOID_CPL
155 0 : CPLError( CE_Failure, CPLE_OpenFailed,
156 : #else
157 : fprintf( stderr,
158 : #endif
159 : "No UHL record. %s is not a DTED file.",
160 : pszFilename );
161 : }
162 0 : VSIFCloseL( fp );
163 0 : return NULL;
164 : }
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Create and initialize the DTEDInfo structure. */
168 : /* -------------------------------------------------------------------- */
169 164 : psDInfo = (DTEDInfo *) CPLCalloc(1,sizeof(DTEDInfo));
170 :
171 164 : psDInfo->fp = fp;
172 :
173 164 : psDInfo->bUpdate = EQUAL(pszAccess,"r+b");
174 :
175 164 : psDInfo->nUHLOffset = (int)VSIFTellL( fp ) - DTED_UHL_SIZE;
176 164 : psDInfo->pachUHLRecord = (char *) CPLMalloc(DTED_UHL_SIZE);
177 164 : memcpy( psDInfo->pachUHLRecord, achRecord, DTED_UHL_SIZE );
178 :
179 164 : psDInfo->nDSIOffset = (int)VSIFTellL( fp );
180 164 : psDInfo->pachDSIRecord = (char *) CPLMalloc(DTED_DSI_SIZE);
181 164 : VSIFReadL( psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, fp );
182 :
183 164 : psDInfo->nACCOffset = (int)VSIFTellL( fp );
184 164 : psDInfo->pachACCRecord = (char *) CPLMalloc(DTED_ACC_SIZE);
185 164 : VSIFReadL( psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, fp );
186 :
187 328 : if( !EQUALN(psDInfo->pachDSIRecord,"DSI",3)
188 164 : || !EQUALN(psDInfo->pachACCRecord,"ACC",3) )
189 : {
190 : #ifndef AVOID_CPL
191 0 : CPLError( CE_Failure, CPLE_OpenFailed,
192 : #else
193 : fprintf( stderr,
194 : #endif
195 : "DSI or ACC record missing. DTED access to\n%s failed.",
196 : pszFilename );
197 :
198 0 : VSIFCloseL( fp );
199 0 : return NULL;
200 : }
201 :
202 164 : psDInfo->nDataOffset = (int)VSIFTellL( fp );
203 :
204 : /* DTED3 file from http://www.falconview.org/trac/FalconView/downloads/20 */
205 : /* (co_elevation.zip) has really weird offsets that don't comply with the 89020B specification */
206 164 : bIsWeirdDTED = achRecord[4] == ' ';
207 :
208 : /* -------------------------------------------------------------------- */
209 : /* Parse out position information. Note that we are extracting */
210 : /* the top left corner of the top left pixel area, not the */
211 : /* center of the area. */
212 : /* -------------------------------------------------------------------- */
213 164 : if (!bIsWeirdDTED)
214 : {
215 164 : psDInfo->dfPixelSizeX =
216 164 : atoi(DTEDGetField(szResult,achRecord,21,4)) / 36000.0;
217 :
218 164 : psDInfo->dfPixelSizeY =
219 164 : atoi(DTEDGetField(szResult,achRecord,25,4)) / 36000.0;
220 :
221 164 : psDInfo->nXSize = atoi(DTEDGetField(szResult,achRecord,48,4));
222 164 : psDInfo->nYSize = atoi(DTEDGetField(szResult,achRecord,52,4));
223 : }
224 : else
225 : {
226 0 : psDInfo->dfPixelSizeX =
227 0 : atoi(DTEDGetField(szResult,achRecord,41,4)) / 36000.0;
228 :
229 0 : psDInfo->dfPixelSizeY =
230 0 : atoi(DTEDGetField(szResult,achRecord,45,4)) / 36000.0;
231 :
232 0 : psDInfo->nXSize = atoi(DTEDGetField(szResult,psDInfo->pachDSIRecord,563,4));
233 0 : psDInfo->nYSize = atoi(DTEDGetField(szResult,psDInfo->pachDSIRecord,567,4));
234 : }
235 :
236 : /* create a scope so I don't need to declare these up top */
237 164 : if (!bIsWeirdDTED)
238 : {
239 164 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,5,3)));
240 164 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,8,2)));
241 164 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,10,2)));
242 164 : chHemisphere = achRecord[11];
243 : }
244 : else
245 : {
246 0 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,9,3)));
247 0 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,12,2)));
248 0 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,14,2)));
249 0 : chHemisphere = achRecord[15];
250 : }
251 :
252 : /* NOTE : The first version of MIL-D-89020 was buggy.
253 : The latitude and longitude of the LL cornder of the UHF record was inverted.
254 : This was fixed in MIL-D-89020 Amendement 1, but some products may be affected.
255 : We detect this situation by looking at N/S in the longitude field and
256 : E/W in the latitude one
257 : */
258 :
259 164 : dfLLOriginX = deg + min / 60.0 + sec / 3600.0;
260 164 : if( chHemisphere == 'W' )
261 118 : dfLLOriginX *= -1;
262 46 : else if ( chHemisphere == 'N' )
263 2 : bSwapLatLong = TRUE;
264 44 : else if ( chHemisphere == 'S' )
265 : {
266 0 : dfLLOriginX *= -1;
267 0 : bSwapLatLong = TRUE;
268 : }
269 :
270 164 : if (!bIsWeirdDTED)
271 : {
272 164 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,13,3)));
273 164 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,16,2)));
274 164 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,18,2)));
275 164 : chHemisphere = achRecord[19];
276 : }
277 : else
278 : {
279 0 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,25,3)));
280 0 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,28,2)));
281 0 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,30,2)));
282 0 : chHemisphere = achRecord[31];
283 : }
284 :
285 164 : dfLLOriginY = deg + min / 60.0 + sec / 3600.0;
286 164 : if( chHemisphere == 'S' || (bSwapLatLong && chHemisphere == 'W'))
287 2 : dfLLOriginY *= -1;
288 :
289 164 : if (bSwapLatLong)
290 : {
291 2 : double dfTmp = dfLLOriginX;
292 2 : dfLLOriginX = dfLLOriginY;
293 2 : dfLLOriginY = dfTmp;
294 : }
295 :
296 164 : psDInfo->dfULCornerX = dfLLOriginX - 0.5 * psDInfo->dfPixelSizeX;
297 164 : psDInfo->dfULCornerY = dfLLOriginY - 0.5 * psDInfo->dfPixelSizeY
298 164 : + psDInfo->nYSize * psDInfo->dfPixelSizeY;
299 :
300 164 : return psDInfo;
301 : }
302 :
303 :
304 :
305 : /************************************************************************/
306 : /* DTEDReadPoint() */
307 : /* */
308 : /* Read one single sample. The coordinates are given from the */
309 : /* top-left corner of the file (contrary to the internal */
310 : /* organisation or a DTED file) */
311 : /************************************************************************/
312 :
313 0 : int DTEDReadPoint( DTEDInfo * psDInfo, int nXOff, int nYOff, GInt16* panVal)
314 : {
315 : int nOffset;
316 : GByte pabyData[2];
317 :
318 0 : if (nYOff < 0 || nXOff < 0 || nYOff >= psDInfo->nYSize || nXOff >= psDInfo->nXSize)
319 : {
320 : #ifndef AVOID_CPL
321 0 : CPLError( CE_Failure, CPLE_AppDefined,
322 : #else
323 : fprintf( stderr,
324 : #endif
325 : "Invalid raster coordinates (%d,%d) in DTED file.\n", nXOff, nYOff);
326 0 : return FALSE;
327 : }
328 :
329 0 : nOffset = psDInfo->nDataOffset + nXOff * (12+psDInfo->nYSize*2) + 8 + 2 * (psDInfo->nYSize-1-nYOff);
330 0 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
331 0 : || VSIFReadL( pabyData, 2, 1, psDInfo->fp ) != 1)
332 : {
333 : #ifndef AVOID_CPL
334 0 : CPLError( CE_Failure, CPLE_FileIO,
335 : #else
336 : fprintf( stderr,
337 : #endif
338 : "Failed to seek to, or read (%d,%d) at offset %d\n"
339 : "in DTED file.\n",
340 : nXOff, nYOff, nOffset );
341 0 : return FALSE;
342 : }
343 :
344 0 : *panVal = ((pabyData[0] & 0x7f) << 8) | pabyData[1];
345 :
346 0 : if( pabyData[0] & 0x80 )
347 : {
348 0 : *panVal *= -1;
349 :
350 : /*
351 : ** It seems that some files are improperly generated in twos
352 : ** complement form for negatives. For these, redo the job
353 : ** in twos complement. eg. w_069_s50.dt0
354 : */
355 0 : if(( *panVal < -16000 ) && (*panVal != DTED_NODATA_VALUE))
356 : {
357 0 : *panVal = (pabyData[0] << 8) | pabyData[1];
358 :
359 0 : if( !bWarnedTwoComplement )
360 : {
361 0 : bWarnedTwoComplement = TRUE;
362 : #ifndef AVOID_CPL
363 0 : CPLError( CE_Warning, CPLE_AppDefined,
364 : #else
365 : fprintf( stderr,
366 : #endif
367 : "The DTED driver found values less than -16000, and has adjusted\n"
368 : "them assuming they are improperly two-complemented. No more warnings\n"
369 : "will be issued in this session about this operation." );
370 : }
371 : }
372 : }
373 :
374 0 : return TRUE;
375 : }
376 :
377 : /************************************************************************/
378 : /* DTEDReadProfile() */
379 : /* */
380 : /* Read one profile line. These are organized in bottom to top */
381 : /* order starting from the leftmost column (0). */
382 : /************************************************************************/
383 :
384 0 : int DTEDReadProfile( DTEDInfo * psDInfo, int nColumnOffset,
385 : GInt16 * panData )
386 : {
387 0 : return DTEDReadProfileEx( psDInfo, nColumnOffset, panData, FALSE);
388 : }
389 :
390 9262 : int DTEDReadProfileEx( DTEDInfo * psDInfo, int nColumnOffset,
391 : GInt16 * panData, int bVerifyChecksum )
392 : {
393 : int nOffset;
394 : int i;
395 : GByte *pabyRecord;
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Read data record from disk. */
399 : /* -------------------------------------------------------------------- */
400 9262 : pabyRecord = (GByte *) CPLMalloc(12 + psDInfo->nYSize*2);
401 :
402 9262 : nOffset = psDInfo->nDataOffset + nColumnOffset * (12+psDInfo->nYSize*2);
403 :
404 18524 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
405 18524 : || VSIFReadL( pabyRecord, (12+psDInfo->nYSize*2), 1, psDInfo->fp ) != 1)
406 : {
407 : #ifndef AVOID_CPL
408 0 : CPLError( CE_Failure, CPLE_FileIO,
409 : #else
410 : fprintf( stderr,
411 : #endif
412 : "Failed to seek to, or read profile %d at offset %d\n"
413 : "in DTED file.\n",
414 : nColumnOffset, nOffset );
415 0 : CPLFree( pabyRecord );
416 0 : return FALSE;
417 : }
418 :
419 : /* -------------------------------------------------------------------- */
420 : /* Translate data values from "signed magnitude" to standard */
421 : /* binary. */
422 : /* -------------------------------------------------------------------- */
423 2428124 : for( i = 0; i < psDInfo->nYSize; i++ )
424 : {
425 2418862 : panData[i] = ((pabyRecord[8+i*2] & 0x7f) << 8) | pabyRecord[8+i*2+1];
426 :
427 2418862 : if( pabyRecord[8+i*2] & 0x80 )
428 : {
429 0 : panData[i] *= -1;
430 :
431 : /*
432 : ** It seems that some files are improperly generated in twos
433 : ** complement form for negatives. For these, redo the job
434 : ** in twos complement. eg. w_069_s50.dt0
435 : */
436 0 : if(( panData[i] < -16000 ) && (panData[i] != DTED_NODATA_VALUE))
437 : {
438 0 : panData[i] = (pabyRecord[8+i*2] << 8) | pabyRecord[8+i*2+1];
439 :
440 0 : if( !bWarnedTwoComplement )
441 : {
442 0 : bWarnedTwoComplement = TRUE;
443 : #ifndef AVOID_CPL
444 0 : CPLError( CE_Warning, CPLE_AppDefined,
445 : #else
446 : fprintf( stderr,
447 : #endif
448 : "The DTED driver found values less than -16000, and has adjusted\n"
449 : "them assuming they are improperly two-complemented. No more warnings\n"
450 : "will be issued in this session about this operation." );
451 : }
452 : }
453 : }
454 : }
455 :
456 9262 : if (bVerifyChecksum)
457 : {
458 2 : unsigned int nCheckSum = 0;
459 : unsigned int fileCheckSum;
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Verify the checksum. */
463 : /* -------------------------------------------------------------------- */
464 :
465 502 : for( i = 0; i < psDInfo->nYSize*2 + 8; i++ )
466 500 : nCheckSum += pabyRecord[i];
467 :
468 4 : fileCheckSum = (pabyRecord[8+psDInfo->nYSize*2+0] << 24) |
469 2 : (pabyRecord[8+psDInfo->nYSize*2+1] << 16) |
470 2 : (pabyRecord[8+psDInfo->nYSize*2+2] << 8) |
471 2 : pabyRecord[8+psDInfo->nYSize*2+3];
472 :
473 2 : if ((GIntBig)fileCheckSum > (GIntBig)(0xff * (8+psDInfo->nYSize*2)))
474 : {
475 : static int bWarned = FALSE;
476 0 : if (! bWarned)
477 : {
478 0 : bWarned = TRUE;
479 : #ifndef AVOID_CPL
480 0 : CPLError( CE_Warning, CPLE_AppDefined,
481 : #else
482 : fprintf( stderr,
483 : #endif
484 : "The DTED driver has read from the file a checksum "
485 : "with an impossible value (0x%X) at column %d.\n"
486 : "Check with your file producer.\n"
487 : "No more warnings will be issued in this session about this operation.",
488 : fileCheckSum, nColumnOffset);
489 : }
490 : }
491 2 : else if (fileCheckSum != nCheckSum)
492 : {
493 : #ifndef AVOID_CPL
494 2 : CPLError( CE_Warning, CPLE_AppDefined,
495 : #else
496 : fprintf( stderr,
497 : #endif
498 : "The DTED driver has found a computed and read checksum "
499 : "that do not match at column %d.\n",
500 : nColumnOffset);
501 2 : CPLFree( pabyRecord );
502 2 : return FALSE;
503 : }
504 : }
505 :
506 9260 : CPLFree( pabyRecord );
507 :
508 9260 : return TRUE;
509 : }
510 :
511 : /************************************************************************/
512 : /* DTEDWriteProfile() */
513 : /************************************************************************/
514 :
515 28108 : int DTEDWriteProfile( DTEDInfo * psDInfo, int nColumnOffset,
516 : GInt16 * panData )
517 :
518 : {
519 : int nOffset;
520 28108 : int i, nCheckSum = 0;
521 : GByte *pabyRecord;
522 :
523 : /* -------------------------------------------------------------------- */
524 : /* Format the data record. */
525 : /* -------------------------------------------------------------------- */
526 28108 : pabyRecord = (GByte *) CPLMalloc(12 + psDInfo->nYSize*2);
527 :
528 33263096 : for( i = 0; i < psDInfo->nYSize; i++ )
529 : {
530 33234988 : int nABSVal = ABS(panData[psDInfo->nYSize-i-1]);
531 33234988 : pabyRecord[8+i*2] = (GByte) ((nABSVal >> 8) & 0x7f);
532 33234988 : pabyRecord[8+i*2+1] = (GByte) (nABSVal & 0xff);
533 :
534 33234988 : if( panData[psDInfo->nYSize-i-1] < 0 )
535 4217475 : pabyRecord[8+i*2] |= 0x80;
536 : }
537 :
538 28108 : pabyRecord[0] = 0xaa;
539 28108 : pabyRecord[1] = 0;
540 28108 : pabyRecord[2] = (GByte) (nColumnOffset / 256);
541 28108 : pabyRecord[3] = (GByte) (nColumnOffset % 256);
542 28108 : pabyRecord[4] = (GByte) (nColumnOffset / 256);
543 28108 : pabyRecord[5] = (GByte) (nColumnOffset % 256);
544 28108 : pabyRecord[6] = 0;
545 28108 : pabyRecord[7] = 0;
546 :
547 : /* -------------------------------------------------------------------- */
548 : /* Compute the checksum. */
549 : /* -------------------------------------------------------------------- */
550 66722948 : for( i = 0; i < psDInfo->nYSize*2 + 8; i++ )
551 66694840 : nCheckSum += pabyRecord[i];
552 :
553 28108 : pabyRecord[8+psDInfo->nYSize*2+0] = (GByte) ((nCheckSum >> 24) & 0xff);
554 28108 : pabyRecord[8+psDInfo->nYSize*2+1] = (GByte) ((nCheckSum >> 16) & 0xff);
555 28108 : pabyRecord[8+psDInfo->nYSize*2+2] = (GByte) ((nCheckSum >> 8) & 0xff);
556 28108 : pabyRecord[8+psDInfo->nYSize*2+3] = (GByte) (nCheckSum & 0xff);
557 :
558 : /* -------------------------------------------------------------------- */
559 : /* Write the record. */
560 : /* -------------------------------------------------------------------- */
561 28108 : nOffset = psDInfo->nDataOffset + nColumnOffset * (12+psDInfo->nYSize*2);
562 :
563 56216 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
564 56216 : || VSIFWriteL( pabyRecord,(12+psDInfo->nYSize*2),1,psDInfo->fp ) != 1)
565 : {
566 : #ifndef AVOID_CPL
567 0 : CPLError( CE_Failure, CPLE_FileIO,
568 : #else
569 : fprintf( stderr,
570 : #endif
571 : "Failed to seek to, or write profile %d at offset %d\n"
572 : "in DTED file.\n",
573 : nColumnOffset, nOffset );
574 0 : CPLFree( pabyRecord );
575 0 : return FALSE;
576 : }
577 :
578 28108 : CPLFree( pabyRecord );
579 :
580 28108 : return TRUE;
581 :
582 : }
583 :
584 : /************************************************************************/
585 : /* DTEDGetMetadataLocation() */
586 : /************************************************************************/
587 :
588 3068 : static void DTEDGetMetadataLocation( DTEDInfo *psDInfo,
589 : DTEDMetaDataCode eCode,
590 : char **ppszLocation, int *pnLength )
591 : {
592 3068 : int bIsWeirdDTED = psDInfo->pachUHLRecord[4] == ' ';
593 :
594 3068 : switch( eCode )
595 : {
596 : case DTEDMD_ORIGINLONG:
597 136 : if (bIsWeirdDTED)
598 0 : *ppszLocation = psDInfo->pachUHLRecord + 8;
599 : else
600 136 : *ppszLocation = psDInfo->pachUHLRecord + 4;
601 136 : *pnLength = 8;
602 136 : break;
603 :
604 : case DTEDMD_ORIGINLAT:
605 136 : if (bIsWeirdDTED)
606 0 : *ppszLocation = psDInfo->pachUHLRecord + 24;
607 : else
608 136 : *ppszLocation = psDInfo->pachUHLRecord + 12;
609 136 : *pnLength = 8;
610 136 : break;
611 :
612 : case DTEDMD_VERTACCURACY_UHL:
613 140 : if (bIsWeirdDTED)
614 0 : *ppszLocation = psDInfo->pachUHLRecord + 56;
615 : else
616 140 : *ppszLocation = psDInfo->pachUHLRecord + 28;
617 140 : *pnLength = 4;
618 140 : break;
619 :
620 : case DTEDMD_SECURITYCODE_UHL:
621 140 : if (bIsWeirdDTED)
622 0 : *ppszLocation = psDInfo->pachUHLRecord + 60;
623 : else
624 140 : *ppszLocation = psDInfo->pachUHLRecord + 32;
625 140 : *pnLength = 3;
626 140 : break;
627 :
628 : case DTEDMD_UNIQUEREF_UHL:
629 140 : if (bIsWeirdDTED)
630 0 : *ppszLocation = NULL;
631 : else
632 140 : *ppszLocation = psDInfo->pachUHLRecord + 35;
633 140 : *pnLength = 12;
634 140 : break;
635 :
636 : case DTEDMD_DATA_EDITION:
637 140 : if (bIsWeirdDTED)
638 0 : *ppszLocation = psDInfo->pachDSIRecord + 174;
639 : else
640 140 : *ppszLocation = psDInfo->pachDSIRecord + 87;
641 140 : *pnLength = 2;
642 140 : break;
643 :
644 : case DTEDMD_MATCHMERGE_VERSION:
645 140 : if (bIsWeirdDTED)
646 0 : *ppszLocation = psDInfo->pachDSIRecord + 176;
647 : else
648 140 : *ppszLocation = psDInfo->pachDSIRecord + 89;
649 140 : *pnLength = 1;
650 140 : break;
651 :
652 : case DTEDMD_MAINT_DATE:
653 140 : if (bIsWeirdDTED)
654 0 : *ppszLocation = psDInfo->pachDSIRecord + 177;
655 : else
656 140 : *ppszLocation = psDInfo->pachDSIRecord + 90;
657 140 : *pnLength = 4;
658 140 : break;
659 :
660 : case DTEDMD_MATCHMERGE_DATE:
661 140 : if (bIsWeirdDTED)
662 0 : *ppszLocation = psDInfo->pachDSIRecord + 181;
663 : else
664 140 : *ppszLocation = psDInfo->pachDSIRecord + 94;
665 140 : *pnLength = 4;
666 140 : break;
667 :
668 : case DTEDMD_MAINT_DESCRIPTION:
669 140 : if (bIsWeirdDTED)
670 0 : *ppszLocation = psDInfo->pachDSIRecord + 185;
671 : else
672 140 : *ppszLocation = psDInfo->pachDSIRecord + 98;
673 140 : *pnLength = 4;
674 140 : break;
675 :
676 : case DTEDMD_PRODUCER:
677 140 : if (bIsWeirdDTED)
678 0 : *ppszLocation = psDInfo->pachDSIRecord + 189;
679 : else
680 140 : *ppszLocation = psDInfo->pachDSIRecord + 102;
681 140 : *pnLength = 8;
682 140 : break;
683 :
684 : case DTEDMD_VERTDATUM:
685 140 : if (bIsWeirdDTED)
686 0 : *ppszLocation = psDInfo->pachDSIRecord + 267;
687 : else
688 140 : *ppszLocation = psDInfo->pachDSIRecord + 141;
689 140 : *pnLength = 3;
690 140 : break;
691 :
692 : case DTEDMD_HORIZDATUM:
693 140 : if (bIsWeirdDTED)
694 0 : *ppszLocation = psDInfo->pachDSIRecord + 270;
695 : else
696 140 : *ppszLocation = psDInfo->pachDSIRecord + 144;
697 140 : *pnLength = 5;
698 140 : break;
699 :
700 : case DTEDMD_DIGITIZING_SYS:
701 140 : if (bIsWeirdDTED)
702 0 : *ppszLocation = NULL;
703 : else
704 140 : *ppszLocation = psDInfo->pachDSIRecord + 149;
705 140 : *pnLength = 10;
706 140 : break;
707 :
708 : case DTEDMD_COMPILATION_DATE:
709 140 : if (bIsWeirdDTED)
710 0 : *ppszLocation = NULL;
711 : else
712 140 : *ppszLocation = psDInfo->pachDSIRecord + 159;
713 140 : *pnLength = 4;
714 140 : break;
715 :
716 : case DTEDMD_HORIZACCURACY:
717 140 : *ppszLocation = psDInfo->pachACCRecord + 3;
718 140 : *pnLength = 4;
719 140 : break;
720 :
721 : case DTEDMD_REL_HORIZACCURACY:
722 140 : *ppszLocation = psDInfo->pachACCRecord + 11;
723 140 : *pnLength = 4;
724 140 : break;
725 :
726 : case DTEDMD_REL_VERTACCURACY:
727 140 : *ppszLocation = psDInfo->pachACCRecord + 15;
728 140 : *pnLength = 4;
729 140 : break;
730 :
731 : case DTEDMD_VERTACCURACY_ACC:
732 140 : *ppszLocation = psDInfo->pachACCRecord + 7;
733 140 : *pnLength = 4;
734 140 : break;
735 :
736 : case DTEDMD_SECURITYCODE_DSI:
737 140 : *ppszLocation = psDInfo->pachDSIRecord + 3;
738 140 : *pnLength = 1;
739 140 : break;
740 :
741 : case DTEDMD_UNIQUEREF_DSI:
742 140 : if (bIsWeirdDTED)
743 0 : *ppszLocation = NULL;
744 : else
745 140 : *ppszLocation = psDInfo->pachDSIRecord + 64;
746 140 : *pnLength = 15;
747 140 : break;
748 :
749 : case DTEDMD_NIMA_DESIGNATOR:
750 136 : if (bIsWeirdDTED)
751 0 : *ppszLocation = psDInfo->pachDSIRecord + 118;
752 : else
753 136 : *ppszLocation = psDInfo->pachDSIRecord + 59;
754 136 : *pnLength = 5;
755 136 : break;
756 :
757 : default:
758 0 : *ppszLocation = NULL;
759 0 : *pnLength = 0;
760 : }
761 3068 : }
762 :
763 : /************************************************************************/
764 : /* DTEDGetMetadata() */
765 : /************************************************************************/
766 :
767 2992 : char *DTEDGetMetadata( DTEDInfo *psDInfo, DTEDMetaDataCode eCode )
768 :
769 : {
770 : int nFieldLen;
771 : char *pszFieldSrc;
772 : char *pszResult;
773 :
774 2992 : DTEDGetMetadataLocation( psDInfo, eCode, &pszFieldSrc, &nFieldLen );
775 2992 : if( pszFieldSrc == NULL )
776 0 : return strdup( "" );
777 :
778 2992 : pszResult = (char *) malloc(nFieldLen+1);
779 2992 : strncpy( pszResult, pszFieldSrc, nFieldLen );
780 2992 : pszResult[nFieldLen] = '\0';
781 :
782 2992 : return pszResult;
783 : }
784 :
785 : /************************************************************************/
786 : /* DTEDSetMetadata() */
787 : /************************************************************************/
788 :
789 76 : int DTEDSetMetadata( DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
790 : const char *pszNewValue )
791 :
792 : {
793 : int nFieldLen;
794 : char *pszFieldSrc;
795 :
796 76 : if( !psDInfo->bUpdate )
797 0 : return FALSE;
798 :
799 : /* -------------------------------------------------------------------- */
800 : /* Get the location in the headers to update. */
801 : /* -------------------------------------------------------------------- */
802 76 : DTEDGetMetadataLocation( psDInfo, eCode, &pszFieldSrc, &nFieldLen );
803 76 : if( pszFieldSrc == NULL )
804 0 : return FALSE;
805 :
806 : /* -------------------------------------------------------------------- */
807 : /* Update it, padding with spaces. */
808 : /* -------------------------------------------------------------------- */
809 76 : memset( pszFieldSrc, ' ', nFieldLen );
810 76 : strncpy( pszFieldSrc, pszNewValue,
811 76 : MIN((size_t)nFieldLen,strlen(pszNewValue)) );
812 :
813 : /* -------------------------------------------------------------------- */
814 : /* Write all headers back to disk. */
815 : /* -------------------------------------------------------------------- */
816 76 : VSIFSeekL( psDInfo->fp, psDInfo->nUHLOffset, SEEK_SET );
817 76 : VSIFWriteL( psDInfo->pachUHLRecord, 1, DTED_UHL_SIZE, psDInfo->fp );
818 :
819 76 : VSIFSeekL( psDInfo->fp, psDInfo->nDSIOffset, SEEK_SET );
820 76 : VSIFWriteL( psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, psDInfo->fp );
821 :
822 76 : VSIFSeekL( psDInfo->fp, psDInfo->nACCOffset, SEEK_SET );
823 76 : VSIFWriteL( psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, psDInfo->fp );
824 :
825 76 : return TRUE;
826 : }
827 :
828 : /************************************************************************/
829 : /* DTEDClose() */
830 : /************************************************************************/
831 :
832 164 : void DTEDClose( DTEDInfo * psDInfo )
833 :
834 : {
835 164 : VSIFCloseL( psDInfo->fp );
836 :
837 164 : CPLFree( psDInfo->pachUHLRecord );
838 164 : CPLFree( psDInfo->pachDSIRecord );
839 164 : CPLFree( psDInfo->pachACCRecord );
840 :
841 164 : CPLFree( psDInfo );
842 164 : }
|