Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  WAsP Translator
4
 * Purpose:  Implements OGRWAsPDataSource class
5
 * Author:   Vincent Mora, vincent dot mora at oslandia dot com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Oslandia <info at oslandia dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "ogrwasp.h"
14
#include "cpl_conv.h"
15
#include "cpl_string.h"
16
17
#include <cassert>
18
#include <sstream>
19
20
/************************************************************************/
21
/*                         OGRWAsPDataSource()                          */
22
/************************************************************************/
23
24
OGRWAsPDataSource::OGRWAsPDataSource(const char *pszName, VSILFILE *hFileHandle)
25
14.7k
    : sFilename(pszName), hFile(hFileHandle)
26
14.7k
{
27
14.7k
}
28
29
/************************************************************************/
30
/*                         ~OGRWAsPDataSource()                         */
31
/************************************************************************/
32
33
OGRWAsPDataSource::~OGRWAsPDataSource()
34
35
14.7k
{
36
14.7k
    oLayer.reset();    /* we write to file int layer dtor */
37
14.7k
    VSIFCloseL(hFile); /* nothing smart can be done here in case of error */
38
14.7k
}
39
40
/************************************************************************/
41
/*                           TestCapability()                           */
42
/************************************************************************/
43
44
int OGRWAsPDataSource::TestCapability(const char *pszCap) const
45
46
0
{
47
0
    if (EQUAL(pszCap, ODsCCreateLayer) && oLayer.get() == nullptr)
48
0
        return true;
49
0
    else if (EQUAL(pszCap, ODsCZGeometries))
50
0
        return true;
51
52
0
    return false;
53
0
}
54
55
/************************************************************************/
56
/*                           GetLayerByName()                           */
57
/************************************************************************/
58
59
OGRLayer *OGRWAsPDataSource::GetLayerByName(const char *pszName)
60
61
0
{
62
0
    return (oLayer.get() && EQUAL(pszName, oLayer->GetName())) ? oLayer.get()
63
0
                                                               : nullptr;
64
0
}
65
66
/************************************************************************/
67
/*                                Load()                                */
68
/************************************************************************/
69
70
OGRErr OGRWAsPDataSource::Load(bool bSilent)
71
72
14.7k
{
73
    /* if we don't have a layer, we read from file */
74
14.7k
    if (oLayer.get())
75
0
    {
76
0
        if (!bSilent)
77
0
            CPLError(CE_Failure, CPLE_NotSupported, "layer already loaded");
78
0
        return OGRERR_FAILURE;
79
0
    }
80
    /* Parse the first line of the file in case it is a spatial ref*/
81
14.7k
    const char *pszLine = CPLReadLine2L(hFile, 1024, nullptr);
82
14.7k
    if (!pszLine)
83
80
    {
84
80
        if (!bSilent)
85
0
            CPLError(CE_Failure, CPLE_FileIO, "empty file");
86
80
        return OGRERR_FAILURE;
87
80
    }
88
14.6k
    CPLString sLine(pszLine);
89
14.6k
    sLine = sLine.substr(0, sLine.find("|"));
90
14.6k
    OGRSpatialReference *poSpatialRef = new OGRSpatialReference;
91
14.6k
    poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
92
14.6k
    if (poSpatialRef->importFromProj4(sLine.c_str()) != OGRERR_NONE)
93
11.0k
    {
94
11.0k
        if (!bSilent)
95
0
            CPLError(CE_Warning, CPLE_FileIO, "cannot find spatial reference");
96
11.0k
        delete poSpatialRef;
97
11.0k
        poSpatialRef = nullptr;
98
11.0k
    }
99
100
    /* TODO Parse those line since they define a coordinate transformation */
101
14.6k
    CPLReadLineL(hFile);
102
14.6k
    CPLReadLineL(hFile);
103
14.6k
    CPLReadLineL(hFile);
104
105
14.6k
    oLayer.reset(new OGRWAsPLayer(this,
106
14.6k
                                  CPLGetBasenameSafe(sFilename.c_str()).c_str(),
107
14.6k
                                  hFile, poSpatialRef));
108
14.6k
    if (poSpatialRef)
109
3.62k
        poSpatialRef->Release();
110
111
14.6k
    const vsi_l_offset iOffset = VSIFTellL(hFile);
112
14.6k
    pszLine = CPLReadLineL(hFile);
113
14.6k
    if (!pszLine)
114
14.0k
    {
115
14.0k
        if (!bSilent)
116
0
            CPLError(CE_Failure, CPLE_FileIO, "no feature in file");
117
14.0k
        oLayer.reset();
118
14.0k
        return OGRERR_FAILURE;
119
14.0k
    }
120
121
540
    double dfValues[4] = {0};
122
540
    int iNumValues = 0;
123
540
    {
124
540
        std::istringstream iss(pszLine);
125
997
        while (iNumValues < 4 && (iss >> dfValues[iNumValues]))
126
457
        {
127
457
            ++iNumValues;
128
457
        }
129
130
540
        if (iNumValues < 2)
131
361
        {
132
361
            if (!bSilent && iNumValues)
133
0
                CPLError(CE_Failure, CPLE_FileIO, "no enough values");
134
361
            else if (!bSilent)
135
0
                CPLError(CE_Failure, CPLE_FileIO, "no feature in file");
136
137
361
            oLayer.reset();
138
361
            return OGRERR_FAILURE;
139
361
        }
140
540
    }
141
142
179
    if (iNumValues == 3 || iNumValues == 4)
143
51
    {
144
51
        OGRFieldDefn left("z_left", OFTReal);
145
51
        OGRFieldDefn right("z_right", OFTReal);
146
51
        oLayer->CreateField(&left);
147
51
        oLayer->CreateField(&right);
148
51
    }
149
179
    if (iNumValues == 2 || iNumValues == 4)
150
164
    {
151
164
        OGRFieldDefn height("elevation", OFTReal);
152
164
        oLayer->CreateField(&height);
153
164
    }
154
155
179
    VSIFSeekL(hFile, iOffset, SEEK_SET);
156
179
    return OGRERR_NONE;
157
540
}
158
159
/************************************************************************/
160
/*                              GetLayer()                              */
161
/************************************************************************/
162
163
const OGRLayer *OGRWAsPDataSource::GetLayer(int iLayer) const
164
165
177
{
166
177
    return (iLayer == 0) ? oLayer.get() : nullptr;
167
177
}
168
169
/************************************************************************/
170
/*                            ICreateLayer()                            */
171
/************************************************************************/
172
173
OGRLayer *
174
OGRWAsPDataSource::ICreateLayer(const char *pszName,
175
                                const OGRGeomFieldDefn *poGeomFieldDefn,
176
                                CSLConstList papszOptions)
177
178
0
{
179
0
    const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
180
0
    const auto poSpatialRef =
181
0
        poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
182
183
0
    if (eGType != wkbLineString && eGType != wkbLineString25D &&
184
0
        eGType != wkbMultiLineString && eGType != wkbMultiLineString25D &&
185
0
        eGType != wkbPolygon && eGType != wkbPolygon25D &&
186
0
        eGType != wkbMultiPolygon && eGType != wkbMultiPolygon25D)
187
0
    {
188
0
        CPLError(CE_Failure, CPLE_NotSupported, "unsupported geometry type %s",
189
0
                 OGRGeometryTypeToName(eGType));
190
0
        return nullptr;
191
0
    }
192
193
0
    if (!OGRGeometryFactory::haveGEOS() &&
194
0
        (eGType == wkbPolygon || eGType == wkbPolygon25D ||
195
0
         eGType == wkbMultiPolygon || eGType == wkbMultiPolygon25D))
196
0
    {
197
0
        CPLError(CE_Failure, CPLE_NotSupported,
198
0
                 "unsupported geometry type %s without GEOS support",
199
0
                 OGRGeometryTypeToName(eGType));
200
0
        return nullptr;
201
0
    }
202
203
0
    if (oLayer.get())
204
0
    {
205
0
        CPLError(CE_Failure, CPLE_NotSupported,
206
0
                 "this data source does not support more than one layer");
207
0
        return nullptr;
208
0
    }
209
210
0
    CPLString sFirstField, sSecondField, sGeomField;
211
212
0
    const char *pszFields = CSLFetchNameValue(papszOptions, "WASP_FIELDS");
213
0
    CPLString sFields(pszFields ? pszFields : "");
214
0
    if (!sFields.empty())
215
0
    {
216
        /* parse the comma separated list of fields */
217
0
        const size_t iComma = sFields.find(',');
218
0
        if (std::string::npos != iComma)
219
0
        {
220
0
            sFirstField = sFields.substr(0, iComma);
221
0
            sSecondField = sFields.substr(iComma + 1);
222
0
        }
223
0
        else
224
0
        {
225
0
            sFirstField = std::move(sFields);
226
0
        }
227
0
    }
228
229
0
    const char *pszGeomField =
230
0
        CSLFetchNameValue(papszOptions, "WASP_GEOM_FIELD");
231
0
    sGeomField = CPLString(pszGeomField ? pszGeomField : "");
232
233
0
    const bool bMerge =
234
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "WASP_MERGE", "YES"));
235
236
0
    std::unique_ptr<double> pdfTolerance;
237
0
    {
238
0
        const char *pszToler =
239
0
            CSLFetchNameValue(papszOptions, "WASP_TOLERANCE");
240
241
0
        if (pszToler)
242
0
        {
243
0
            if (!OGRGeometryFactory::haveGEOS())
244
0
            {
245
0
                CPLError(
246
0
                    CE_Warning, CPLE_IllegalArg,
247
0
                    "GEOS support not enabled, ignoring option WASP_TOLERANCE");
248
0
            }
249
0
            else
250
0
            {
251
0
                pdfTolerance.reset(new double);
252
0
                if (!(std::istringstream(pszToler) >> *pdfTolerance))
253
0
                {
254
0
                    CPLError(CE_Failure, CPLE_IllegalArg,
255
0
                             "cannot set tolerance from %s", pszToler);
256
0
                    return nullptr;
257
0
                }
258
0
            }
259
0
        }
260
0
    }
261
262
0
    std::unique_ptr<double> pdfAdjacentPointTolerance;
263
0
    {
264
0
        const char *pszAdjToler =
265
0
            CSLFetchNameValue(papszOptions, "WASP_ADJ_TOLER");
266
0
        if (pszAdjToler)
267
0
        {
268
0
            pdfAdjacentPointTolerance.reset(new double);
269
0
            if (!(std::istringstream(pszAdjToler) >>
270
0
                  *pdfAdjacentPointTolerance))
271
0
            {
272
0
                CPLError(CE_Failure, CPLE_IllegalArg,
273
0
                         "cannot set tolerance from %s", pszAdjToler);
274
0
                return nullptr;
275
0
            }
276
0
        }
277
0
    }
278
279
0
    std::unique_ptr<double> pdfPointToCircleRadius;
280
0
    {
281
0
        const char *pszPtToCircRad =
282
0
            CSLFetchNameValue(papszOptions, "WASP_POINT_TO_CIRCLE_RADIUS");
283
0
        if (pszPtToCircRad)
284
0
        {
285
0
            pdfPointToCircleRadius.reset(new double);
286
0
            if (!(std::istringstream(pszPtToCircRad) >>
287
0
                  *pdfPointToCircleRadius))
288
0
            {
289
0
                CPLError(CE_Failure, CPLE_IllegalArg,
290
0
                         "cannot set tolerance from %s", pszPtToCircRad);
291
0
                return nullptr;
292
0
            }
293
0
        }
294
0
    }
295
296
0
    OGRSpatialReference *poSRSClone = nullptr;
297
0
    if (poSpatialRef)
298
0
    {
299
0
        poSRSClone = poSpatialRef->Clone();
300
0
        poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
301
0
    }
302
0
    oLayer.reset(new OGRWAsPLayer(
303
0
        this, CPLGetBasenameSafe(pszName).c_str(), hFile, poSRSClone,
304
0
        sFirstField, sSecondField, sGeomField, bMerge, pdfTolerance.release(),
305
0
        pdfAdjacentPointTolerance.release(), pdfPointToCircleRadius.release()));
306
0
    if (poSRSClone)
307
0
        poSRSClone->Release();
308
309
0
    char *ppszWktSpatialRef = nullptr;
310
0
    if (poSpatialRef &&
311
0
        poSpatialRef->exportToProj4(&ppszWktSpatialRef) == OGRERR_NONE)
312
0
    {
313
0
        VSIFPrintfL(hFile, "%s\n", ppszWktSpatialRef);
314
0
    }
315
0
    else
316
0
    {
317
0
        VSIFPrintfL(hFile, "no spatial ref sys\n");
318
0
    }
319
0
    CPLFree(ppszWktSpatialRef);
320
321
0
    VSIFPrintfL(hFile, "  0.0 0.0 0.0 0.0\n");
322
0
    VSIFPrintfL(hFile, "  1.0 0.0 1.0 0.0\n");
323
0
    VSIFPrintfL(hFile, "  1.0 0.0\n");
324
0
    return oLayer.get();
325
0
}