1 : /******************************************************************************
2 : * $Id: dted_api.c 17398 2009-07-16 04:16:26Z chaitanya $
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 17398 2009-07-16 04:16:26Z chaitanya $");
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 610 : char *DTEDGetField( char szResult[81], const char *pachRecord, int nStart, int nSize )
49 :
50 : {
51 : CPLAssert( nSize < 81 );
52 610 : memcpy( szResult, pachRecord + nStart - 1, nSize );
53 610 : szResult[nSize] = '\0';
54 :
55 610 : 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 366 : static const char* stripLeadingZeros(const char* buf)
67 : {
68 366 : const char* ptr = buf;
69 :
70 : /* Go until we run out of characters or hit something non-zero */
71 :
72 1119 : while( *ptr == '0' && *(ptr+1) != '\0' )
73 : {
74 387 : ptr++;
75 : }
76 :
77 366 : return ptr;
78 : }
79 :
80 : /************************************************************************/
81 : /* DTEDOpen() */
82 : /************************************************************************/
83 :
84 61 : DTEDInfo * DTEDOpen( const char * pszFilename,
85 : const char * pszAccess,
86 : int bTestOpen )
87 :
88 : {
89 : FILE *fp;
90 : char achRecord[DTED_UHL_SIZE];
91 61 : DTEDInfo *psDInfo = NULL;
92 : double dfLLOriginX, dfLLOriginY;
93 61 : int deg = 0;
94 61 : int min = 0;
95 61 : int sec = 0;
96 61 : int bSwapLatLong = FALSE;
97 : char szResult[81];
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Open the physical file. */
101 : /* -------------------------------------------------------------------- */
102 108 : if( EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb") )
103 47 : pszAccess = "rb";
104 : else
105 14 : pszAccess = "r+b";
106 :
107 61 : fp = VSIFOpenL( pszFilename, pszAccess );
108 :
109 61 : if( fp == NULL )
110 : {
111 0 : if( !bTestOpen )
112 : {
113 : #ifndef AVOID_CPL
114 0 : CPLError( CE_Failure, CPLE_OpenFailed,
115 : #else
116 : fprintf( stderr,
117 : #endif
118 : "Failed to open file %s.",
119 : pszFilename );
120 : }
121 :
122 0 : return NULL;
123 : }
124 :
125 : /* -------------------------------------------------------------------- */
126 : /* Read, trying to find the UHL record. Skip VOL or HDR */
127 : /* records if they are encountered. */
128 : /* -------------------------------------------------------------------- */
129 : do
130 : {
131 62 : if( VSIFReadL( achRecord, 1, DTED_UHL_SIZE, fp ) != DTED_UHL_SIZE )
132 : {
133 0 : if( !bTestOpen )
134 : {
135 : #ifndef AVOID_CPL
136 0 : CPLError( CE_Failure, CPLE_OpenFailed,
137 : #else
138 : fprintf( stderr,
139 : #endif
140 : "Unable to read header, %s is not DTED.",
141 : pszFilename );
142 : }
143 0 : VSIFCloseL( fp );
144 0 : return NULL;
145 : }
146 :
147 62 : } while( EQUALN(achRecord,"VOL",3) || EQUALN(achRecord,"HDR",3) );
148 :
149 61 : if( !EQUALN(achRecord,"UHL",3) )
150 : {
151 0 : if( !bTestOpen )
152 : {
153 : #ifndef AVOID_CPL
154 0 : CPLError( CE_Failure, CPLE_OpenFailed,
155 : #else
156 : fprintf( stderr,
157 : #endif
158 : "No UHL record. %s is not a DTED file.",
159 : pszFilename );
160 : }
161 0 : VSIFCloseL( fp );
162 0 : return NULL;
163 : }
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Create and initialize the DTEDInfo structure. */
167 : /* -------------------------------------------------------------------- */
168 61 : psDInfo = (DTEDInfo *) CPLCalloc(1,sizeof(DTEDInfo));
169 :
170 61 : psDInfo->fp = fp;
171 :
172 61 : psDInfo->bUpdate = EQUAL(pszAccess,"r+b");
173 :
174 61 : psDInfo->nXSize = atoi(DTEDGetField(szResult,achRecord,48,4));
175 61 : psDInfo->nYSize = atoi(DTEDGetField(szResult,achRecord,52,4));
176 :
177 61 : psDInfo->nUHLOffset = (int)VSIFTellL( fp ) - DTED_UHL_SIZE;
178 61 : psDInfo->pachUHLRecord = (char *) CPLMalloc(DTED_UHL_SIZE);
179 61 : memcpy( psDInfo->pachUHLRecord, achRecord, DTED_UHL_SIZE );
180 :
181 61 : psDInfo->nDSIOffset = (int)VSIFTellL( fp );
182 61 : psDInfo->pachDSIRecord = (char *) CPLMalloc(DTED_DSI_SIZE);
183 61 : VSIFReadL( psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, fp );
184 :
185 61 : psDInfo->nACCOffset = (int)VSIFTellL( fp );
186 61 : psDInfo->pachACCRecord = (char *) CPLMalloc(DTED_ACC_SIZE);
187 61 : VSIFReadL( psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, fp );
188 :
189 122 : if( !EQUALN(psDInfo->pachDSIRecord,"DSI",3)
190 61 : || !EQUALN(psDInfo->pachACCRecord,"ACC",3) )
191 : {
192 : #ifndef AVOID_CPL
193 0 : CPLError( CE_Failure, CPLE_OpenFailed,
194 : #else
195 : fprintf( stderr,
196 : #endif
197 : "DSI or ACC record missing. DTED access to\n%s failed.",
198 : pszFilename );
199 :
200 0 : VSIFCloseL( fp );
201 0 : return NULL;
202 : }
203 :
204 61 : psDInfo->nDataOffset = (int)VSIFTellL( fp );
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Parse out position information. Note that we are extracting */
208 : /* the top left corner of the top left pixel area, not the */
209 : /* center of the area. */
210 : /* -------------------------------------------------------------------- */
211 61 : psDInfo->dfPixelSizeX =
212 61 : atoi(DTEDGetField(szResult,achRecord,21,4)) / 36000.0;
213 :
214 61 : psDInfo->dfPixelSizeY =
215 61 : atoi(DTEDGetField(szResult,achRecord,25,4)) / 36000.0;
216 :
217 : /* create a scope so I don't need to declare these up top */
218 61 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,5,3)));
219 61 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,8,2)));
220 61 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,10,2)));
221 :
222 : /* NOTE : The first version of MIL-D-89020 was buggy.
223 : The latitude and longitude of the LL cornder of the UHF record was inverted.
224 : This was fixed in MIL-D-89020 Amendement 1, but some products may be affected.
225 : We detect this situation by looking at N/S in the longitude field and
226 : E/W in the latitude one
227 : */
228 :
229 61 : dfLLOriginX = deg + min / 60.0 + sec / 3600.0;
230 61 : if( achRecord[11] == 'W' )
231 38 : dfLLOriginX *= -1;
232 23 : else if ( achRecord[11] == 'N' )
233 1 : bSwapLatLong = TRUE;
234 22 : else if ( achRecord[11] == 'S' )
235 : {
236 0 : dfLLOriginX *= -1;
237 0 : bSwapLatLong = TRUE;
238 : }
239 :
240 61 : deg = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,13,3)));
241 61 : min = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,16,2)));
242 61 : sec = atoi(stripLeadingZeros(DTEDGetField(szResult,achRecord,18,2)));
243 :
244 61 : dfLLOriginY = deg + min / 60.0 + sec / 3600.0;
245 61 : if( achRecord[19] == 'S' || (bSwapLatLong && achRecord[19] == 'W'))
246 1 : dfLLOriginY *= -1;
247 :
248 61 : if (bSwapLatLong)
249 : {
250 1 : double dfTmp = dfLLOriginX;
251 1 : dfLLOriginX = dfLLOriginY;
252 1 : dfLLOriginY = dfTmp;
253 : }
254 :
255 61 : psDInfo->dfULCornerX = dfLLOriginX - 0.5 * psDInfo->dfPixelSizeX;
256 61 : psDInfo->dfULCornerY = dfLLOriginY - 0.5 * psDInfo->dfPixelSizeY
257 61 : + psDInfo->nYSize * psDInfo->dfPixelSizeY;
258 :
259 61 : return psDInfo;
260 : }
261 :
262 :
263 :
264 : /************************************************************************/
265 : /* DTEDReadPoint() */
266 : /* */
267 : /* Read one single sample. The coordinates are given from the */
268 : /* top-left corner of the file (contrary to the internal */
269 : /* organisation or a DTED file) */
270 : /************************************************************************/
271 :
272 0 : int DTEDReadPoint( DTEDInfo * psDInfo, int nXOff, int nYOff, GInt16* panVal)
273 : {
274 : int nOffset;
275 : GByte pabyData[2];
276 :
277 0 : if (nYOff < 0 || nXOff < 0 || nYOff >= psDInfo->nYSize || nXOff >= psDInfo->nXSize)
278 : {
279 : #ifndef AVOID_CPL
280 0 : CPLError( CE_Failure, CPLE_AppDefined,
281 : #else
282 : fprintf( stderr,
283 : #endif
284 : "Invalid raster coordinates (%d,%d) in DTED file.\n", nXOff, nYOff);
285 0 : return FALSE;
286 : }
287 :
288 0 : nOffset = psDInfo->nDataOffset + nXOff * (12+psDInfo->nYSize*2) + 8 + 2 * (psDInfo->nYSize-1-nYOff);
289 0 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
290 0 : || VSIFReadL( pabyData, 2, 1, psDInfo->fp ) != 1)
291 : {
292 : #ifndef AVOID_CPL
293 0 : CPLError( CE_Failure, CPLE_FileIO,
294 : #else
295 : fprintf( stderr,
296 : #endif
297 : "Failed to seek to, or read (%d,%d) at offset %d\n"
298 : "in DTED file.\n",
299 : nXOff, nYOff, nOffset );
300 0 : return FALSE;
301 : }
302 :
303 0 : *panVal = ((pabyData[0] & 0x7f) << 8) | pabyData[1];
304 :
305 0 : if( pabyData[0] & 0x80 )
306 : {
307 0 : *panVal *= -1;
308 :
309 : /*
310 : ** It seems that some files are improperly generated in twos
311 : ** complement form for negatives. For these, redo the job
312 : ** in twos complement. eg. w_069_s50.dt0
313 : */
314 0 : if(( *panVal < -16000 ) && (*panVal != DTED_NODATA_VALUE))
315 : {
316 0 : *panVal = (pabyData[0] << 8) | pabyData[1];
317 :
318 0 : if( !bWarnedTwoComplement )
319 : {
320 0 : bWarnedTwoComplement = TRUE;
321 : #ifndef AVOID_CPL
322 0 : CPLError( CE_Warning, CPLE_AppDefined,
323 : #else
324 : fprintf( stderr,
325 : #endif
326 : "The DTED driver found values less than -16000, and has adjusted\n"
327 : "them assuming they are improperly two-complemented. No more warnings\n"
328 : "will be issued in this session about this operation." );
329 : }
330 : }
331 : }
332 :
333 0 : return TRUE;
334 : }
335 :
336 : /************************************************************************/
337 : /* DTEDReadProfile() */
338 : /* */
339 : /* Read one profile line. These are organized in bottom to top */
340 : /* order starting from the leftmost column (0). */
341 : /************************************************************************/
342 :
343 0 : int DTEDReadProfile( DTEDInfo * psDInfo, int nColumnOffset,
344 : GInt16 * panData )
345 : {
346 0 : return DTEDReadProfileEx( psDInfo, nColumnOffset, panData, FALSE);
347 : }
348 :
349 3300 : int DTEDReadProfileEx( DTEDInfo * psDInfo, int nColumnOffset,
350 : GInt16 * panData, int bVerifyChecksum )
351 : {
352 : int nOffset;
353 : int i;
354 : GByte *pabyRecord;
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* Read data record from disk. */
358 : /* -------------------------------------------------------------------- */
359 3300 : pabyRecord = (GByte *) CPLMalloc(12 + psDInfo->nYSize*2);
360 :
361 3300 : nOffset = psDInfo->nDataOffset + nColumnOffset * (12+psDInfo->nYSize*2);
362 :
363 6600 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
364 6600 : || VSIFReadL( pabyRecord, (12+psDInfo->nYSize*2), 1, psDInfo->fp ) != 1)
365 : {
366 : #ifndef AVOID_CPL
367 0 : CPLError( CE_Failure, CPLE_FileIO,
368 : #else
369 : fprintf( stderr,
370 : #endif
371 : "Failed to seek to, or read profile %d at offset %d\n"
372 : "in DTED file.\n",
373 : nColumnOffset, nOffset );
374 0 : CPLFree( pabyRecord );
375 0 : return FALSE;
376 : }
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Translate data values from "signed magnitude" to standard */
380 : /* binary. */
381 : /* -------------------------------------------------------------------- */
382 1051680 : for( i = 0; i < psDInfo->nYSize; i++ )
383 : {
384 1048380 : panData[i] = ((pabyRecord[8+i*2] & 0x7f) << 8) | pabyRecord[8+i*2+1];
385 :
386 1048380 : if( pabyRecord[8+i*2] & 0x80 )
387 : {
388 0 : panData[i] *= -1;
389 :
390 : /*
391 : ** It seems that some files are improperly generated in twos
392 : ** complement form for negatives. For these, redo the job
393 : ** in twos complement. eg. w_069_s50.dt0
394 : */
395 0 : if(( panData[i] < -16000 ) && (panData[i] != DTED_NODATA_VALUE))
396 : {
397 0 : panData[i] = (pabyRecord[8+i*2] << 8) | pabyRecord[8+i*2+1];
398 :
399 0 : if( !bWarnedTwoComplement )
400 : {
401 0 : bWarnedTwoComplement = TRUE;
402 : #ifndef AVOID_CPL
403 0 : CPLError( CE_Warning, CPLE_AppDefined,
404 : #else
405 : fprintf( stderr,
406 : #endif
407 : "The DTED driver found values less than -16000, and has adjusted\n"
408 : "them assuming they are improperly two-complemented. No more warnings\n"
409 : "will be issued in this session about this operation." );
410 : }
411 : }
412 : }
413 : }
414 :
415 3300 : if (bVerifyChecksum)
416 : {
417 1 : unsigned int nCheckSum = 0;
418 : unsigned int fileCheckSum;
419 :
420 : /* -------------------------------------------------------------------- */
421 : /* Verify the checksum. */
422 : /* -------------------------------------------------------------------- */
423 :
424 251 : for( i = 0; i < psDInfo->nYSize*2 + 8; i++ )
425 250 : nCheckSum += pabyRecord[i];
426 :
427 2 : fileCheckSum = (pabyRecord[8+psDInfo->nYSize*2+0] << 24) |
428 1 : (pabyRecord[8+psDInfo->nYSize*2+1] << 16) |
429 1 : (pabyRecord[8+psDInfo->nYSize*2+2] << 8) |
430 1 : pabyRecord[8+psDInfo->nYSize*2+3];
431 :
432 1 : if ((GIntBig)fileCheckSum > (GIntBig)(0xff * (8+psDInfo->nYSize*2)))
433 : {
434 : static int bWarned = FALSE;
435 0 : if (! bWarned)
436 : {
437 0 : bWarned = TRUE;
438 : #ifndef AVOID_CPL
439 0 : CPLError( CE_Warning, CPLE_AppDefined,
440 : #else
441 : fprintf( stderr,
442 : #endif
443 : "The DTED driver has read from the file a checksum "
444 : "with an impossible value (0x%X) at column %d.\n"
445 : "Check with your file producer.\n"
446 : "No more warnings will be issued in this session about this operation.",
447 : fileCheckSum, nColumnOffset);
448 : }
449 : }
450 1 : else if (fileCheckSum != nCheckSum)
451 : {
452 : #ifndef AVOID_CPL
453 1 : CPLError( CE_Warning, CPLE_AppDefined,
454 : #else
455 : fprintf( stderr,
456 : #endif
457 : "The DTED driver has found a computed and read checksum "
458 : "that do not match at column %d.\n",
459 : nColumnOffset);
460 1 : CPLFree( pabyRecord );
461 1 : return FALSE;
462 : }
463 : }
464 :
465 3299 : CPLFree( pabyRecord );
466 :
467 3299 : return TRUE;
468 : }
469 :
470 : /************************************************************************/
471 : /* DTEDWriteProfile() */
472 : /************************************************************************/
473 :
474 14054 : int DTEDWriteProfile( DTEDInfo * psDInfo, int nColumnOffset,
475 : GInt16 * panData )
476 :
477 : {
478 : int nOffset;
479 14054 : int i, nCheckSum = 0;
480 : GByte *pabyRecord;
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* Format the data record. */
484 : /* -------------------------------------------------------------------- */
485 14054 : pabyRecord = (GByte *) CPLMalloc(12 + psDInfo->nYSize*2);
486 :
487 16631548 : for( i = 0; i < psDInfo->nYSize; i++ )
488 : {
489 16617494 : int nABSVal = ABS(panData[psDInfo->nYSize-i-1]);
490 16617494 : pabyRecord[8+i*2] = (GByte) ((nABSVal >> 8) & 0x7f);
491 16617494 : pabyRecord[8+i*2+1] = (GByte) (nABSVal & 0xff);
492 :
493 16617494 : if( panData[psDInfo->nYSize-i-1] < 0 )
494 0 : pabyRecord[8+i*2] |= 0x80;
495 : }
496 :
497 14054 : pabyRecord[0] = 0xaa;
498 14054 : pabyRecord[1] = 0;
499 14054 : pabyRecord[2] = (GByte) (nColumnOffset / 256);
500 14054 : pabyRecord[3] = (GByte) (nColumnOffset % 256);
501 14054 : pabyRecord[4] = (GByte) (nColumnOffset / 256);
502 14054 : pabyRecord[5] = (GByte) (nColumnOffset % 256);
503 14054 : pabyRecord[6] = 0;
504 14054 : pabyRecord[7] = 0;
505 :
506 : /* -------------------------------------------------------------------- */
507 : /* Compute the checksum. */
508 : /* -------------------------------------------------------------------- */
509 33361474 : for( i = 0; i < psDInfo->nYSize*2 + 8; i++ )
510 33347420 : nCheckSum += pabyRecord[i];
511 :
512 14054 : pabyRecord[8+psDInfo->nYSize*2+0] = (GByte) ((nCheckSum >> 24) & 0xff);
513 14054 : pabyRecord[8+psDInfo->nYSize*2+1] = (GByte) ((nCheckSum >> 16) & 0xff);
514 14054 : pabyRecord[8+psDInfo->nYSize*2+2] = (GByte) ((nCheckSum >> 8) & 0xff);
515 14054 : pabyRecord[8+psDInfo->nYSize*2+3] = (GByte) (nCheckSum & 0xff);
516 :
517 : /* -------------------------------------------------------------------- */
518 : /* Write the record. */
519 : /* -------------------------------------------------------------------- */
520 14054 : nOffset = psDInfo->nDataOffset + nColumnOffset * (12+psDInfo->nYSize*2);
521 :
522 28108 : if( VSIFSeekL( psDInfo->fp, nOffset, SEEK_SET ) != 0
523 28108 : || VSIFWriteL( pabyRecord,(12+psDInfo->nYSize*2),1,psDInfo->fp ) != 1)
524 : {
525 0 : CPLFree( pabyRecord );
526 : #ifndef AVOID_CPL
527 0 : CPLError( CE_Failure, CPLE_FileIO,
528 : #else
529 : fprintf( stderr,
530 : #endif
531 : "Failed to seek to, or write profile %d at offset %d\n"
532 : "in DTED file.\n",
533 : nColumnOffset, nOffset );
534 0 : CPLFree( pabyRecord );
535 0 : return FALSE;
536 : }
537 :
538 14054 : CPLFree( pabyRecord );
539 :
540 14054 : return TRUE;
541 :
542 : }
543 :
544 : /************************************************************************/
545 : /* DTEDGetMetadataLocation() */
546 : /************************************************************************/
547 :
548 931 : static void DTEDGetMetadataLocation( DTEDInfo *psDInfo,
549 : DTEDMetaDataCode eCode,
550 : char **ppszLocation, int *pnLength )
551 : {
552 931 : switch( eCode )
553 : {
554 : case DTEDMD_VERTACCURACY_UHL:
555 49 : *ppszLocation = psDInfo->pachUHLRecord + 28;
556 49 : *pnLength = 4;
557 49 : break;
558 :
559 : case DTEDMD_SECURITYCODE_UHL:
560 49 : *ppszLocation = psDInfo->pachUHLRecord + 32;
561 49 : *pnLength = 3;
562 49 : break;
563 :
564 : case DTEDMD_UNIQUEREF_UHL:
565 49 : *ppszLocation = psDInfo->pachUHLRecord + 35;
566 49 : *pnLength = 12;
567 49 : break;
568 :
569 : case DTEDMD_DATA_EDITION:
570 49 : *ppszLocation = psDInfo->pachDSIRecord + 87;
571 49 : *pnLength = 2;
572 49 : break;
573 :
574 : case DTEDMD_MATCHMERGE_VERSION:
575 49 : *ppszLocation = psDInfo->pachDSIRecord + 89;
576 49 : *pnLength = 1;
577 49 : break;
578 :
579 : case DTEDMD_MAINT_DATE:
580 49 : *ppszLocation = psDInfo->pachDSIRecord + 90;
581 49 : *pnLength = 4;
582 49 : break;
583 :
584 : case DTEDMD_MATCHMERGE_DATE:
585 49 : *ppszLocation = psDInfo->pachDSIRecord + 94;
586 49 : *pnLength = 4;
587 49 : break;
588 :
589 : case DTEDMD_MAINT_DESCRIPTION:
590 49 : *ppszLocation = psDInfo->pachDSIRecord + 98;
591 49 : *pnLength = 4;
592 49 : break;
593 :
594 : case DTEDMD_PRODUCER:
595 49 : *ppszLocation = psDInfo->pachDSIRecord + 102;
596 49 : *pnLength = 8;
597 49 : break;
598 :
599 : case DTEDMD_VERTDATUM:
600 49 : *ppszLocation = psDInfo->pachDSIRecord + 141;
601 49 : *pnLength = 3;
602 49 : break;
603 :
604 : case DTEDMD_HORIZDATUM:
605 49 : *ppszLocation = psDInfo->pachDSIRecord + 144;
606 49 : *pnLength = 5;
607 49 : break;
608 :
609 : case DTEDMD_DIGITIZING_SYS:
610 49 : *ppszLocation = psDInfo->pachDSIRecord + 149;
611 49 : *pnLength = 10;
612 49 : break;
613 :
614 : case DTEDMD_COMPILATION_DATE:
615 49 : *ppszLocation = psDInfo->pachDSIRecord + 159;
616 49 : *pnLength = 4;
617 49 : break;
618 :
619 : case DTEDMD_HORIZACCURACY:
620 49 : *ppszLocation = psDInfo->pachACCRecord + 3;
621 49 : *pnLength = 4;
622 49 : break;
623 :
624 : case DTEDMD_REL_HORIZACCURACY:
625 49 : *ppszLocation = psDInfo->pachACCRecord + 11;
626 49 : *pnLength = 4;
627 49 : break;
628 :
629 : case DTEDMD_REL_VERTACCURACY:
630 49 : *ppszLocation = psDInfo->pachACCRecord + 15;
631 49 : *pnLength = 4;
632 49 : break;
633 :
634 : case DTEDMD_VERTACCURACY_ACC:
635 49 : *ppszLocation = psDInfo->pachACCRecord + 7;
636 49 : *pnLength = 4;
637 49 : break;
638 :
639 : case DTEDMD_SECURITYCODE_DSI:
640 49 : *ppszLocation = psDInfo->pachDSIRecord + 3;
641 49 : *pnLength = 1;
642 49 : break;
643 :
644 : case DTEDMD_UNIQUEREF_DSI:
645 49 : *ppszLocation = psDInfo->pachDSIRecord + 64;
646 49 : *pnLength = 15;
647 49 : break;
648 :
649 : default:
650 0 : *ppszLocation = NULL;
651 0 : *pnLength = 0;
652 : }
653 931 : }
654 :
655 : /************************************************************************/
656 : /* DTEDGetMetadata() */
657 : /************************************************************************/
658 :
659 893 : char *DTEDGetMetadata( DTEDInfo *psDInfo, DTEDMetaDataCode eCode )
660 :
661 : {
662 : int nFieldLen;
663 : char *pszFieldSrc;
664 : char *pszResult;
665 :
666 893 : DTEDGetMetadataLocation( psDInfo, eCode, &pszFieldSrc, &nFieldLen );
667 893 : if( pszFieldSrc == NULL )
668 0 : return VSIStrdup( "" );
669 :
670 893 : pszResult = (char *) malloc(nFieldLen+1);
671 893 : strncpy( pszResult, pszFieldSrc, nFieldLen );
672 893 : pszResult[nFieldLen] = '\0';
673 :
674 893 : return pszResult;
675 : }
676 :
677 : /************************************************************************/
678 : /* DTEDSetMetadata() */
679 : /************************************************************************/
680 :
681 38 : int DTEDSetMetadata( DTEDInfo *psDInfo, DTEDMetaDataCode eCode,
682 : const char *pszNewValue )
683 :
684 : {
685 : int nFieldLen;
686 : char *pszFieldSrc;
687 :
688 38 : if( !psDInfo->bUpdate )
689 0 : return FALSE;
690 :
691 : /* -------------------------------------------------------------------- */
692 : /* Get the location in the headers to update. */
693 : /* -------------------------------------------------------------------- */
694 38 : DTEDGetMetadataLocation( psDInfo, eCode, &pszFieldSrc, &nFieldLen );
695 38 : if( pszFieldSrc == NULL )
696 0 : return FALSE;
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Update it, padding with spaces. */
700 : /* -------------------------------------------------------------------- */
701 38 : memset( pszFieldSrc, ' ', nFieldLen );
702 38 : strncpy( pszFieldSrc, pszNewValue,
703 38 : MIN((size_t)nFieldLen,strlen(pszNewValue)) );
704 :
705 : /* -------------------------------------------------------------------- */
706 : /* Write all headers back to disk. */
707 : /* -------------------------------------------------------------------- */
708 38 : VSIFSeekL( psDInfo->fp, psDInfo->nUHLOffset, SEEK_SET );
709 38 : VSIFWriteL( psDInfo->pachUHLRecord, 1, DTED_UHL_SIZE, psDInfo->fp );
710 :
711 38 : VSIFSeekL( psDInfo->fp, psDInfo->nDSIOffset, SEEK_SET );
712 38 : VSIFWriteL( psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, psDInfo->fp );
713 :
714 38 : VSIFSeekL( psDInfo->fp, psDInfo->nACCOffset, SEEK_SET );
715 38 : VSIFWriteL( psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, psDInfo->fp );
716 :
717 38 : return TRUE;
718 : }
719 :
720 : /************************************************************************/
721 : /* DTEDClose() */
722 : /************************************************************************/
723 :
724 61 : void DTEDClose( DTEDInfo * psDInfo )
725 :
726 : {
727 61 : VSIFCloseL( psDInfo->fp );
728 :
729 61 : CPLFree( psDInfo->pachUHLRecord );
730 61 : CPLFree( psDInfo->pachDSIRecord );
731 61 : CPLFree( psDInfo->pachACCRecord );
732 :
733 61 : CPLFree( psDInfo );
734 61 : }
|