/src/gdal/frmts/dted/dted_api.c
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: DTED Translator |
4 | | * Purpose: Implementation of DTED/CDED access functions. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 1999, Frank Warmerdam |
9 | | * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "dted_api.h" |
15 | | |
16 | | #ifndef AVOID_CPL |
17 | | #endif |
18 | | |
19 | | static int bWarnedTwoComplement = FALSE; |
20 | | |
21 | | static void DTEDDetectVariantWithMissingColumns(DTEDInfo *psDInfo); |
22 | | |
23 | | CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) |
24 | 54 | { |
25 | 54 | } |
26 | | |
27 | | CPL_INLINE static void CPL_IGNORE_RET_VAL_SIZET(CPL_UNUSED size_t unused) |
28 | 136 | { |
29 | 136 | } |
30 | | |
31 | 1.23k | #define DIGIT_ZERO '0' |
32 | | |
33 | | /************************************************************************/ |
34 | | /* DTEDGetField() */ |
35 | | /* */ |
36 | | /* Extract a field as a zero terminated string. Address is */ |
37 | | /* deliberately 1 based so the getfield arguments will be the */ |
38 | | /* same as the numbers in the file format specification. */ |
39 | | /************************************************************************/ |
40 | | |
41 | | static char *DTEDGetField(char szResult[81], const char *pachRecord, int nStart, |
42 | | int nSize) |
43 | | |
44 | 528 | { |
45 | 528 | CPLAssert(nSize < 81); |
46 | 528 | memcpy(szResult, pachRecord + nStart - 1, nSize); |
47 | 528 | szResult[nSize] = '\0'; |
48 | | |
49 | 528 | return szResult; |
50 | 528 | } |
51 | | |
52 | | /************************************************************************/ |
53 | | /* StripLeadingZeros() */ |
54 | | /* */ |
55 | | /* Return a pointer to the first non-zero character in BUF. */ |
56 | | /* BUF must be null terminated. */ |
57 | | /* If buff is all zeros, then it will point to the last non-zero */ |
58 | | /************************************************************************/ |
59 | | |
60 | | static const char *stripLeadingZeros(const char *buf) |
61 | 312 | { |
62 | 312 | const char *ptr = buf; |
63 | | |
64 | | /* Go until we run out of characters or hit something non-zero */ |
65 | | |
66 | 618 | while (*ptr == DIGIT_ZERO && *(ptr + 1) != '\0') |
67 | 306 | { |
68 | 306 | ptr++; |
69 | 306 | } |
70 | | |
71 | 312 | return ptr; |
72 | 312 | } |
73 | | |
74 | | /************************************************************************/ |
75 | | /* DTEDOpen() */ |
76 | | /************************************************************************/ |
77 | | |
78 | | DTEDInfo *DTEDOpen(const char *pszFilename, const char *pszAccess, |
79 | | int bTestOpen) |
80 | | |
81 | 0 | { |
82 | 0 | VSILFILE *fp; |
83 | | |
84 | | /* -------------------------------------------------------------------- */ |
85 | | /* Open the physical file. */ |
86 | | /* -------------------------------------------------------------------- */ |
87 | 0 | if (EQUAL(pszAccess, "r") || EQUAL(pszAccess, "rb")) |
88 | 0 | pszAccess = "rb"; |
89 | 0 | else |
90 | 0 | pszAccess = "r+b"; |
91 | |
|
92 | 0 | fp = VSIFOpenL(pszFilename, pszAccess); |
93 | |
|
94 | 0 | if (fp == NULL) |
95 | 0 | { |
96 | 0 | if (!bTestOpen) |
97 | 0 | { |
98 | 0 | #ifndef AVOID_CPL |
99 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, |
100 | | #else |
101 | | fprintf(stderr, |
102 | | #endif |
103 | 0 | "Failed to open file %s.", pszFilename); |
104 | 0 | } |
105 | |
|
106 | 0 | return NULL; |
107 | 0 | } |
108 | | |
109 | 0 | return DTEDOpenEx(fp, pszFilename, pszAccess, bTestOpen); |
110 | 0 | } |
111 | | |
112 | | /************************************************************************/ |
113 | | /* DTEDOpenEx() */ |
114 | | /************************************************************************/ |
115 | | |
116 | | DTEDInfo *DTEDOpenEx(VSILFILE *fp, const char *pszFilename, |
117 | | const char *pszAccess, int bTestOpen) |
118 | | |
119 | 54 | { |
120 | 54 | char achRecord[DTED_UHL_SIZE]; |
121 | 54 | DTEDInfo *psDInfo = NULL; |
122 | 54 | double dfLLOriginX, dfLLOriginY; |
123 | 54 | int deg = 0; |
124 | 54 | int min = 0; |
125 | 54 | int sec = 0; |
126 | 54 | int bSwapLatLong = FALSE; |
127 | 54 | char szResult[81]; |
128 | 54 | int bIsWeirdDTED; |
129 | 54 | char chHemisphere; |
130 | | |
131 | | /* -------------------------------------------------------------------- */ |
132 | | /* Read, trying to find the UHL record. Skip VOL or HDR */ |
133 | | /* records if they are encountered. */ |
134 | | /* -------------------------------------------------------------------- */ |
135 | 54 | do |
136 | 61 | { |
137 | 61 | if (VSIFReadL(achRecord, 1, DTED_UHL_SIZE, fp) != DTED_UHL_SIZE) |
138 | 0 | { |
139 | 0 | if (!bTestOpen) |
140 | 0 | { |
141 | 0 | #ifndef AVOID_CPL |
142 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, |
143 | | #else |
144 | | fprintf(stderr, |
145 | | #endif |
146 | 0 | "Unable to read header, %s is not DTED.", pszFilename); |
147 | 0 | } |
148 | 0 | CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp)); |
149 | 0 | return NULL; |
150 | 0 | } |
151 | | |
152 | 61 | } while (STARTS_WITH_CI(achRecord, "VOL") || |
153 | 61 | STARTS_WITH_CI(achRecord, "HDR")); |
154 | | |
155 | 54 | if (!STARTS_WITH_CI(achRecord, "UHL")) |
156 | 0 | { |
157 | 0 | if (!bTestOpen) |
158 | 0 | { |
159 | 0 | #ifndef AVOID_CPL |
160 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, |
161 | | #else |
162 | | fprintf(stderr, |
163 | | #endif |
164 | 0 | "No UHL record. %s is not a DTED file.", pszFilename); |
165 | 0 | } |
166 | 0 | CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp)); |
167 | 0 | return NULL; |
168 | 0 | } |
169 | | |
170 | | /* -------------------------------------------------------------------- */ |
171 | | /* Create and initialize the DTEDInfo structure. */ |
172 | | /* -------------------------------------------------------------------- */ |
173 | 54 | psDInfo = (DTEDInfo *)CPLCalloc(1, sizeof(DTEDInfo)); |
174 | | |
175 | 54 | psDInfo->fp = fp; |
176 | | |
177 | 54 | psDInfo->bUpdate = EQUAL(pszAccess, "r+b"); |
178 | 54 | psDInfo->bRewriteHeaders = FALSE; |
179 | | |
180 | 54 | psDInfo->nUHLOffset = (int)VSIFTellL(fp) - DTED_UHL_SIZE; |
181 | 54 | psDInfo->pachUHLRecord = (char *)CPLMalloc(DTED_UHL_SIZE); |
182 | 54 | memcpy(psDInfo->pachUHLRecord, achRecord, DTED_UHL_SIZE); |
183 | | |
184 | 54 | psDInfo->nDSIOffset = (int)VSIFTellL(fp); |
185 | 54 | psDInfo->pachDSIRecord = (char *)CPLMalloc(DTED_DSI_SIZE); |
186 | 54 | CPL_IGNORE_RET_VAL_SIZET( |
187 | 54 | VSIFReadL(psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, fp)); |
188 | | |
189 | 54 | psDInfo->nACCOffset = (int)VSIFTellL(fp); |
190 | 54 | psDInfo->pachACCRecord = (char *)CPLMalloc(DTED_ACC_SIZE); |
191 | 54 | CPL_IGNORE_RET_VAL_SIZET( |
192 | 54 | VSIFReadL(psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, fp)); |
193 | | |
194 | 54 | if (!STARTS_WITH_CI(psDInfo->pachDSIRecord, "DSI") || |
195 | 54 | !STARTS_WITH_CI(psDInfo->pachACCRecord, "ACC")) |
196 | 0 | { |
197 | 0 | #ifndef AVOID_CPL |
198 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, |
199 | | #else |
200 | | fprintf(stderr, |
201 | | #endif |
202 | 0 | "DSI or ACC record missing. DTED access to\n%s failed.", |
203 | 0 | pszFilename); |
204 | |
|
205 | 0 | DTEDClose(psDInfo); |
206 | 0 | return NULL; |
207 | 0 | } |
208 | | |
209 | 54 | psDInfo->nDataOffset = (int)VSIFTellL(fp); |
210 | | |
211 | | /* DTED3 file from http://www.falconview.org/trac/FalconView/downloads/20 */ |
212 | | /* (co_elevation.zip) has really weird offsets that don't comply with the |
213 | | * 89020B specification */ |
214 | 54 | bIsWeirdDTED = achRecord[4] == ' '; |
215 | | |
216 | | /* -------------------------------------------------------------------- */ |
217 | | /* Parse out position information. Note that we are extracting */ |
218 | | /* the top left corner of the top left pixel area, not the */ |
219 | | /* center of the area. */ |
220 | | /* -------------------------------------------------------------------- */ |
221 | 54 | if (!bIsWeirdDTED) |
222 | 54 | { |
223 | 54 | psDInfo->dfPixelSizeX = |
224 | 54 | atoi(DTEDGetField(szResult, achRecord, 21, 4)) / 36000.0; |
225 | | |
226 | 54 | psDInfo->dfPixelSizeY = |
227 | 54 | atoi(DTEDGetField(szResult, achRecord, 25, 4)) / 36000.0; |
228 | | |
229 | 54 | psDInfo->nXSize = atoi(DTEDGetField(szResult, achRecord, 48, 4)); |
230 | 54 | psDInfo->nYSize = atoi(DTEDGetField(szResult, achRecord, 52, 4)); |
231 | 54 | } |
232 | 0 | else |
233 | 0 | { |
234 | 0 | psDInfo->dfPixelSizeX = |
235 | 0 | atoi(DTEDGetField(szResult, achRecord, 41, 4)) / 36000.0; |
236 | |
|
237 | 0 | psDInfo->dfPixelSizeY = |
238 | 0 | atoi(DTEDGetField(szResult, achRecord, 45, 4)) / 36000.0; |
239 | |
|
240 | 0 | psDInfo->nXSize = |
241 | 0 | atoi(DTEDGetField(szResult, psDInfo->pachDSIRecord, 563, 4)); |
242 | 0 | psDInfo->nYSize = |
243 | 0 | atoi(DTEDGetField(szResult, psDInfo->pachDSIRecord, 567, 4)); |
244 | 0 | } |
245 | | |
246 | 54 | if (psDInfo->nXSize <= 0 || psDInfo->nYSize <= 0) |
247 | 2 | { |
248 | 2 | #ifndef AVOID_CPL |
249 | 2 | CPLError(CE_Failure, CPLE_OpenFailed, |
250 | | #else |
251 | | fprintf(stderr, |
252 | | #endif |
253 | 2 | "Invalid dimensions : %d x %d. DTED access to\n%s failed.", |
254 | 2 | psDInfo->nXSize, psDInfo->nYSize, pszFilename); |
255 | | |
256 | 2 | DTEDClose(psDInfo); |
257 | 2 | return NULL; |
258 | 2 | } |
259 | | |
260 | | /* create a scope so I don't need to declare these up top */ |
261 | 52 | if (!bIsWeirdDTED) |
262 | 52 | { |
263 | 52 | deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 5, 3))); |
264 | 52 | min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 8, 2))); |
265 | 52 | sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 10, 2))); |
266 | 52 | chHemisphere = achRecord[11]; |
267 | 52 | } |
268 | 0 | else |
269 | 0 | { |
270 | 0 | deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 9, 3))); |
271 | 0 | min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 12, 2))); |
272 | 0 | sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 14, 2))); |
273 | 0 | chHemisphere = achRecord[15]; |
274 | 0 | } |
275 | | |
276 | | /* NOTE : The first version of MIL-D-89020 was buggy. |
277 | | The latitude and longitude of the LL corner of the UHF record was |
278 | | inverted. This was fixed in MIL-D-89020 Amendment 1, but some products |
279 | | may be affected. We detect this situation by looking at N/S in the |
280 | | longitude field and E/W in the latitude one. |
281 | | */ |
282 | | |
283 | 52 | dfLLOriginX = deg + min / 60.0 + sec / 3600.0; |
284 | 52 | if (chHemisphere == 'W') |
285 | 48 | dfLLOriginX *= -1; |
286 | 4 | else if (chHemisphere == 'N') |
287 | 1 | bSwapLatLong = TRUE; |
288 | 3 | else if (chHemisphere == 'S') |
289 | 0 | { |
290 | 0 | dfLLOriginX *= -1; |
291 | 0 | bSwapLatLong = TRUE; |
292 | 0 | } |
293 | | |
294 | 52 | if (!bIsWeirdDTED) |
295 | 52 | { |
296 | 52 | deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 13, 3))); |
297 | 52 | min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 16, 2))); |
298 | 52 | sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 18, 2))); |
299 | 52 | chHemisphere = achRecord[19]; |
300 | 52 | } |
301 | 0 | else |
302 | 0 | { |
303 | 0 | deg = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 25, 3))); |
304 | 0 | min = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 28, 2))); |
305 | 0 | sec = atoi(stripLeadingZeros(DTEDGetField(szResult, achRecord, 30, 2))); |
306 | 0 | chHemisphere = achRecord[31]; |
307 | 0 | } |
308 | | |
309 | 52 | dfLLOriginY = deg + min / 60.0 + sec / 3600.0; |
310 | 52 | if (chHemisphere == 'S' || (bSwapLatLong && chHemisphere == 'W')) |
311 | 1 | dfLLOriginY *= -1; |
312 | | |
313 | 52 | if (bSwapLatLong) |
314 | 1 | { |
315 | 1 | double dfTmp = dfLLOriginX; |
316 | 1 | dfLLOriginX = dfLLOriginY; |
317 | 1 | dfLLOriginY = dfTmp; |
318 | 1 | } |
319 | | |
320 | 52 | psDInfo->dfULCornerX = dfLLOriginX - 0.5 * psDInfo->dfPixelSizeX; |
321 | 52 | psDInfo->dfULCornerY = dfLLOriginY - 0.5 * psDInfo->dfPixelSizeY + |
322 | 52 | psDInfo->nYSize * psDInfo->dfPixelSizeY; |
323 | | |
324 | 52 | DTEDDetectVariantWithMissingColumns(psDInfo); |
325 | | |
326 | 52 | psDInfo->bAssumeConformant = |
327 | 52 | CPLTestBool(CPLGetConfigOption("DTED_ASSUME_CONFORMANT", "NO")); |
328 | | |
329 | 52 | return psDInfo; |
330 | 54 | } |
331 | | |
332 | | /************************************************************************/ |
333 | | /* DTEDDetectVariantWithMissingColumns() */ |
334 | | /************************************************************************/ |
335 | | |
336 | | static void DTEDDetectVariantWithMissingColumns(DTEDInfo *psDInfo) |
337 | 52 | { |
338 | | /* -------------------------------------------------------------------- */ |
339 | | /* Some DTED files have only a subset of all possible columns. */ |
340 | | /* They can declare for example 3601 columns, but in the file, */ |
341 | | /* there are just columns 100->500. Detect that situation. */ |
342 | | /* -------------------------------------------------------------------- */ |
343 | | |
344 | 52 | GByte pabyRecordHeader[8]; |
345 | 52 | int nFirstDataBlockCount, nFirstLongitudeCount; |
346 | 52 | int nLastDataBlockCount, nLastLongitudeCount; |
347 | 52 | int nSize; |
348 | 52 | int nColByteSize = 12 + psDInfo->nYSize * 2; |
349 | | |
350 | 52 | if (VSIFSeekL(psDInfo->fp, psDInfo->nDataOffset, SEEK_SET) < 0 || |
351 | 52 | VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 || |
352 | 49 | pabyRecordHeader[0] != 0252) |
353 | 24 | { |
354 | 24 | CPLDebug("DTED", "Cannot find signature of first column"); |
355 | 24 | return; |
356 | 24 | } |
357 | | |
358 | 28 | nFirstDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3]; |
359 | 28 | nFirstLongitudeCount = (pabyRecordHeader[4] << 8) | pabyRecordHeader[5]; |
360 | | |
361 | 28 | CPL_IGNORE_RET_VAL_SIZET(VSIFSeekL(psDInfo->fp, 0, SEEK_END)); |
362 | 28 | nSize = (int)VSIFTellL(psDInfo->fp); |
363 | 28 | if (nSize < 12 + psDInfo->nYSize * 2) |
364 | 0 | { |
365 | 0 | CPLDebug("DTED", "File too short"); |
366 | 0 | return; |
367 | 0 | } |
368 | | |
369 | 28 | if (VSIFSeekL(psDInfo->fp, nSize - nColByteSize, SEEK_SET) < 0 || |
370 | 28 | VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 || |
371 | 28 | pabyRecordHeader[0] != 0252) |
372 | 8 | { |
373 | 8 | CPLDebug("DTED", "Cannot find signature of last column"); |
374 | 8 | return; |
375 | 8 | } |
376 | | |
377 | 20 | nLastDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3]; |
378 | 20 | nLastLongitudeCount = (pabyRecordHeader[4] << 8) | pabyRecordHeader[5]; |
379 | | |
380 | 20 | if (nFirstDataBlockCount == 0 && nFirstLongitudeCount == 0 && |
381 | 14 | nLastDataBlockCount == psDInfo->nXSize - 1 && |
382 | 14 | nLastLongitudeCount == psDInfo->nXSize - 1 && |
383 | 14 | nSize - psDInfo->nDataOffset == psDInfo->nXSize * nColByteSize) |
384 | 2 | { |
385 | | /* This is the most standard form of DTED. Return happily now. */ |
386 | 2 | return; |
387 | 2 | } |
388 | | |
389 | | /* Well, we have an odd DTED file at that point */ |
390 | | |
391 | 18 | psDInfo->panMapLogicalColsToOffsets = |
392 | 18 | (int *)CPLMalloc(psDInfo->nXSize * sizeof(int)); |
393 | | |
394 | 18 | if (nFirstDataBlockCount == 0 && |
395 | 16 | nLastLongitudeCount - nFirstLongitudeCount == |
396 | 16 | nLastDataBlockCount - nFirstDataBlockCount && |
397 | 13 | nSize - psDInfo->nDataOffset == |
398 | 13 | (nLastLongitudeCount - nFirstLongitudeCount + 1) * nColByteSize) |
399 | 1 | { |
400 | 1 | int i; |
401 | | |
402 | | /* Case seen in a real-world file */ |
403 | | |
404 | 1 | CPLDebug("DTED", |
405 | 1 | "The file only contains data from column %d to column %d.", |
406 | 1 | nFirstLongitudeCount, nLastLongitudeCount); |
407 | | |
408 | 122 | for (i = 0; i < psDInfo->nXSize; i++) |
409 | 121 | { |
410 | 121 | if (i < nFirstLongitudeCount) |
411 | 2 | psDInfo->panMapLogicalColsToOffsets[i] = -1; |
412 | 119 | else if (i <= nLastLongitudeCount) |
413 | 2 | psDInfo->panMapLogicalColsToOffsets[i] = |
414 | 2 | psDInfo->nDataOffset + |
415 | 2 | (i - nFirstLongitudeCount) * nColByteSize; |
416 | 117 | else |
417 | 117 | psDInfo->panMapLogicalColsToOffsets[i] = -1; |
418 | 121 | } |
419 | 1 | } |
420 | 17 | else |
421 | 17 | { |
422 | 17 | int nPhysicalCols = (nSize - psDInfo->nDataOffset) / nColByteSize; |
423 | 17 | int i; |
424 | | |
425 | | /* Theoretical case for now... */ |
426 | | |
427 | 17 | CPLDebug("DTED", "There columns appear to be in non sequential order. " |
428 | 17 | "Scanning the whole file."); |
429 | | |
430 | 2.07k | for (i = 0; i < psDInfo->nXSize; i++) |
431 | 2.05k | { |
432 | 2.05k | psDInfo->panMapLogicalColsToOffsets[i] = -1; |
433 | 2.05k | } |
434 | | |
435 | 489 | for (i = 0; i < nPhysicalCols; i++) |
436 | 487 | { |
437 | 487 | int nDataBlockCount; |
438 | | |
439 | 487 | if (VSIFSeekL(psDInfo->fp, psDInfo->nDataOffset + i * nColByteSize, |
440 | 487 | SEEK_SET) < 0 || |
441 | 487 | VSIFReadL(pabyRecordHeader, 1, 8, psDInfo->fp) != 8 || |
442 | 487 | pabyRecordHeader[0] != 0252) |
443 | 14 | { |
444 | 14 | CPLDebug("DTED", "Cannot find signature of physical column %d", |
445 | 14 | i); |
446 | 14 | return; |
447 | 14 | } |
448 | | |
449 | 473 | nDataBlockCount = (pabyRecordHeader[2] << 8) | pabyRecordHeader[3]; |
450 | 473 | if (nDataBlockCount != i) |
451 | 2 | { |
452 | 2 | CPLDebug("DTED", |
453 | 2 | "Unexpected block count(%d) at physical column %d. " |
454 | 2 | "Ignoring that and going on...", |
455 | 2 | nDataBlockCount, i); |
456 | 2 | } |
457 | | |
458 | 473 | const int nLongitudeCount = |
459 | 473 | (pabyRecordHeader[4] << 8) | pabyRecordHeader[5]; |
460 | 473 | if (nLongitudeCount >= psDInfo->nXSize) |
461 | 1 | { |
462 | 1 | CPLDebug("DTED", |
463 | 1 | "Invalid longitude count (%d) at physical column %d", |
464 | 1 | nLongitudeCount, i); |
465 | 1 | return; |
466 | 1 | } |
467 | | |
468 | 472 | psDInfo->panMapLogicalColsToOffsets[nLongitudeCount] = |
469 | 472 | psDInfo->nDataOffset + i * nColByteSize; |
470 | 472 | } |
471 | 17 | } |
472 | 18 | } |
473 | | |
474 | | /************************************************************************/ |
475 | | /* DTEDReadPoint() */ |
476 | | /* */ |
477 | | /* Read one single sample. The coordinates are given from the */ |
478 | | /* top-left corner of the file (contrary to the internal */ |
479 | | /* organization or a DTED file) */ |
480 | | /************************************************************************/ |
481 | | |
482 | | int DTEDReadPoint(DTEDInfo *psDInfo, int nXOff, int nYOff, GInt16 *panVal) |
483 | 0 | { |
484 | 0 | int nOffset; |
485 | 0 | GByte pabyData[2]; |
486 | |
|
487 | 0 | if (nYOff < 0 || nXOff < 0 || nYOff >= psDInfo->nYSize || |
488 | 0 | nXOff >= psDInfo->nXSize) |
489 | 0 | { |
490 | 0 | #ifndef AVOID_CPL |
491 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
492 | | #else |
493 | | fprintf(stderr, |
494 | | #endif |
495 | 0 | "Invalid raster coordinates (%d,%d) in DTED file.\n", nXOff, |
496 | 0 | nYOff); |
497 | 0 | return FALSE; |
498 | 0 | } |
499 | | |
500 | 0 | if (psDInfo->panMapLogicalColsToOffsets != NULL) |
501 | 0 | { |
502 | 0 | nOffset = psDInfo->panMapLogicalColsToOffsets[nXOff]; |
503 | 0 | if (nOffset < 0) |
504 | 0 | { |
505 | 0 | *panVal = DTED_NODATA_VALUE; |
506 | 0 | return TRUE; |
507 | 0 | } |
508 | 0 | } |
509 | 0 | else |
510 | 0 | nOffset = psDInfo->nDataOffset + nXOff * (12 + psDInfo->nYSize * 2); |
511 | 0 | nOffset += 8 + 2 * (psDInfo->nYSize - 1 - nYOff); |
512 | |
|
513 | 0 | if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 || |
514 | 0 | VSIFReadL(pabyData, 2, 1, psDInfo->fp) != 1) |
515 | 0 | { |
516 | 0 | #ifndef AVOID_CPL |
517 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
518 | | #else |
519 | | fprintf(stderr, |
520 | | #endif |
521 | 0 | "Failed to seek to, or read (%d,%d) at offset %d\n" |
522 | 0 | "in DTED file.\n", |
523 | 0 | nXOff, nYOff, nOffset); |
524 | 0 | return FALSE; |
525 | 0 | } |
526 | | |
527 | 0 | *panVal = ((pabyData[0] & 0x7f) << 8) | pabyData[1]; |
528 | |
|
529 | 0 | if (pabyData[0] & 0x80) |
530 | 0 | { |
531 | 0 | *panVal *= -1; |
532 | | |
533 | | /* |
534 | | ** It seems that some files are improperly generated in twos |
535 | | ** complement form for negatives. For these, redo the job |
536 | | ** in twos complement. eg. w_069_s50.dt0 |
537 | | */ |
538 | 0 | if (!psDInfo->bAssumeConformant && (*panVal < -16000) && |
539 | 0 | (*panVal != DTED_NODATA_VALUE)) |
540 | 0 | { |
541 | 0 | *panVal = (pabyData[0] << 8) | pabyData[1]; |
542 | |
|
543 | 0 | if (!bWarnedTwoComplement) |
544 | 0 | { |
545 | 0 | bWarnedTwoComplement = TRUE; |
546 | 0 | #ifndef AVOID_CPL |
547 | 0 | CPLError( |
548 | 0 | CE_Warning, CPLE_AppDefined, |
549 | | #else |
550 | | fprintf( |
551 | | stderr, |
552 | | #endif |
553 | 0 | "The DTED driver found values less than -16000, and has " |
554 | 0 | "adjusted\n" |
555 | 0 | "them assuming they are improperly two-complemented. If " |
556 | 0 | "you wish to\n" |
557 | 0 | "disable this behavior, set the DTED_ASSUME_CONFORMANT " |
558 | 0 | "configuration\n" |
559 | 0 | "option to YES. No more warnings will be issued in this " |
560 | 0 | "session\n" |
561 | 0 | "about this operation."); |
562 | 0 | } |
563 | 0 | } |
564 | 0 | } |
565 | |
|
566 | 0 | return TRUE; |
567 | 0 | } |
568 | | |
569 | | /************************************************************************/ |
570 | | /* DTEDReadProfile() */ |
571 | | /* */ |
572 | | /* Read one profile line. These are organized in bottom to top */ |
573 | | /* order starting from the leftmost column (0). */ |
574 | | /************************************************************************/ |
575 | | |
576 | | int DTEDReadProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData) |
577 | 0 | { |
578 | 0 | return DTEDReadProfileEx(psDInfo, nColumnOffset, panData, FALSE); |
579 | 0 | } |
580 | | |
581 | | int DTEDReadProfileEx(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData, |
582 | | int bVerifyChecksum) |
583 | 3.59k | { |
584 | 3.59k | int nOffset; |
585 | 3.59k | int i; |
586 | 3.59k | GByte *pabyRecord; |
587 | 3.59k | int nLongitudeCount; |
588 | | |
589 | | /* -------------------------------------------------------------------- */ |
590 | | /* Read data record from disk. */ |
591 | | /* -------------------------------------------------------------------- */ |
592 | 3.59k | if (psDInfo->panMapLogicalColsToOffsets != NULL) |
593 | 2.17k | { |
594 | 2.17k | nOffset = psDInfo->panMapLogicalColsToOffsets[nColumnOffset]; |
595 | 2.17k | if (nOffset < 0) |
596 | 1.70k | { |
597 | 207k | for (i = 0; i < psDInfo->nYSize; i++) |
598 | 206k | { |
599 | 206k | panData[i] = DTED_NODATA_VALUE; |
600 | 206k | } |
601 | 1.70k | return TRUE; |
602 | 1.70k | } |
603 | 2.17k | } |
604 | 1.41k | else |
605 | 1.41k | nOffset = |
606 | 1.41k | psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2); |
607 | | |
608 | 1.89k | pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2); |
609 | | |
610 | 1.89k | if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 || |
611 | 1.89k | VSIFReadL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1) |
612 | 31 | { |
613 | 31 | #ifndef AVOID_CPL |
614 | 31 | CPLError(CE_Failure, CPLE_FileIO, |
615 | | #else |
616 | | fprintf(stderr, |
617 | | #endif |
618 | 31 | "Failed to seek to, or read profile %d at offset %d\n" |
619 | 31 | "in DTED file.\n", |
620 | 31 | nColumnOffset, nOffset); |
621 | 31 | CPLFree(pabyRecord); |
622 | 31 | return FALSE; |
623 | 31 | } |
624 | | |
625 | 1.85k | nLongitudeCount = (pabyRecord[4] << 8) | pabyRecord[5]; |
626 | 1.85k | if (nLongitudeCount != nColumnOffset) |
627 | 951 | { |
628 | 951 | #ifndef AVOID_CPL |
629 | 951 | CPLError( |
630 | 951 | CE_Warning, CPLE_AppDefined, |
631 | | #else |
632 | | fprintf( |
633 | | stderr, |
634 | | #endif |
635 | 951 | "Longitude count (%d) of column %d doesn't match expected value.\n", |
636 | 951 | nLongitudeCount, nColumnOffset); |
637 | 951 | } |
638 | | |
639 | | /* -------------------------------------------------------------------- */ |
640 | | /* Translate data values from "signed magnitude" to standard */ |
641 | | /* binary. */ |
642 | | /* -------------------------------------------------------------------- */ |
643 | 182k | for (i = 0; i < psDInfo->nYSize; i++) |
644 | 180k | { |
645 | 180k | panData[i] = |
646 | 180k | ((pabyRecord[8 + i * 2] & 0x7f) << 8) | pabyRecord[8 + i * 2 + 1]; |
647 | | |
648 | 180k | if (pabyRecord[8 + i * 2] & 0x80) |
649 | 10.0k | { |
650 | 10.0k | panData[i] *= -1; |
651 | | |
652 | | /* |
653 | | ** It seems that some files are improperly generated in twos |
654 | | ** complement form for negatives. For these, redo the job |
655 | | ** in twos complement. eg. w_069_s50.dt0 |
656 | | */ |
657 | 10.0k | if ((panData[i] < -16000) && (panData[i] != DTED_NODATA_VALUE)) |
658 | 4.02k | { |
659 | 4.02k | panData[i] = |
660 | 4.02k | (pabyRecord[8 + i * 2] << 8) | pabyRecord[8 + i * 2 + 1]; |
661 | | |
662 | 4.02k | if (!bWarnedTwoComplement) |
663 | 2 | { |
664 | 2 | bWarnedTwoComplement = TRUE; |
665 | 2 | #ifndef AVOID_CPL |
666 | 2 | CPLError( |
667 | 2 | CE_Warning, CPLE_AppDefined, |
668 | | #else |
669 | | fprintf( |
670 | | stderr, |
671 | | #endif |
672 | 2 | "The DTED driver found values less than -16000, and " |
673 | 2 | "has adjusted\n" |
674 | 2 | "them assuming they are improperly two-complemented. " |
675 | 2 | "No more warnings\n" |
676 | 2 | "will be issued in this session about this operation."); |
677 | 2 | } |
678 | 4.02k | } |
679 | 10.0k | } |
680 | 180k | } |
681 | | |
682 | 1.85k | if (bVerifyChecksum) |
683 | 0 | { |
684 | 0 | unsigned int nCheckSum = 0; |
685 | 0 | unsigned int fileCheckSum; |
686 | | |
687 | | /* -------------------------------------------------------------------- |
688 | | */ |
689 | | /* Verify the checksum. */ |
690 | | /* -------------------------------------------------------------------- |
691 | | */ |
692 | |
|
693 | 0 | for (i = 0; i < psDInfo->nYSize * 2 + 8; i++) |
694 | 0 | nCheckSum += pabyRecord[i]; |
695 | |
|
696 | 0 | fileCheckSum = |
697 | 0 | ((unsigned)pabyRecord[8 + psDInfo->nYSize * 2 + 0] << 24) | |
698 | 0 | (pabyRecord[8 + psDInfo->nYSize * 2 + 1] << 16) | |
699 | 0 | (pabyRecord[8 + psDInfo->nYSize * 2 + 2] << 8) | |
700 | 0 | pabyRecord[8 + psDInfo->nYSize * 2 + 3]; |
701 | |
|
702 | 0 | if (fileCheckSum > 0xff * (8 + (unsigned int)psDInfo->nYSize * 2)) |
703 | 0 | { |
704 | 0 | static int bWarned = FALSE; |
705 | 0 | if (!bWarned) |
706 | 0 | { |
707 | 0 | bWarned = TRUE; |
708 | 0 | #ifndef AVOID_CPL |
709 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
710 | | #else |
711 | | fprintf(stderr, |
712 | | #endif |
713 | 0 | "The DTED driver has read from the file a checksum " |
714 | 0 | "with an impossible value (0x%X) at column %d.\n" |
715 | 0 | "Check with your file producer.\n" |
716 | 0 | "No more warnings will be issued in this session " |
717 | 0 | "about this operation.", |
718 | 0 | fileCheckSum, nColumnOffset); |
719 | 0 | } |
720 | 0 | } |
721 | 0 | else if (fileCheckSum != nCheckSum) |
722 | 0 | { |
723 | 0 | #ifndef AVOID_CPL |
724 | 0 | CPLError( |
725 | 0 | CE_Failure, CPLE_AppDefined, |
726 | | #else |
727 | | fprintf( |
728 | | stderr, |
729 | | #endif |
730 | 0 | "The DTED driver has found a computed and read checksum " |
731 | 0 | "that do not match at column %d. Computed 0x%X, read 0x%X\n", |
732 | 0 | nColumnOffset, nCheckSum, fileCheckSum); |
733 | 0 | CPLFree(pabyRecord); |
734 | 0 | return FALSE; |
735 | 0 | } |
736 | 0 | } |
737 | | |
738 | 1.85k | CPLFree(pabyRecord); |
739 | | |
740 | 1.85k | return TRUE; |
741 | 1.85k | } |
742 | | |
743 | | /************************************************************************/ |
744 | | /* DTEDWriteProfile() */ |
745 | | /************************************************************************/ |
746 | | |
747 | | int DTEDWriteProfile(DTEDInfo *psDInfo, int nColumnOffset, GInt16 *panData) |
748 | | |
749 | 0 | { |
750 | 0 | int nOffset; |
751 | 0 | int i, nCheckSum = 0; |
752 | 0 | GByte *pabyRecord; |
753 | |
|
754 | 0 | if (psDInfo->panMapLogicalColsToOffsets != NULL) |
755 | 0 | { |
756 | 0 | #ifndef AVOID_CPL |
757 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
758 | | #else |
759 | | fprintf(stderr, |
760 | | #endif |
761 | 0 | "Write to partial file not supported.\n"); |
762 | 0 | return FALSE; |
763 | 0 | } |
764 | | |
765 | | /* -------------------------------------------------------------------- */ |
766 | | /* Format the data record. */ |
767 | | /* -------------------------------------------------------------------- */ |
768 | 0 | pabyRecord = (GByte *)CPLMalloc(12 + psDInfo->nYSize * 2); |
769 | |
|
770 | 0 | for (i = 0; i < psDInfo->nYSize; i++) |
771 | 0 | { |
772 | 0 | int nABSVal = CPL_ABS(panData[psDInfo->nYSize - i - 1]); |
773 | 0 | pabyRecord[8 + i * 2] = (GByte)((nABSVal >> 8) & 0x7f); |
774 | 0 | pabyRecord[8 + i * 2 + 1] = (GByte)(nABSVal & 0xff); |
775 | |
|
776 | 0 | if (panData[psDInfo->nYSize - i - 1] < 0) |
777 | 0 | pabyRecord[8 + i * 2] |= 0x80; |
778 | 0 | } |
779 | |
|
780 | 0 | pabyRecord[0] = 0xaa; |
781 | 0 | pabyRecord[1] = 0; |
782 | 0 | pabyRecord[2] = (GByte)(nColumnOffset / 256); |
783 | 0 | pabyRecord[3] = (GByte)(nColumnOffset % 256); |
784 | 0 | pabyRecord[4] = (GByte)(nColumnOffset / 256); |
785 | 0 | pabyRecord[5] = (GByte)(nColumnOffset % 256); |
786 | 0 | pabyRecord[6] = 0; |
787 | 0 | pabyRecord[7] = 0; |
788 | | |
789 | | /* -------------------------------------------------------------------- */ |
790 | | /* Compute the checksum. */ |
791 | | /* -------------------------------------------------------------------- */ |
792 | 0 | for (i = 0; i < psDInfo->nYSize * 2 + 8; i++) |
793 | 0 | nCheckSum += pabyRecord[i]; |
794 | |
|
795 | 0 | pabyRecord[8 + psDInfo->nYSize * 2 + 0] = (GByte)((nCheckSum >> 24) & 0xff); |
796 | 0 | pabyRecord[8 + psDInfo->nYSize * 2 + 1] = (GByte)((nCheckSum >> 16) & 0xff); |
797 | 0 | pabyRecord[8 + psDInfo->nYSize * 2 + 2] = (GByte)((nCheckSum >> 8) & 0xff); |
798 | 0 | pabyRecord[8 + psDInfo->nYSize * 2 + 3] = (GByte)(nCheckSum & 0xff); |
799 | | |
800 | | /* -------------------------------------------------------------------- */ |
801 | | /* Write the record. */ |
802 | | /* -------------------------------------------------------------------- */ |
803 | 0 | nOffset = psDInfo->nDataOffset + nColumnOffset * (12 + psDInfo->nYSize * 2); |
804 | |
|
805 | 0 | if (VSIFSeekL(psDInfo->fp, nOffset, SEEK_SET) != 0 || |
806 | 0 | VSIFWriteL(pabyRecord, (12 + psDInfo->nYSize * 2), 1, psDInfo->fp) != 1) |
807 | 0 | { |
808 | 0 | #ifndef AVOID_CPL |
809 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
810 | | #else |
811 | | fprintf(stderr, |
812 | | #endif |
813 | 0 | "Failed to seek to, or write profile %d at offset %d\n" |
814 | 0 | "in DTED file.\n", |
815 | 0 | nColumnOffset, nOffset); |
816 | 0 | CPLFree(pabyRecord); |
817 | 0 | return FALSE; |
818 | 0 | } |
819 | | |
820 | 0 | CPLFree(pabyRecord); |
821 | |
|
822 | 0 | return TRUE; |
823 | 0 | } |
824 | | |
825 | | /************************************************************************/ |
826 | | /* DTEDGetMetadataLocation() */ |
827 | | /************************************************************************/ |
828 | | |
829 | | static void DTEDGetMetadataLocation(DTEDInfo *psDInfo, DTEDMetaDataCode eCode, |
830 | | char **ppszLocation, int *pnLength) |
831 | 1.30k | { |
832 | 1.30k | int bIsWeirdDTED = psDInfo->pachUHLRecord[4] == ' '; |
833 | | |
834 | 1.30k | switch (eCode) |
835 | 1.30k | { |
836 | 52 | case DTEDMD_ORIGINLONG: |
837 | 52 | if (bIsWeirdDTED) |
838 | 0 | *ppszLocation = psDInfo->pachUHLRecord + 8; |
839 | 52 | else |
840 | 52 | *ppszLocation = psDInfo->pachUHLRecord + 4; |
841 | 52 | *pnLength = 8; |
842 | 52 | break; |
843 | | |
844 | 52 | case DTEDMD_ORIGINLAT: |
845 | 52 | if (bIsWeirdDTED) |
846 | 0 | *ppszLocation = psDInfo->pachUHLRecord + 24; |
847 | 52 | else |
848 | 52 | *ppszLocation = psDInfo->pachUHLRecord + 12; |
849 | 52 | *pnLength = 8; |
850 | 52 | break; |
851 | | |
852 | 52 | case DTEDMD_VERTACCURACY_UHL: |
853 | 52 | if (bIsWeirdDTED) |
854 | 0 | *ppszLocation = psDInfo->pachUHLRecord + 56; |
855 | 52 | else |
856 | 52 | *ppszLocation = psDInfo->pachUHLRecord + 28; |
857 | 52 | *pnLength = 4; |
858 | 52 | break; |
859 | | |
860 | 52 | case DTEDMD_SECURITYCODE_UHL: |
861 | 52 | if (bIsWeirdDTED) |
862 | 0 | *ppszLocation = psDInfo->pachUHLRecord + 60; |
863 | 52 | else |
864 | 52 | *ppszLocation = psDInfo->pachUHLRecord + 32; |
865 | 52 | *pnLength = 3; |
866 | 52 | break; |
867 | | |
868 | 52 | case DTEDMD_UNIQUEREF_UHL: |
869 | 52 | if (bIsWeirdDTED) |
870 | 0 | *ppszLocation = NULL; |
871 | 52 | else |
872 | 52 | *ppszLocation = psDInfo->pachUHLRecord + 35; |
873 | 52 | *pnLength = 12; |
874 | 52 | break; |
875 | | |
876 | 52 | case DTEDMD_DATA_EDITION: |
877 | 52 | if (bIsWeirdDTED) |
878 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 174; |
879 | 52 | else |
880 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 87; |
881 | 52 | *pnLength = 2; |
882 | 52 | break; |
883 | | |
884 | 52 | case DTEDMD_MATCHMERGE_VERSION: |
885 | 52 | if (bIsWeirdDTED) |
886 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 176; |
887 | 52 | else |
888 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 89; |
889 | 52 | *pnLength = 1; |
890 | 52 | break; |
891 | | |
892 | 52 | case DTEDMD_MAINT_DATE: |
893 | 52 | if (bIsWeirdDTED) |
894 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 177; |
895 | 52 | else |
896 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 90; |
897 | 52 | *pnLength = 4; |
898 | 52 | break; |
899 | | |
900 | 52 | case DTEDMD_MATCHMERGE_DATE: |
901 | 52 | if (bIsWeirdDTED) |
902 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 181; |
903 | 52 | else |
904 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 94; |
905 | 52 | *pnLength = 4; |
906 | 52 | break; |
907 | | |
908 | 52 | case DTEDMD_MAINT_DESCRIPTION: |
909 | 52 | if (bIsWeirdDTED) |
910 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 185; |
911 | 52 | else |
912 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 98; |
913 | 52 | *pnLength = 4; |
914 | 52 | break; |
915 | | |
916 | 52 | case DTEDMD_PRODUCER: |
917 | 52 | if (bIsWeirdDTED) |
918 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 189; |
919 | 52 | else |
920 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 102; |
921 | 52 | *pnLength = 8; |
922 | 52 | break; |
923 | | |
924 | 52 | case DTEDMD_VERTDATUM: |
925 | 52 | if (bIsWeirdDTED) |
926 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 267; |
927 | 52 | else |
928 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 141; |
929 | 52 | *pnLength = 3; |
930 | 52 | break; |
931 | | |
932 | 52 | case DTEDMD_HORIZDATUM: |
933 | 52 | if (bIsWeirdDTED) |
934 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 270; |
935 | 52 | else |
936 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 144; |
937 | 52 | *pnLength = 5; |
938 | 52 | break; |
939 | | |
940 | 52 | case DTEDMD_DIGITIZING_SYS: |
941 | 52 | if (bIsWeirdDTED) |
942 | 0 | *ppszLocation = NULL; |
943 | 52 | else |
944 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 149; |
945 | 52 | *pnLength = 10; |
946 | 52 | break; |
947 | | |
948 | 52 | case DTEDMD_COMPILATION_DATE: |
949 | 52 | if (bIsWeirdDTED) |
950 | 0 | *ppszLocation = NULL; |
951 | 52 | else |
952 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 159; |
953 | 52 | *pnLength = 4; |
954 | 52 | break; |
955 | | |
956 | 52 | case DTEDMD_HORIZACCURACY: |
957 | 52 | *ppszLocation = psDInfo->pachACCRecord + 3; |
958 | 52 | *pnLength = 4; |
959 | 52 | break; |
960 | | |
961 | 52 | case DTEDMD_REL_HORIZACCURACY: |
962 | 52 | *ppszLocation = psDInfo->pachACCRecord + 11; |
963 | 52 | *pnLength = 4; |
964 | 52 | break; |
965 | | |
966 | 52 | case DTEDMD_REL_VERTACCURACY: |
967 | 52 | *ppszLocation = psDInfo->pachACCRecord + 15; |
968 | 52 | *pnLength = 4; |
969 | 52 | break; |
970 | | |
971 | 52 | case DTEDMD_VERTACCURACY_ACC: |
972 | 52 | *ppszLocation = psDInfo->pachACCRecord + 7; |
973 | 52 | *pnLength = 4; |
974 | 52 | break; |
975 | | |
976 | 52 | case DTEDMD_SECURITYCODE_DSI: |
977 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 3; |
978 | 52 | *pnLength = 1; |
979 | 52 | break; |
980 | | |
981 | 52 | case DTEDMD_UNIQUEREF_DSI: |
982 | 52 | if (bIsWeirdDTED) |
983 | 0 | *ppszLocation = NULL; |
984 | 52 | else |
985 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 64; |
986 | 52 | *pnLength = 15; |
987 | 52 | break; |
988 | | |
989 | 52 | case DTEDMD_NIMA_DESIGNATOR: |
990 | 52 | if (bIsWeirdDTED) |
991 | 0 | *ppszLocation = psDInfo->pachDSIRecord + 118; |
992 | 52 | else |
993 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 59; |
994 | 52 | *pnLength = 5; |
995 | 52 | break; |
996 | | |
997 | 52 | case DTEDMD_PARTIALCELL_DSI: |
998 | 52 | if (bIsWeirdDTED) |
999 | 0 | *ppszLocation = NULL; |
1000 | 52 | else |
1001 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 289; |
1002 | 52 | *pnLength = 2; |
1003 | 52 | break; |
1004 | | |
1005 | 52 | case DTEDMD_SECURITYCONTROL: |
1006 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 4; |
1007 | 52 | *pnLength = 2; |
1008 | 52 | break; |
1009 | | |
1010 | 52 | case DTEDMD_SECURITYHANDLING: |
1011 | 52 | *ppszLocation = psDInfo->pachDSIRecord + 6; |
1012 | 52 | *pnLength = 27; |
1013 | 52 | break; |
1014 | | |
1015 | 0 | default: |
1016 | 0 | *ppszLocation = NULL; |
1017 | 0 | *pnLength = 0; |
1018 | 1.30k | } |
1019 | 1.30k | } |
1020 | | |
1021 | | /************************************************************************/ |
1022 | | /* DTEDGetMetadata() */ |
1023 | | /************************************************************************/ |
1024 | | |
1025 | | char *DTEDGetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode) |
1026 | | |
1027 | 1.30k | { |
1028 | 1.30k | int nFieldLen; |
1029 | 1.30k | char *pszFieldSrc; |
1030 | 1.30k | char *pszResult; |
1031 | | |
1032 | 1.30k | DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen); |
1033 | 1.30k | if (pszFieldSrc == NULL) |
1034 | 0 | return CPLStrdup(""); |
1035 | | |
1036 | 1.30k | pszResult = (char *)CPLMalloc(nFieldLen + 1); |
1037 | 1.30k | strncpy(pszResult, pszFieldSrc, nFieldLen); |
1038 | 1.30k | pszResult[nFieldLen] = '\0'; |
1039 | | |
1040 | 1.30k | return pszResult; |
1041 | 1.30k | } |
1042 | | |
1043 | | /************************************************************************/ |
1044 | | /* DTEDSetMetadata() */ |
1045 | | /************************************************************************/ |
1046 | | |
1047 | | int DTEDSetMetadata(DTEDInfo *psDInfo, DTEDMetaDataCode eCode, |
1048 | | const char *pszNewValue) |
1049 | | |
1050 | 0 | { |
1051 | 0 | int nFieldLen; |
1052 | 0 | char *pszFieldSrc; |
1053 | 0 | size_t nLenToCopy; |
1054 | |
|
1055 | 0 | if (!psDInfo->bUpdate) |
1056 | 0 | return FALSE; |
1057 | | |
1058 | | /* -------------------------------------------------------------------- */ |
1059 | | /* Get the location in the headers to update. */ |
1060 | | /* -------------------------------------------------------------------- */ |
1061 | 0 | DTEDGetMetadataLocation(psDInfo, eCode, &pszFieldSrc, &nFieldLen); |
1062 | 0 | if (pszFieldSrc == NULL) |
1063 | 0 | return FALSE; |
1064 | | |
1065 | | /* -------------------------------------------------------------------- */ |
1066 | | /* Update it, padding with spaces. */ |
1067 | | /* -------------------------------------------------------------------- */ |
1068 | 0 | nLenToCopy = CPL_MIN((size_t)nFieldLen, strlen(pszNewValue)); |
1069 | 0 | memcpy(pszFieldSrc, pszNewValue, nLenToCopy); |
1070 | 0 | if (nLenToCopy < (size_t)nFieldLen) |
1071 | 0 | memset(pszFieldSrc + nLenToCopy, ' ', nFieldLen - nLenToCopy); |
1072 | | |
1073 | | /* Turn the flag on, so that the headers are rewritten at file */ |
1074 | | /* closing */ |
1075 | 0 | psDInfo->bRewriteHeaders = TRUE; |
1076 | |
|
1077 | 0 | return TRUE; |
1078 | 0 | } |
1079 | | |
1080 | | /************************************************************************/ |
1081 | | /* DTEDClose() */ |
1082 | | /************************************************************************/ |
1083 | | |
1084 | | void DTEDClose(DTEDInfo *psDInfo) |
1085 | | |
1086 | 54 | { |
1087 | 54 | if (psDInfo->bRewriteHeaders) |
1088 | 0 | { |
1089 | | /* -------------------------------------------------------------------- |
1090 | | */ |
1091 | | /* Write all headers back to disk. */ |
1092 | | /* -------------------------------------------------------------------- |
1093 | | */ |
1094 | 0 | CPL_IGNORE_RET_VAL_INT( |
1095 | 0 | VSIFSeekL(psDInfo->fp, psDInfo->nUHLOffset, SEEK_SET)); |
1096 | 0 | CPL_IGNORE_RET_VAL_SIZET( |
1097 | 0 | VSIFWriteL(psDInfo->pachUHLRecord, 1, DTED_UHL_SIZE, psDInfo->fp)); |
1098 | |
|
1099 | 0 | CPL_IGNORE_RET_VAL_INT( |
1100 | 0 | VSIFSeekL(psDInfo->fp, psDInfo->nDSIOffset, SEEK_SET)); |
1101 | 0 | CPL_IGNORE_RET_VAL_SIZET( |
1102 | 0 | VSIFWriteL(psDInfo->pachDSIRecord, 1, DTED_DSI_SIZE, psDInfo->fp)); |
1103 | |
|
1104 | 0 | CPL_IGNORE_RET_VAL_INT( |
1105 | 0 | VSIFSeekL(psDInfo->fp, psDInfo->nACCOffset, SEEK_SET)); |
1106 | 0 | CPL_IGNORE_RET_VAL_SIZET( |
1107 | 0 | VSIFWriteL(psDInfo->pachACCRecord, 1, DTED_ACC_SIZE, psDInfo->fp)); |
1108 | 0 | } |
1109 | | |
1110 | 54 | CPL_IGNORE_RET_VAL_INT(VSIFCloseL(psDInfo->fp)); |
1111 | | |
1112 | 54 | CPLFree(psDInfo->pachUHLRecord); |
1113 | 54 | CPLFree(psDInfo->pachDSIRecord); |
1114 | 54 | CPLFree(psDInfo->pachACCRecord); |
1115 | | |
1116 | 54 | CPLFree(psDInfo->panMapLogicalColsToOffsets); |
1117 | | |
1118 | 54 | CPLFree(psDInfo); |
1119 | 54 | } |