Coverage Report

Created: 2026-11-12 08:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/dted/dted_create.c
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  DTED Translator
4
 * Purpose:  Implementation of DTEDCreate() portion of DTED API.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2001, Frank Warmerdam
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "dted_api.h"
14
#include <assert.h>
15
16
0
#define DTED_ABS_VERT_ACC "NA  "
17
0
#define DTED_SECURITY "U"
18
0
#define DTED_EDITION 1
19
20
/************************************************************************/
21
/*                           DTEDFormatDMS()                            */
22
/************************************************************************/
23
24
static void DTEDFormatDMS(unsigned char *achField, size_t nTargetLenSize,
25
                          size_t nOffset, double dfAngle,
26
                          const char *pszLatLong, const char *pszFormat)
27
28
0
{
29
0
    char chHemisphere;
30
0
    int nDegrees, nMinutes, nSeconds;
31
0
    double dfRemainder;
32
33
0
    if (pszFormat == NULL)
34
0
        pszFormat = "%03d%02d%02d%c";
35
36
0
    assert(EQUAL(pszLatLong, "LAT") || EQUAL(pszLatLong, "LONG"));
37
38
0
    if (EQUAL(pszLatLong, "LAT"))
39
0
    {
40
0
        if (dfAngle < 0.0)
41
0
            chHemisphere = 'S';
42
0
        else
43
0
            chHemisphere = 'N';
44
0
    }
45
0
    else
46
0
    {
47
0
        if (dfAngle < 0.0)
48
0
            chHemisphere = 'W';
49
0
        else
50
0
            chHemisphere = 'E';
51
0
    }
52
53
0
    dfAngle = CPL_ABS(dfAngle);
54
55
0
    nDegrees = (int)floor(dfAngle + 0.5 / 3600.0);
56
0
    dfRemainder = dfAngle - nDegrees;
57
0
    nMinutes = (int)floor(dfRemainder * 60.0 + 0.5 / 60.0);
58
0
    dfRemainder = dfRemainder - nMinutes / 60.0;
59
0
    nSeconds = (int)floor(dfRemainder * 3600.0 + 0.5);
60
61
0
    snprintf((char *)achField + nOffset, nTargetLenSize - nOffset, pszFormat,
62
0
             nDegrees, nMinutes, nSeconds, chHemisphere);
63
0
}
64
65
/************************************************************************/
66
/*                             DTEDFormat()                             */
67
/************************************************************************/
68
69
static void DTEDFormat(unsigned char *pszTarget, size_t nTargetLenSize,
70
                       size_t nOffset, const char *pszFormat, ...)
71
    CPL_PRINT_FUNC_FORMAT(4, 5);
72
73
static void DTEDFormat(unsigned char *pszTarget, size_t nTargetLenSize,
74
                       size_t nOffset, const char *pszFormat, ...)
75
76
0
{
77
0
    va_list args;
78
79
0
    va_start(args, pszFormat);
80
0
    CPLvsnprintf((char *)pszTarget + nOffset, nTargetLenSize - nOffset,
81
0
                 pszFormat, args);
82
0
    va_end(args);
83
0
}
84
85
/************************************************************************/
86
/*                             DTEDCreate()                             */
87
/************************************************************************/
88
89
const char *DTEDCreate(const char *pszFilename, int nLevel, int nLLOriginLat,
90
                       int nLLOriginLong)
91
92
0
{
93
0
    VSILFILE *fp;
94
0
    unsigned char achRecord[3601 * 2 + 12];
95
0
    int nXSize, nYSize, nReferenceLat, iProfile;
96
97
    /* -------------------------------------------------------------------- */
98
    /*      Establish resolution.                                           */
99
    /* -------------------------------------------------------------------- */
100
0
    if (nLevel == 0)
101
0
    {
102
0
        nXSize = 121;
103
0
        nYSize = 121;
104
0
    }
105
0
    else if (nLevel == 1)
106
0
    {
107
0
        nXSize = 1201;
108
0
        nYSize = 1201;
109
0
    }
110
0
    else if (nLevel == 2)
111
0
    {
112
0
        nXSize = 3601;
113
0
        nYSize = 3601;
114
0
    }
115
0
    else
116
0
    {
117
0
        return CPLSPrintf("Illegal DTED Level value %d, only 0-2 allowed.",
118
0
                          nLevel);
119
0
    }
120
121
0
    nReferenceLat = nLLOriginLat < 0 ? -(nLLOriginLat + 1) : nLLOriginLat;
122
123
0
    if (nReferenceLat >= 80)
124
0
        nXSize = (nXSize - 1) / 6 + 1;
125
0
    else if (nReferenceLat >= 75)
126
0
        nXSize = (nXSize - 1) / 4 + 1;
127
0
    else if (nReferenceLat >= 70)
128
0
        nXSize = (nXSize - 1) / 3 + 1;
129
0
    else if (nReferenceLat >= 50)
130
0
        nXSize = (nXSize - 1) / 2 + 1;
131
132
    /* -------------------------------------------------------------------- */
133
    /*      Open the file.                                                  */
134
    /* -------------------------------------------------------------------- */
135
0
    fp = VSIFOpenL(pszFilename, "wb");
136
137
0
    if (fp == NULL)
138
0
    {
139
0
        return CPLSPrintf("Unable to create file `%s'.", pszFilename);
140
0
    }
141
142
    /* -------------------------------------------------------------------- */
143
    /*      Format and write the UHL record.                                */
144
    /* -------------------------------------------------------------------- */
145
0
    memset(achRecord, ' ', DTED_UHL_SIZE);
146
147
0
    DTEDFormat(achRecord, sizeof(achRecord), 0, "UHL1");
148
149
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 4, nLLOriginLong, "LONG", NULL);
150
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 12, nLLOriginLat, "LAT", NULL);
151
152
0
    DTEDFormat(achRecord, sizeof(achRecord), 20, "%04d",
153
0
               (3600 / (nXSize - 1)) * 10);
154
0
    DTEDFormat(achRecord, sizeof(achRecord), 24, "%04d",
155
0
               (3600 / (nYSize - 1)) * 10);
156
157
0
    DTEDFormat(achRecord, sizeof(achRecord), 28, "%4s", DTED_ABS_VERT_ACC);
158
0
    DTEDFormat(achRecord, sizeof(achRecord), 32, "%-3s", DTED_SECURITY);
159
0
    DTEDFormat(achRecord, sizeof(achRecord), 47, "%04d", nXSize);
160
0
    DTEDFormat(achRecord, sizeof(achRecord), 51, "%04d", nYSize);
161
0
    DTEDFormat(achRecord, sizeof(achRecord), 55, "%c", '0');
162
163
0
    if (VSIFWriteL(achRecord, DTED_UHL_SIZE, 1, fp) != 1)
164
0
        return "UHL record write failed.";
165
166
    /* -------------------------------------------------------------------- */
167
    /*      Format and write the DSI record.                                */
168
    /* -------------------------------------------------------------------- */
169
0
    memset(achRecord, ' ', DTED_DSI_SIZE);
170
171
0
    DTEDFormat(achRecord, sizeof(achRecord), 0, "DSI");
172
0
    DTEDFormat(achRecord, sizeof(achRecord), 3, "%1s", DTED_SECURITY);
173
174
0
    DTEDFormat(achRecord, sizeof(achRecord), 59, "DTED%d", nLevel);
175
0
    DTEDFormat(achRecord, sizeof(achRecord), 64, "%015d", 0);
176
0
    DTEDFormat(achRecord, sizeof(achRecord), 87, "%02d", DTED_EDITION);
177
0
    DTEDFormat(achRecord, sizeof(achRecord), 89, "%c", 'A');
178
0
    DTEDFormat(achRecord, sizeof(achRecord), 90, "%04d", 0);
179
0
    DTEDFormat(achRecord, sizeof(achRecord), 94, "%04d", 0);
180
0
    DTEDFormat(achRecord, sizeof(achRecord), 98, "%04d", 0);
181
0
    DTEDFormat(achRecord, sizeof(achRecord), 126, "PRF89020B");
182
0
    DTEDFormat(achRecord, sizeof(achRecord), 135, "00");
183
0
    DTEDFormat(achRecord, sizeof(achRecord), 137, "0005");
184
0
    DTEDFormat(achRecord, sizeof(achRecord), 141, "MSL");
185
0
    DTEDFormat(achRecord, sizeof(achRecord), 144, "WGS84");
186
187
    /* origin */
188
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 185, nLLOriginLat, "LAT",
189
0
                  "%02d%02d%02d.0%c");
190
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 194, nLLOriginLong, "LONG",
191
0
                  "%03d%02d%02d.0%c");
192
193
    /* SW */
194
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 204, nLLOriginLat, "LAT",
195
0
                  "%02d%02d%02d%c");
196
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 211, nLLOriginLong, "LONG",
197
0
                  NULL);
198
199
    /* NW */
200
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 219, nLLOriginLat + 1, "LAT",
201
0
                  "%02d%02d%02d%c");
202
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 226, nLLOriginLong, "LONG",
203
0
                  NULL);
204
205
    /* NE */
206
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 234, nLLOriginLat + 1, "LAT",
207
0
                  "%02d%02d%02d%c");
208
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 241, nLLOriginLong + 1, "LONG",
209
0
                  NULL);
210
211
    /* SE */
212
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 249, nLLOriginLat, "LAT",
213
0
                  "%02d%02d%02d%c");
214
0
    DTEDFormatDMS(achRecord, sizeof(achRecord), 256, nLLOriginLong + 1, "LONG",
215
0
                  NULL);
216
217
0
    DTEDFormat(achRecord, sizeof(achRecord), 264, "0000000.0");
218
0
    DTEDFormat(achRecord, sizeof(achRecord), 264, "0000000.0");
219
220
0
    DTEDFormat(achRecord, sizeof(achRecord), 273, "%04d",
221
0
               (3600 / (nYSize - 1)) * 10);
222
0
    DTEDFormat(achRecord, sizeof(achRecord), 277, "%04d",
223
0
               (3600 / (nXSize - 1)) * 10);
224
225
0
    DTEDFormat(achRecord, sizeof(achRecord), 281, "%04d", nYSize);
226
0
    DTEDFormat(achRecord, sizeof(achRecord), 285, "%04d", nXSize);
227
0
    DTEDFormat(achRecord, sizeof(achRecord), 289, "%02d", 0);
228
229
0
    if (VSIFWriteL(achRecord, DTED_DSI_SIZE, 1, fp) != 1)
230
0
        return "DSI record write failed.";
231
232
    /* -------------------------------------------------------------------- */
233
    /*      Create and write ACC record.                                    */
234
    /* -------------------------------------------------------------------- */
235
0
    memset(achRecord, ' ', DTED_ACC_SIZE);
236
237
0
    DTEDFormat(achRecord, sizeof(achRecord), 0, "ACC");
238
239
0
    DTEDFormat(achRecord, sizeof(achRecord), 3, "NA");
240
0
    DTEDFormat(achRecord, sizeof(achRecord), 7, "NA");
241
0
    DTEDFormat(achRecord, sizeof(achRecord), 11, "NA");
242
0
    DTEDFormat(achRecord, sizeof(achRecord), 15, "NA");
243
244
0
    DTEDFormat(achRecord, sizeof(achRecord), 55, "00");
245
246
0
    if (VSIFWriteL(achRecord, DTED_ACC_SIZE, 1, fp) != 1)
247
0
        return "ACC record write failed.";
248
249
    /* -------------------------------------------------------------------- */
250
    /*      Write blank template profile data records.                      */
251
    /* -------------------------------------------------------------------- */
252
0
    memset(achRecord, 0, nYSize * 2 + 12);
253
0
    memset(achRecord + 8, 0xff, nYSize * 2);
254
255
0
    achRecord[0] = 0252;
256
257
0
    for (iProfile = 0; iProfile < nXSize; iProfile++)
258
0
    {
259
0
        achRecord[1] = 0;
260
0
        achRecord[2] = (GByte)(iProfile / 256);
261
0
        achRecord[3] = (GByte)(iProfile % 256);
262
263
0
        achRecord[4] = (GByte)(iProfile / 256);
264
0
        achRecord[5] = (GByte)(iProfile % 256);
265
266
0
        if (VSIFWriteL(achRecord, nYSize * 2 + 12, 1, fp) != 1)
267
0
            return "Data record write failed.";
268
0
    }
269
270
0
    if (VSIFCloseL(fp) != 0)
271
0
        return "I/O error";
272
273
0
    return NULL;
274
0
}