• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 17382915019

01 Sep 2025 04:24PM UTC coverage: 70.88% (-0.001%) from 70.881%
17382915019

push

github

web-flow
Merge pull request #13008 from OSGeo/backport-12991-to-release/3.11

[Backport release/3.11] gdalwarp: fix error when reprojecting large raster (such as WMTS with global extent)

7 of 10 new or added lines in 1 file covered. (70.0%)

83 existing lines in 37 files now uncovered.

567659 of 800875 relevant lines covered (70.88%)

235914.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.96
/ogr/ograpispy.cpp
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  OGR C API "Spy"
5
 * Author:   Even Rouault, even.rouault at spatialys.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "cpl_port.h"
14
#include "cpl_multiproc.h"
15
#include "ograpispy.h"
16

17
#include <cassert>
18
#include <cstdio>
19
#include <map>
20
#include <set>
21

22
#include "cpl_string.h"
23
#include "gdal.h"
24
#include "ogr_geometry.h"
25
#include "ogr_feature.h"
26
#include "ogr_spatialref.h"
27
#include "ogrsf_frmts.h"
28

29
#ifdef OGRAPISPY_ENABLED
30

31
int bOGRAPISpyEnabled = FALSE;
32
static CPLMutex *hOGRAPISpyMutex = nullptr;
33
static CPLString osSnapshotPath;
34
static CPLString osSpyFile;
35
static FILE *fpSpyFile = nullptr;
36

37
// Keep in sync with cpl_conv.cpp
38
void OGRAPISPYCPLSetConfigOption(const char *, const char *);
39
void OGRAPISPYCPLSetThreadLocalConfigOption(const char *, const char *);
40

41
namespace
42
{
43

44
class LayerDescription
45
{
46
  public:
47
    int iLayer = -1;
48

49
    LayerDescription() = default;
13✔
50

51
    explicit LayerDescription(int iLayerIn) : iLayer(iLayerIn)
13✔
52
    {
53
    }
13✔
54
};
55

56
class DatasetDescription
9✔
57
{
58
  public:
59
    int iDS = -1;
60
    std::map<OGRLayerH, LayerDescription> oMapLayer{};
61

62
    DatasetDescription() = default;
9✔
63

64
    explicit DatasetDescription(int iDSIn) : iDS(iDSIn)
9✔
65
    {
66
    }
9✔
67

68
    DatasetDescription &operator=(DatasetDescription &&) = default;
69
    ~DatasetDescription();
70
};
71

72
class FeatureDefnDescription
7✔
73
{
74
  public:
75
    OGRFeatureDefnH hFDefn = nullptr;
76
    int iUniqueNumber = -1;
77
    std::map<OGRFieldDefnH, int> oMapFieldDefn{};
78
    std::map<OGRGeomFieldDefnH, int> oMapGeomFieldDefn{};
79

80
    FeatureDefnDescription() = default;
7✔
81

82
    FeatureDefnDescription(OGRFeatureDefnH hFDefnIn, int iUniqueNumberIn)
7✔
83
        : hFDefn(hFDefnIn), iUniqueNumber(iUniqueNumberIn)
7✔
84
    {
85
    }
7✔
86

87
    FeatureDefnDescription(const FeatureDefnDescription &) = default;
88
    FeatureDefnDescription &operator=(const FeatureDefnDescription &) = default;
89

90
    void Free();
91
};
92

93
}  // namespace
94

95
static std::map<GDALDatasetH, DatasetDescription> oMapDS;
96
static std::set<int> oSetDSIndex;
97
static std::map<OGRLayerH, CPLString> oGlobalMapLayer;
98
static OGRLayerH hLayerGetNextFeature = nullptr;
99
static OGRLayerH hLayerGetLayerDefn = nullptr;
100
static bool bDeferGetFieldCount = false;
101
static int nGetNextFeatureCalls = 0;
102
static std::set<CPLString> aoSetCreatedDS;
103
static std::map<OGRFeatureDefnH, FeatureDefnDescription> oMapFDefn;
104
static std::map<OGRGeomFieldDefnH, CPLString> oGlobalMapGeomFieldDefn;
105
static std::map<OGRFieldDefnH, CPLString> oGlobalMapFieldDefn;
106

107
void FeatureDefnDescription::Free()
1✔
108
{
109
    {
110
        std::map<OGRGeomFieldDefnH, int>::iterator oIter =
111
            oMapGeomFieldDefn.begin();
1✔
112
        for (; oIter != oMapGeomFieldDefn.end(); ++oIter)
1✔
113
            oGlobalMapGeomFieldDefn.erase(oIter->first);
×
114
    }
115
    {
116
        std::map<OGRFieldDefnH, int>::iterator oIter = oMapFieldDefn.begin();
1✔
117
        for (; oIter != oMapFieldDefn.end(); ++oIter)
1✔
118
            oGlobalMapFieldDefn.erase(oIter->first);
×
119
    }
120
}
1✔
121

122
DatasetDescription::~DatasetDescription()
18✔
123
{
124
    {
125
        std::map<OGRLayerH, LayerDescription>::iterator oIter =
126
            oMapLayer.begin();
18✔
127
        for (; oIter != oMapLayer.end(); ++oIter)
27✔
128
            oGlobalMapLayer.erase(oIter->first);
9✔
129
    }
130
}
18✔
131

132
void OGRAPISpyDestroyMutex()
1,128✔
133
{
134
    if (hOGRAPISpyMutex)
1,128✔
135
    {
136
        CPLDestroyMutex(hOGRAPISpyMutex);
×
137
        hOGRAPISpyMutex = nullptr;
×
138

139
        aoSetCreatedDS.clear();
×
140
        oMapFDefn.clear();
×
141
        oGlobalMapGeomFieldDefn.clear();
×
142
        oGlobalMapFieldDefn.clear();
×
143
    }
144
}
1,128✔
145

146
static void OGRAPISpyFileReopen()
196✔
147
{
148
    if (fpSpyFile == nullptr)
196✔
149
    {
150
        fpSpyFile = fopen(osSpyFile, "ab");
182✔
151
        if (fpSpyFile == nullptr)
182✔
152
            fpSpyFile = stderr;
×
153
    }
154
}
196✔
155

156
static void OGRAPISpyFileClose()
185✔
157
{
158
    if (fpSpyFile != stdout && fpSpyFile != stderr)
185✔
159
    {
160
        fclose(fpSpyFile);
185✔
161
        fpSpyFile = nullptr;
185✔
162
    }
163
}
185✔
164

165
static bool OGRAPISpyEnabled()
90,858✔
166
{
167
    if (bOGRAPISpyEnabled < 0)
90,858✔
168
        return false;
8✔
169

170
    const char *pszSpyFile = CPLGetConfigOption("OGR_API_SPY_FILE", nullptr);
90,850✔
171
    bOGRAPISpyEnabled = pszSpyFile != nullptr;
90,881✔
172
    if (!bOGRAPISpyEnabled)
90,881✔
173
    {
174
        osSpyFile.resize(0);
90,831✔
175
        aoSetCreatedDS.clear();
90,833✔
176
        return false;
90,776✔
177
    }
178
    if (!osSpyFile.empty())
50✔
179
        return true;
43✔
180

181
    CPLMutexHolderD(&hOGRAPISpyMutex);
6✔
182
    if (!osSpyFile.empty())
3✔
183
        return true;
×
184

185
    osSpyFile = pszSpyFile;
3✔
186

187
    const char *pszSnapshotPath =
188
        CPLGetConfigOption("OGR_API_SPY_SNAPSHOT_PATH", ".");
3✔
189
    if (EQUAL(pszSnapshotPath, "NO"))
3✔
190
        osSnapshotPath = "";
×
191
    else
192
        osSnapshotPath = pszSnapshotPath;
3✔
193

194
    if (EQUAL(pszSpyFile, "stdout"))
3✔
195
        fpSpyFile = stdout;
×
196
    else if (EQUAL(pszSpyFile, "stderr"))
3✔
197
        fpSpyFile = stderr;
×
198
    else
199
        fpSpyFile = fopen(pszSpyFile, "wb");
3✔
200
    if (fpSpyFile == nullptr)
3✔
201
        fpSpyFile = stderr;
×
202

203
    assert(fpSpyFile != nullptr);
3✔
204
    fprintf(fpSpyFile,
3✔
205
            "# This file is generated by the OGR_API_SPY mechanism.\n");
206
    fprintf(fpSpyFile, "import os\n");
3✔
207
    fprintf(fpSpyFile, "import shutil\n");
3✔
208
    fprintf(fpSpyFile, "from osgeo import gdal\n");
3✔
209
    fprintf(fpSpyFile, "from osgeo import ogr\n");
3✔
210
    fprintf(fpSpyFile, "from osgeo import osr\n");
3✔
211
    // To make pyflakes happy in case it is unused later.
212
    fprintf(fpSpyFile, "os.access\n");
3✔
213
    fprintf(fpSpyFile, "shutil.copy\n");  // Same here.
3✔
214
    fprintf(fpSpyFile, "\n");
3✔
215

216
    return true;
3✔
217
}
218

219
static CPLString OGRAPISpyGetOptions(char **papszOptions)
16✔
220
{
221
    if (papszOptions == nullptr)
16✔
222
    {
223
        return "[]";
10✔
224
    }
225

226
    CPLString options = "[";
12✔
227
    for (char **papszIter = papszOptions; *papszIter != nullptr; papszIter++)
14✔
228
    {
229
        if (papszIter != papszOptions)
8✔
230
            options += ", ";
2✔
231
        options += "'";
8✔
232
        options += *papszIter;
8✔
233
        options += "'";
8✔
234
    }
235
    options += "]";
6✔
236

237
    return options;
6✔
238
}
239

240
static CPLString OGRAPISpyGetString(const char *pszStr)
73✔
241
{
242
    if (pszStr == nullptr)
73✔
243
        return "None";
2✔
244
    CPLString osRet = "'";
142✔
245
    while (*pszStr)
719✔
246
    {
247
        if (*pszStr == '\'')
648✔
248
            osRet += "\\'";
4✔
249
        else if (*pszStr == '\\')
644✔
250
            osRet += "\\\\";
×
251
        else
252
            osRet += *pszStr;
644✔
253
        pszStr++;
648✔
254
    }
255
    osRet += "'";
71✔
256
    return osRet;
71✔
257
}
258

259
static CPLString OGRAPISpyGetDSVar(GDALDatasetH hDS)
74✔
260
{
261
    if (hDS && oMapDS.find(hDS) == oMapDS.end())
74✔
262
    {
263
        int i = 1;
9✔
264
        while (oSetDSIndex.find(i) != oSetDSIndex.end())
9✔
265
            i++;
×
266
        oMapDS[hDS] = DatasetDescription(i);
9✔
267
        oSetDSIndex.insert(i);
9✔
268
    }
269
    return CPLSPrintf("ds%d", hDS ? oMapDS[hDS].iDS : 0);
74✔
270
}
271

272
static CPLString OGRAPISpyGetLayerVar(OGRLayerH hLayer)
98✔
273
{
274
    return oGlobalMapLayer[hLayer];
98✔
275
}
276

277
static CPLString OGRAPISpyGetAndRegisterLayerVar(GDALDatasetH hDS,
17✔
278
                                                 OGRLayerH hLayer)
279
{
280
    DatasetDescription &dd = oMapDS[hDS];
17✔
281
    if (hLayer && dd.oMapLayer.find(hLayer) == dd.oMapLayer.end())
17✔
282
    {
283
        const int i = static_cast<int>(dd.oMapLayer.size()) + 1;
13✔
284
        dd.oMapLayer[hLayer] = LayerDescription(i);
13✔
285
        oGlobalMapLayer[hLayer] =
13✔
286
            OGRAPISpyGetDSVar(hDS) + "_" + CPLSPrintf("lyr%d", i);
26✔
287
    }
288

289
    return OGRAPISpyGetDSVar(hDS) + "_" +
34✔
290
           CPLSPrintf("lyr%d", hLayer ? dd.oMapLayer[hLayer].iLayer : 0);
51✔
291
}
292

293
static CPLString OGRAPISpyGetSRS(OGRSpatialReferenceH hSpatialRef)
10✔
294
{
295
    if (hSpatialRef == nullptr)
10✔
296
        return "None";
6✔
297

298
    char *pszWKT = nullptr;
4✔
299
    OGRSpatialReference::FromHandle(hSpatialRef)->exportToWkt(&pszWKT);
4✔
300
    const char *pszRet =
301
        CPLSPrintf(R"(osr.SpatialReference("""%s"""))", pszWKT);
4✔
302
    CPLFree(pszWKT);
4✔
303
    return pszRet;
4✔
304
}
305

306
static CPLString OGRAPISpyGetGeom(OGRGeometryH hGeom)
12✔
307
{
308
    if (hGeom == nullptr)
12✔
309
        return "None";
6✔
310

311
    char *pszWKT = nullptr;
6✔
312
    OGRGeometry::FromHandle(hGeom)->exportToWkt(&pszWKT);
6✔
313
    const char *pszRet = CPLSPrintf("ogr.CreateGeometryFromWkt('%s')", pszWKT);
6✔
314
    CPLFree(pszWKT);
6✔
315
    return pszRet;
6✔
316
}
317

318
#define casePrefixOgrDot(x)                                                    \
319
    case x:                                                                    \
320
        return "ogr." #x;
321

322
static CPLString OGRAPISpyGetGeomType(OGRwkbGeometryType eType)
10✔
323
{
324
    switch (eType)
10✔
325
    {
326
        casePrefixOgrDot(wkbUnknown) casePrefixOgrDot(wkbPoint) casePrefixOgrDot(wkbLineString) casePrefixOgrDot(
10✔
327
            wkbPolygon) casePrefixOgrDot(wkbMultiPoint) casePrefixOgrDot(wkbMultiLineString)
×
328
            casePrefixOgrDot(wkbMultiPolygon) casePrefixOgrDot(wkbGeometryCollection) casePrefixOgrDot(
×
329
                wkbCircularString) casePrefixOgrDot(wkbCompoundCurve) casePrefixOgrDot(wkbCurvePolygon)
×
330
                casePrefixOgrDot(wkbMultiCurve) casePrefixOgrDot(wkbMultiSurface) casePrefixOgrDot(
×
331
                    wkbCurve) casePrefixOgrDot(wkbSurface) casePrefixOgrDot(wkbNone) casePrefixOgrDot(wkbLinearRing)
×
332
                    casePrefixOgrDot(wkbCircularStringZ) casePrefixOgrDot(wkbCompoundCurveZ) casePrefixOgrDot(
×
333
                        wkbCurvePolygonZ) casePrefixOgrDot(wkbMultiCurveZ) casePrefixOgrDot(wkbMultiSurfaceZ)
×
334
                        casePrefixOgrDot(wkbCurveZ) casePrefixOgrDot(wkbSurfaceZ) casePrefixOgrDot(
×
335
                            wkbPoint25D) casePrefixOgrDot(wkbLineString25D) casePrefixOgrDot(wkbPolygon25D)
×
336
                            casePrefixOgrDot(wkbMultiPoint25D) casePrefixOgrDot(wkbMultiLineString25D) casePrefixOgrDot(
×
337
                                wkbMultiPolygon25D) casePrefixOgrDot(wkbGeometryCollection25D)
×
338
                                casePrefixOgrDot(wkbPolyhedralSurface) casePrefixOgrDot(
×
339
                                    wkbTIN) casePrefixOgrDot(wkbTriangle) casePrefixOgrDot(wkbPolyhedralSurfaceZ)
×
340
                                    casePrefixOgrDot(wkbTINZ) casePrefixOgrDot(wkbTriangleZ) casePrefixOgrDot(
×
341
                                        wkbPointM) casePrefixOgrDot(wkbLineStringM) casePrefixOgrDot(wkbPolygonM)
×
342
                                        casePrefixOgrDot(wkbMultiPointM) casePrefixOgrDot(
×
343
                                            wkbMultiLineStringM) casePrefixOgrDot(wkbMultiPolygonM)
×
344
                                            casePrefixOgrDot(wkbGeometryCollectionM) casePrefixOgrDot(
×
345
                                                wkbCircularStringM) casePrefixOgrDot(wkbCompoundCurveM)
×
346
                                                casePrefixOgrDot(wkbCurvePolygonM) casePrefixOgrDot(
×
347
                                                    wkbMultiCurveM) casePrefixOgrDot(wkbMultiSurfaceM)
×
348
                                                    casePrefixOgrDot(wkbCurveM) casePrefixOgrDot(
×
349
                                                        wkbSurfaceM) casePrefixOgrDot(wkbPolyhedralSurfaceM)
×
350
                                                        casePrefixOgrDot(wkbTINM) casePrefixOgrDot(
×
351
                                                            wkbTriangleM) casePrefixOgrDot(wkbPointZM)
×
352
                                                            casePrefixOgrDot(wkbLineStringZM) casePrefixOgrDot(
×
353
                                                                wkbPolygonZM) casePrefixOgrDot(wkbMultiPointZM)
×
354
                                                                casePrefixOgrDot(wkbMultiLineStringZM) casePrefixOgrDot(
×
355
                                                                    wkbMultiPolygonZM) casePrefixOgrDot(wkbGeometryCollectionZM)
×
356
                                                                    casePrefixOgrDot(wkbCircularStringZM) casePrefixOgrDot(
×
357
                                                                        wkbCompoundCurveZM)
358
                                                                        casePrefixOgrDot(wkbCurvePolygonZM) casePrefixOgrDot(
×
359
                                                                            wkbMultiCurveZM)
360
                                                                            casePrefixOgrDot(
×
361
                                                                                wkbMultiSurfaceZM)
362
                                                                                casePrefixOgrDot(
×
363
                                                                                    wkbCurveZM)
364
                                                                                    casePrefixOgrDot(
×
365
                                                                                        wkbSurfaceZM)
366
                                                                                        casePrefixOgrDot(
×
367
                                                                                            wkbPolyhedralSurfaceZM)
368
                                                                                            casePrefixOgrDot(
×
369
                                                                                                wkbTriangleZM)
370
                                                                                                casePrefixOgrDot(
×
371
                                                                                                    wkbTINZM)
372
    }
373
    return "error";
×
374
}
375

376
static CPLString OGRAPISpyGetFieldType(OGRFieldType eType)
8✔
377
{
378
    switch (eType)
8✔
379
    {
380
        casePrefixOgrDot(OFTInteger) casePrefixOgrDot(OFTInteger64)
2✔
381
            casePrefixOgrDot(OFTIntegerList) casePrefixOgrDot(OFTInteger64List)
×
382
                casePrefixOgrDot(OFTReal) casePrefixOgrDot(OFTRealList)
2✔
383
                    casePrefixOgrDot(OFTString) casePrefixOgrDot(OFTStringList)
4✔
384
                        casePrefixOgrDot(OFTWideString)
×
385
                            casePrefixOgrDot(OFTWideStringList)
×
386
                                casePrefixOgrDot(OFTBinary)
×
387
                                    casePrefixOgrDot(OFTDate)
×
388
                                        casePrefixOgrDot(OFTTime)
×
389
                                            casePrefixOgrDot(OFTDateTime)
×
390
    }
391
    return "error";
×
392
}
393

394
#undef casePrefixOgrDot
395

396
static CPLString OGRAPISpyGetFeatureDefnVar(OGRFeatureDefnH hFDefn)
44✔
397
{
398
    std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter =
399
        oMapFDefn.find(hFDefn);
44✔
400
    int i = 0;
44✔
401
    if (oIter == oMapFDefn.end())
44✔
402
    {
403
        i = static_cast<int>(oMapFDefn.size()) + 1;
7✔
404
        oMapFDefn[hFDefn] = FeatureDefnDescription(hFDefn, i);
7✔
405

406
        // So that we can check when they are no longer used.
407
        OGRFeatureDefn::FromHandle(hFDefn)->Reference();
7✔
408
    }
409
    else
410
    {
411
        i = oIter->second.iUniqueNumber;
37✔
412
    }
413
    return CPLSPrintf("fdefn%d", i);
88✔
414
}
415

416
static void OGRAPISpyFlushDefered()
188✔
417
{
418
    OGRAPISpyFileReopen();
188✔
419
    if (hLayerGetLayerDefn != nullptr)
188✔
420
    {
421
        OGRFeatureDefnH hDefn = OGRFeatureDefn::ToHandle(
13✔
422
            OGRLayer::FromHandle(hLayerGetLayerDefn)->GetLayerDefn());
13✔
423
        fprintf(fpSpyFile, "%s = %s.GetLayerDefn()\n",
26✔
424
                OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
26✔
425
                OGRAPISpyGetLayerVar(hLayerGetLayerDefn).c_str());
26✔
426

427
        if (bDeferGetFieldCount)
13✔
428
        {
429
            fprintf(fpSpyFile, "%s.GetFieldCount()\n",
2✔
430
                    OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
4✔
431
            bDeferGetFieldCount = false;
2✔
432
        }
433

434
        hLayerGetLayerDefn = nullptr;
13✔
435
    }
436

437
    if (nGetNextFeatureCalls == 1)
188✔
438
    {
439
        fprintf(fpSpyFile, "%s.GetNextFeature()\n",
2✔
440
                OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
4✔
441
        hLayerGetNextFeature = nullptr;
2✔
442
        nGetNextFeatureCalls = 0;
2✔
443
    }
444
    else if (nGetNextFeatureCalls > 0)
186✔
445
    {
446
        fprintf(fpSpyFile, "for i in range(%d):\n", nGetNextFeatureCalls);
2✔
447
        fprintf(fpSpyFile, "    %s.GetNextFeature()\n",
2✔
448
                OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
4✔
449
        hLayerGetNextFeature = nullptr;
2✔
450
        nGetNextFeatureCalls = 0;
2✔
451
    }
452
}
188✔
453

454
int OGRAPISpyOpenTakeSnapshot(const char *pszName, int bUpdate)
11,655✔
455
{
456
    if (!OGRAPISpyEnabled() || !bUpdate || osSnapshotPath.empty() ||
11,660✔
457
        aoSetCreatedDS.find(pszName) != aoSetCreatedDS.end())
11,660✔
458
        return -1;
11,652✔
459
    OGRAPISpyFlushDefered();
3✔
460

461
    VSIStatBufL sStat;
462
    if (VSIStatL(pszName, &sStat) == 0)
3✔
463
    {
464
        bOGRAPISpyEnabled = -1;
1✔
465
        GDALDatasetH hDS =
466
            GDALOpenEx(pszName, GDAL_OF_VECTOR, nullptr, nullptr, nullptr);
1✔
467
        char **papszFileList =
468
            hDS ? GDALDataset::FromHandle(hDS)->GetFileList() : nullptr;
1✔
469
        GDALClose(hDS);
1✔
470
        bOGRAPISpyEnabled = true;
1✔
471
        if (papszFileList)
1✔
472
        {
473
            int i = 1;
1✔
474
            CPLString osBaseDir;
2✔
475
            CPLString osSrcDir;
2✔
476
            CPLString osWorkingDir;
1✔
477
            while (true)
478
            {
479
                osBaseDir = CPLFormFilenameSafe(
1✔
480
                    osSnapshotPath, CPLSPrintf("snapshot_%d", i), nullptr);
1✔
481
                if (VSIStatL(osBaseDir, &sStat) != 0)
1✔
482
                    break;
1✔
483
                i++;
×
484
            }
485
            VSIMkdir(osSnapshotPath, 0777);
1✔
486
            VSIMkdir(osBaseDir, 0777);
1✔
487
            osSrcDir = CPLFormFilenameSafe(osBaseDir, "source", nullptr);
1✔
488
            VSIMkdir(osSrcDir, 0777);
1✔
489
            osWorkingDir = CPLFormFilenameSafe(osBaseDir, "working", nullptr);
1✔
490
            VSIMkdir(osWorkingDir, 0777);
1✔
491

492
            OGRAPISpyFileReopen();
1✔
493
            fprintf(fpSpyFile, "# Take snapshot of %s\n", pszName);
1✔
494
            fprintf(fpSpyFile, "try:\n");
1✔
495
            fprintf(fpSpyFile, "    shutil.rmtree('%s')\n",
1✔
496
                    osWorkingDir.c_str());
497
            fprintf(fpSpyFile, "except:\n");
1✔
498
            fprintf(fpSpyFile, "    pass\n");
1✔
499
            fprintf(fpSpyFile, "os.mkdir('%s')\n", osWorkingDir.c_str());
1✔
500
            for (char **papszIter = papszFileList; *papszIter; papszIter++)
4✔
501
            {
502
                CPLString osSnapshotSrcFile = CPLFormFilenameSafe(
3✔
503
                    osSrcDir, CPLGetFilename(*papszIter), nullptr);
6✔
504
                CPLString osSnapshotWorkingFile = CPLFormFilenameSafe(
3✔
505
                    osWorkingDir, CPLGetFilename(*papszIter), nullptr);
6✔
506
                CPL_IGNORE_RET_VAL(CPLCopyFile(osSnapshotSrcFile, *papszIter));
3✔
507
                CPL_IGNORE_RET_VAL(
3✔
508
                    CPLCopyFile(osSnapshotWorkingFile, *papszIter));
3✔
509
                fprintf(fpSpyFile, "shutil.copy('%s', '%s')\n",
3✔
510
                        osSnapshotSrcFile.c_str(),
511
                        osSnapshotWorkingFile.c_str());
512
            }
513
            CSLDestroy(papszFileList);
1✔
514
            return i;
1✔
515
        }
516
    }
517
    return -1;
2✔
518
}
519

520
void OGRAPISpyOpen(const char *pszName, int bUpdate, int iSnapshot,
11,655✔
521
                   GDALDatasetH *phDS)
522
{
523
    if (!OGRAPISpyEnabled())
11,655✔
524
        return;
11,648✔
525
    CPLMutexHolderD(&hOGRAPISpyMutex);
14✔
526
    OGRAPISpyFlushDefered();
7✔
527

528
    CPLString osName;
14✔
529
    if (iSnapshot > 0)
7✔
530
    {
531
        CPLString osBaseDir = CPLFormFilenameSafe(
1✔
532
            osSnapshotPath, CPLSPrintf("snapshot_%d", iSnapshot), nullptr);
2✔
533
        CPLString osWorkingDir =
534
            CPLFormFilenameSafe(osBaseDir, "working", nullptr);
2✔
535
        osName =
536
            CPLFormFilenameSafe(osWorkingDir, CPLGetFilename(pszName), nullptr);
1✔
537
        pszName = osName.c_str();
1✔
538

539
        if (*phDS != nullptr)
1✔
540
        {
541
            bOGRAPISpyEnabled = -1;
1✔
542
            GDALClose(GDALDataset::FromHandle(*phDS));
1✔
543
            *phDS = GDALOpenEx(pszName, GDAL_OF_VECTOR | GDAL_OF_UPDATE,
1✔
544
                               nullptr, nullptr, nullptr);
545
            bOGRAPISpyEnabled = true;
1✔
546
        }
547
    }
548

549
    OGRAPISpyFileReopen();
7✔
550
    if (*phDS != nullptr)
7✔
551
        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar(*phDS).c_str());
3✔
552
    if (bUpdate)
7✔
553
        fprintf(fpSpyFile, "gdal.OpenEx(%s, gdal.OF_VECTOR | gdal.OF_UPDATE)\n",
5✔
554
                OGRAPISpyGetString(pszName).c_str());
10✔
555
    else
556
        fprintf(fpSpyFile, "gdal.OpenEx(%s, gdal.OF_VECTOR)\n",
2✔
557
                OGRAPISpyGetString(pszName).c_str());
4✔
558
    OGRAPISpyFileClose();
7✔
559
}
560

561
void OGRAPISpyPreClose(GDALDatasetH hDS)
11✔
562
{
563
    if (!OGRAPISpyEnabled())
11✔
564
        return;
2✔
565
    CPLMutexHolderD(&hOGRAPISpyMutex);
18✔
566
    OGRAPISpyFlushDefered();
9✔
567
    fprintf(fpSpyFile, "ds%d = None\n", oMapDS[hDS].iDS);
9✔
568
    oSetDSIndex.erase(oMapDS[hDS].iDS);
9✔
569
    oMapDS.erase(hDS);
9✔
570
    OGRAPISpyFileClose();
9✔
571
}
572

573
void OGRAPISpyPostClose()
11✔
574
{
575
    {
576
        if (!OGRAPISpyEnabled())
11✔
577
            return;
2✔
578
        CPLMutexHolderD(&hOGRAPISpyMutex);
18✔
579
        std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter =
580
            oMapFDefn.begin();
9✔
581
        std::vector<OGRFeatureDefnH> oArray;
18✔
582
        for (; oIter != oMapFDefn.end(); ++oIter)
20✔
583
        {
584
            FeatureDefnDescription &featureDefnDescription = oIter->second;
11✔
585
            if (OGRFeatureDefn::FromHandle(featureDefnDescription.hFDefn)
11✔
586
                    ->GetReferenceCount() == 1)
11✔
587
            {
588
                oArray.push_back(featureDefnDescription.hFDefn);
1✔
589
            }
590
        }
591
        for (auto &hFDefn : oArray)
10✔
592
        {
593
            FeatureDefnDescription &featureDefnDescription = oMapFDefn[hFDefn];
1✔
594
            OGRFeatureDefn::FromHandle(featureDefnDescription.hFDefn)
595
                ->Release();
1✔
596
            featureDefnDescription.Free();
1✔
597
            oMapFDefn.erase(hFDefn);
1✔
598
        }
599
    }
600
}
601

602
void OGRAPISpyCreateDataSource(GDALDriverH hDriver, const char *pszName,
3,248✔
603
                               char **papszOptions, GDALDatasetH hDS)
604
{
605
    if (!OGRAPISpyEnabled())
3,248✔
606
        return;
3,242✔
607
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
608
    OGRAPISpyFlushDefered();
6✔
609
    if (hDS != nullptr)
6✔
610
        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar(hDS).c_str());
6✔
611
    fprintf(fpSpyFile,
12✔
612
            "ogr.GetDriverByName('%s').CreateDataSource(%s, options=%s)\n",
613
            GDALGetDriverShortName(hDriver),
614
            OGRAPISpyGetString(pszName).c_str(),
12✔
615
            OGRAPISpyGetOptions(papszOptions).c_str());
12✔
616
    if (hDS != nullptr)
6✔
617
    {
618
        aoSetCreatedDS.insert(pszName);
6✔
619
    }
620
    OGRAPISpyFileClose();
6✔
621
}
622

623
void OGRAPISpyDeleteDataSource(GDALDriverH hDriver, const char *pszName)
485✔
624
{
625
    if (!OGRAPISpyEnabled())
485✔
626
        return;
479✔
627
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
628
    OGRAPISpyFlushDefered();
6✔
629
    fprintf(fpSpyFile, "ogr.GetDriverByName('%s').DeleteDataSource(%s)\n",
6✔
630
            GDALGetDriverShortName(hDriver),
631
            OGRAPISpyGetString(pszName).c_str());
12✔
632
    aoSetCreatedDS.erase(pszName);
6✔
633
    OGRAPISpyFileClose();
6✔
634
}
635

636
void OGRAPISpy_DS_GetLayer(GDALDatasetH hDS, int iLayer, OGRLayerH hLayer)
3✔
637
{
638
    CPLMutexHolderD(&hOGRAPISpyMutex);
6✔
639
    OGRAPISpyFlushDefered();
3✔
640
    if (hLayer != nullptr)
3✔
641
        fprintf(fpSpyFile,
3✔
642
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
6✔
643
    fprintf(fpSpyFile, "%s.GetLayer(%d)\n", OGRAPISpyGetDSVar(hDS).c_str(),
3✔
644
            iLayer);
645
    OGRAPISpyFileClose();
3✔
646
}
3✔
647

648
void OGRAPISpy_DS_GetLayerCount(GDALDatasetH hDS)
2✔
649
{
650
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
651
    OGRAPISpyFlushDefered();
2✔
652
    fprintf(fpSpyFile, "%s.GetLayerCount()\n", OGRAPISpyGetDSVar(hDS).c_str());
2✔
653
    OGRAPISpyFileClose();
2✔
654
}
2✔
655

656
void OGRAPISpy_DS_GetLayerByName(GDALDatasetH hDS, const char *pszLayerName,
4✔
657
                                 OGRLayerH hLayer)
658
{
659
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
660
    OGRAPISpyFlushDefered();
4✔
661
    if (hLayer != nullptr)
4✔
662
        fprintf(fpSpyFile,
2✔
663
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
4✔
664
    fprintf(fpSpyFile, "%s.GetLayerByName(%s)\n",
8✔
665
            OGRAPISpyGetDSVar(hDS).c_str(),
8✔
666
            OGRAPISpyGetString(pszLayerName).c_str());
8✔
667
    OGRAPISpyFileClose();
4✔
668
}
4✔
669

670
void OGRAPISpy_DS_ExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
4✔
671
                             OGRGeometryH hSpatialFilter,
672
                             const char *pszDialect, OGRLayerH hLayer)
673
{
674
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
675
    OGRAPISpyFlushDefered();
4✔
676
    if (hLayer != nullptr)
4✔
677
        fprintf(fpSpyFile,
4✔
678
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
8✔
679
    fprintf(fpSpyFile, "%s.ExecuteSQL(%s, %s, %s)\n",
16✔
680
            OGRAPISpyGetDSVar(hDS).c_str(),
8✔
681
            OGRAPISpyGetString(pszStatement).c_str(),
8✔
682
            OGRAPISpyGetGeom(hSpatialFilter).c_str(),
8✔
683
            OGRAPISpyGetString(pszDialect).c_str());
8✔
684
    OGRAPISpyFileClose();
4✔
685
}
4✔
686

687
void OGRAPISpy_DS_ReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
6✔
688
{
689
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
690
    OGRAPISpyFlushDefered();
6✔
691
    fprintf(fpSpyFile, "%s.ReleaseResultSet(%s)\n",
8✔
692
            OGRAPISpyGetDSVar(hDS).c_str(),
12✔
693
            (hLayer) ? OGRAPISpyGetLayerVar(hLayer).c_str() : "None");
12✔
694

695
    DatasetDescription &dd = oMapDS[hDS];
6✔
696
    dd.oMapLayer.erase(hLayer);
6✔
697
    oGlobalMapLayer.erase(hLayer);
6✔
698

699
    OGRAPISpyFileClose();
6✔
700
}
6✔
701

702
void OGRAPISpy_DS_CreateLayer(GDALDatasetH hDS, const char *pszName,
8✔
703
                              OGRSpatialReferenceH hSpatialRef,
704
                              OGRwkbGeometryType eType, char **papszOptions,
705
                              OGRLayerH hLayer)
706
{
707
    CPLMutexHolderD(&hOGRAPISpyMutex);
16✔
708
    OGRAPISpyFlushDefered();
8✔
709
    if (hLayer != nullptr)
8✔
710
        fprintf(fpSpyFile,
8✔
711
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
16✔
712
    fprintf(fpSpyFile, "%s.CreateLayer(%s, srs=%s, geom_type=%s, options=%s)\n",
40✔
713
            OGRAPISpyGetDSVar(hDS).c_str(), OGRAPISpyGetString(pszName).c_str(),
24✔
714
            OGRAPISpyGetSRS(hSpatialRef).c_str(),
16✔
715
            OGRAPISpyGetGeomType(eType).c_str(),
16✔
716
            OGRAPISpyGetOptions(papszOptions).c_str());
16✔
717
    OGRAPISpyFileClose();
8✔
718
}
8✔
719

720
void OGRAPISpy_DS_DeleteLayer(GDALDatasetH hDS, int iLayer)
2✔
721
{
722
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
723
    OGRAPISpyFlushDefered();
2✔
724
    fprintf(fpSpyFile, "%s.DeleteLayer(%d)\n", OGRAPISpyGetDSVar(hDS).c_str(),
2✔
725
            iLayer);
726
    // Should perhaps remove from the maps.
727
    OGRAPISpyFileClose();
2✔
728
}
2✔
729

730
void OGRAPISpy_Dataset_StartTransaction(GDALDatasetH hDS, int bForce)
2✔
731
{
732
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
733
    OGRAPISpyFlushDefered();
2✔
734
    fprintf(fpSpyFile, "%s.StartTransaction(%d)\n",
2✔
735
            OGRAPISpyGetDSVar(hDS).c_str(), bForce);
4✔
736
    OGRAPISpyFileClose();
2✔
737
}
2✔
738

739
void OGRAPISpy_Dataset_CommitTransaction(GDALDatasetH hDS)
2✔
740
{
741
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
742
    OGRAPISpyFlushDefered();
2✔
743
    fprintf(fpSpyFile, "%s.CommitTransaction()\n",
2✔
744
            OGRAPISpyGetDSVar(hDS).c_str());
4✔
745
    OGRAPISpyFileClose();
2✔
746
}
2✔
747

748
void OGRAPISpy_Dataset_RollbackTransaction(GDALDatasetH hDS)
2✔
749
{
750
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
751
    OGRAPISpyFlushDefered();
2✔
752
    fprintf(fpSpyFile, "%s.RollbackTransaction()\n",
2✔
753
            OGRAPISpyGetDSVar(hDS).c_str());
4✔
754
    OGRAPISpyFileClose();
2✔
755
}
2✔
756

757
void OGRAPISpy_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
2✔
758
{
759
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
760
    OGRAPISpyFlushDefered();
2✔
761
    fprintf(fpSpyFile, "%s.GetFeatureCount(force=%d)\n",
2✔
762
            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
4✔
763
    OGRAPISpyFileClose();
2✔
764
}
2✔
765

766
void OGRAPISpy_L_GetExtent(OGRLayerH hLayer, int bForce)
×
767
{
768
    CPLMutexHolderD(&hOGRAPISpyMutex);
×
769
    OGRAPISpyFlushDefered();
×
770
    fprintf(fpSpyFile, "%s.GetExtent(force=%d)\n",
×
771
            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
×
772
    OGRAPISpyFileClose();
×
773
}
×
774

775
void OGRAPISpy_L_GetExtentEx(OGRLayerH hLayer, int iGeomField, int bForce)
4✔
776
{
777
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
778
    OGRAPISpyFlushDefered();
4✔
779
    fprintf(fpSpyFile, "%s.GetExtent(geom_field=%d, force=%d)\n",
4✔
780
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, bForce);
8✔
781
    OGRAPISpyFileClose();
4✔
782
}
4✔
783

784
void OGRAPISpy_L_GetExtent3D(OGRLayerH hLayer, int iGeomField, int bForce)
×
785
{
786
    CPLMutexHolderD(&hOGRAPISpyMutex);
×
787
    OGRAPISpyFlushDefered();
×
788
    fprintf(fpSpyFile, "%s.GetExtent3D(geom_field=%d, force=%d)\n",
×
789
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, bForce);
×
790
    OGRAPISpyFileClose();
×
791
}
×
792

793
void OGRAPISpy_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszFilter)
4✔
794
{
795
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
796
    OGRAPISpyFlushDefered();
4✔
797
    fprintf(fpSpyFile, "%s.SetAttributeFilter(%s)\n",
8✔
798
            OGRAPISpyGetLayerVar(hLayer).c_str(),
8✔
799
            OGRAPISpyGetString(pszFilter).c_str());
8✔
800
    OGRAPISpyFileClose();
4✔
801
}
4✔
802

803
void OGRAPISpy_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
2✔
804
{
805
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
806
    OGRAPISpyFlushDefered();
2✔
807
    fprintf(fpSpyFile, "%s.GetFeature(" CPL_FRMT_GIB ")\n",
2✔
808
            OGRAPISpyGetLayerVar(hLayer).c_str(), nFeatureId);
4✔
809
    OGRAPISpyFileClose();
2✔
810
}
2✔
811

812
void OGRAPISpy_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
2✔
813
{
814
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
815
    OGRAPISpyFlushDefered();
2✔
816
    fprintf(fpSpyFile, "%s.SetNextByIndex(" CPL_FRMT_GIB ")\n",
2✔
817
            OGRAPISpyGetLayerVar(hLayer).c_str(), nIndex);
4✔
818
    OGRAPISpyFileClose();
2✔
819
}
2✔
820

821
void OGRAPISpy_L_GetNextFeature(OGRLayerH hLayer)
8✔
822
{
823
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
824
    if (hLayerGetNextFeature != hLayer)
8✔
825
    {
826
        OGRAPISpyFlushDefered();
4✔
827
        OGRAPISpyFileClose();
4✔
828
    }
829
    hLayerGetNextFeature = hLayer;
8✔
830
    nGetNextFeatureCalls++;
8✔
831
}
8✔
832

833
static void OGRAPISpyDumpFeature(OGRFeatureH hFeat)
7✔
834
{
835
    OGRFeature *poFeature = OGRFeature::FromHandle(hFeat);
7✔
836

837
    fprintf(fpSpyFile, "f = ogr.Feature(%s)\n",
7✔
838
            OGRAPISpyGetFeatureDefnVar(
14✔
839
                OGRFeatureDefn::ToHandle(poFeature->GetDefnRef()))
840
                .c_str());
841
    if (poFeature->GetFID() != -1)
7✔
842
        fprintf(fpSpyFile, "f.SetFID(" CPL_FRMT_GIB ")\n", poFeature->GetFID());
2✔
843
    for (int i = 0; i < poFeature->GetFieldCount(); i++)
20✔
844
    {
845
        if (poFeature->IsFieldNull(i))
13✔
846
        {
847
            fprintf(fpSpyFile, "f.SetFieldNull(%d)\n", i);
×
848
        }
849
        else if (poFeature->IsFieldSet(i))
13✔
850
        {
851
            switch (poFeature->GetFieldDefnRef(i)->GetType())
10✔
852
            {
853
                case OFTInteger:
4✔
854
                    fprintf(fpSpyFile, "f.SetField(%d, %d)\n", i,
4✔
855
                            poFeature->GetFieldAsInteger(i));
856
                    break;
4✔
857
                case OFTReal:
2✔
858
                    fprintf(fpSpyFile, "%s",
2✔
859
                            CPLSPrintf("f.SetField(%d, %.16g)\n", i,
860
                                       poFeature->GetFieldAsDouble(i)));
861
                    break;
2✔
862
                case OFTString:
4✔
863
                    fprintf(fpSpyFile, "f.SetField(%d, %s)\n", i,
4✔
864
                            OGRAPISpyGetString(poFeature->GetFieldAsString(i))
8✔
865
                                .c_str());
866
                    break;
4✔
867
                default:
×
868
                    fprintf(fpSpyFile, "f.SetField(%d, %s) #FIXME\n", i,
×
869
                            OGRAPISpyGetString(poFeature->GetFieldAsString(i))
×
870
                                .c_str());
871
                    break;
×
872
            }
873
        }
874
    }
875
    for (int i = 0; i < poFeature->GetGeomFieldCount(); i++)
14✔
876
    {
877
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
7✔
878
        if (poGeom != nullptr)
7✔
879
        {
880
            fprintf(fpSpyFile, "f.SetGeomField(%d, %s)\n", i,
2✔
881
                    OGRAPISpyGetGeom(OGRGeometry::ToHandle(poGeom)).c_str());
4✔
882
        }
883
    }
884
    const char *pszStyleString = poFeature->GetStyleString();
7✔
885
    if (pszStyleString != nullptr)
7✔
886
        fprintf(fpSpyFile, "f.SetStyleString(%s)\n",
2✔
887
                OGRAPISpyGetString(pszStyleString).c_str());
4✔
888
}
7✔
889

890
void OGRAPISpy_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
2✔
891
{
892
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
893
    OGRAPISpyFlushDefered();
2✔
894
    OGRAPISpyDumpFeature(hFeat);
2✔
895
    fprintf(fpSpyFile, "%s.SetFeature(f)\n",
2✔
896
            OGRAPISpyGetLayerVar(hLayer).c_str());
4✔
897
    // In case layer defn is changed afterwards.
898
    fprintf(fpSpyFile, "f = None\n");
2✔
899
    OGRAPISpyFileClose();
2✔
900
}
2✔
901

902
void OGRAPISpy_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
5✔
903
{
904
    CPLMutexHolderD(&hOGRAPISpyMutex);
10✔
905
    OGRAPISpyFlushDefered();
5✔
906
    OGRAPISpyDumpFeature(hFeat);
5✔
907
    fprintf(fpSpyFile, "%s.CreateFeature(f)\n",
5✔
908
            OGRAPISpyGetLayerVar(hLayer).c_str());
10✔
909
    // In case layer defn is changed afterwards.
910
    fprintf(fpSpyFile, "f = None\n");
5✔
911
    OGRAPISpyFileClose();
5✔
912
}
5✔
913

914
void OGRAPISpy_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
×
915
{
916
    CPLMutexHolderD(&hOGRAPISpyMutex);
×
917
    OGRAPISpyFlushDefered();
×
918
    OGRAPISpyDumpFeature(hFeat);
×
919
    fprintf(fpSpyFile, "%s.UpsertFeature(f)\n",
×
920
            OGRAPISpyGetLayerVar(hLayer).c_str());
×
921
    // In case layer defn is changed afterwards.
922
    fprintf(fpSpyFile, "f = None\n");
×
923
    OGRAPISpyFileClose();
×
924
}
×
925

926
static void OGRAPISpyDumpFieldDefn(OGRFieldDefn *poFieldDefn)
8✔
927
{
928
    CPLMutexHolderD(&hOGRAPISpyMutex);
16✔
929
    fprintf(fpSpyFile, "fd = ogr.FieldDefn(%s, %s)\n",
16✔
930
            OGRAPISpyGetString(poFieldDefn->GetNameRef()).c_str(),
16✔
931
            OGRAPISpyGetFieldType(poFieldDefn->GetType()).c_str());
16✔
932
    if (poFieldDefn->GetWidth() > 0)
8✔
933
        fprintf(fpSpyFile, "fd.SetWidth(%d)\n", poFieldDefn->GetWidth());
2✔
934
    if (poFieldDefn->GetPrecision() > 0)
8✔
935
        fprintf(fpSpyFile, "fd.SetPrecision(%d)\n",
2✔
936
                poFieldDefn->GetPrecision());
937
    if (!poFieldDefn->IsNullable())
8✔
938
        fprintf(fpSpyFile, "fd.SetNullable(0)\n");
2✔
939
    if (poFieldDefn->GetDefault() != nullptr)
8✔
940
        fprintf(fpSpyFile, "fd.SetDefault(%s)\n",
2✔
941
                OGRAPISpyGetString(poFieldDefn->GetDefault()).c_str());
4✔
942
}
8✔
943

944
void OGRAPISpy_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField,
6✔
945
                             int bApproxOK)
946
{
947
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
948
    OGRAPISpyFlushDefered();
6✔
949
    OGRFieldDefn *poFieldDefn = OGRFieldDefn::FromHandle(hField);
6✔
950
    OGRAPISpyDumpFieldDefn(poFieldDefn);
6✔
951
    fprintf(fpSpyFile, "%s.CreateField(fd, approx_ok=%d)\n",
6✔
952
            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
12✔
953
    OGRAPISpyFileClose();
6✔
954
}
6✔
955

956
void OGRAPISpy_L_DeleteField(OGRLayerH hLayer, int iField)
2✔
957
{
958
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
959
    OGRAPISpyFlushDefered();
2✔
960
    fprintf(fpSpyFile, "%s.DeleteField(%d)\n",
2✔
961
            OGRAPISpyGetLayerVar(hLayer).c_str(), iField);
4✔
962
    OGRAPISpyFileClose();
2✔
963
}
2✔
964

965
void OGRAPISpy_L_ReorderFields(OGRLayerH hLayer, int *panMap)
2✔
966
{
967
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
968
    OGRAPISpyFlushDefered();
2✔
969
    OGRLayer *poLayer = OGRLayer::FromHandle(hLayer);
2✔
970
    fprintf(fpSpyFile, "%s.ReorderFields([",
2✔
971
            OGRAPISpyGetLayerVar(hLayer).c_str());
4✔
972
    for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++)
8✔
973
    {
974
        if (i > 0)
6✔
975
            fprintf(fpSpyFile, ", ");
4✔
976
        fprintf(fpSpyFile, "%d", panMap[i]);
6✔
977
    }
978
    fprintf(fpSpyFile, "])\n");
2✔
979
    OGRAPISpyFileClose();
2✔
980
}
2✔
981

982
void OGRAPISpy_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos,
2✔
983
                              int iNewFieldPos)
984
{
985
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
986
    OGRAPISpyFlushDefered();
2✔
987
    fprintf(fpSpyFile, "%s.ReorderField(%d, %d)\n",
2✔
988
            OGRAPISpyGetLayerVar(hLayer).c_str(), iOldFieldPos, iNewFieldPos);
4✔
989
    OGRAPISpyFileClose();
2✔
990
}
2✔
991

992
void OGRAPISpy_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
2✔
993
                                OGRFieldDefnH hNewFieldDefn, int nFlags)
994
{
995
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
996
    OGRAPISpyFlushDefered();
2✔
997
    OGRFieldDefn *poFieldDefn = OGRFieldDefn::FromHandle(hNewFieldDefn);
2✔
998
    OGRAPISpyDumpFieldDefn(poFieldDefn);
2✔
999
    fprintf(fpSpyFile, "%s.AlterFieldDefn(%d, fd, %d)\n",
2✔
1000
            OGRAPISpyGetLayerVar(hLayer).c_str(), iField, nFlags);
4✔
1001
    OGRAPISpyFileClose();
2✔
1002
}
2✔
1003

1004
void OGRAPISpy_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
2✔
1005
                                 int bApproxOK)
1006
{
1007
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1008
    OGRAPISpyFlushDefered();
2✔
1009
    OGRGeomFieldDefn *poGeomFieldDefn = OGRGeomFieldDefn::FromHandle(hField);
2✔
1010

1011
    fprintf(fpSpyFile, "geom_fd = ogr.GeomFieldDefn(%s, %s)\n",
4✔
1012
            OGRAPISpyGetString(poGeomFieldDefn->GetNameRef()).c_str(),
4✔
1013
            OGRAPISpyGetGeomType(poGeomFieldDefn->GetType()).c_str());
4✔
1014
    if (poGeomFieldDefn->GetSpatialRef() != nullptr)
2✔
1015
        fprintf(fpSpyFile, "geom_fd.SetSpatialRef(%s)\n",
2✔
1016
                OGRAPISpyGetSRS(OGRSpatialReference::ToHandle(
4✔
1017
                                    const_cast<OGRSpatialReference *>(
1018
                                        poGeomFieldDefn->GetSpatialRef())))
2✔
1019
                    .c_str());
1020
    if (!poGeomFieldDefn->IsNullable())
2✔
1021
        fprintf(fpSpyFile, "geom_fd.SetNullable(0)\n");
2✔
1022
    fprintf(fpSpyFile, "%s.CreateGeomField(geom_fd, approx_ok=%d)\n",
2✔
1023
            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
4✔
1024
    OGRAPISpyFileClose();
2✔
1025
}
2✔
1026

1027
static void OGRAPISpy_L_Op(OGRLayerH hLayer, const char *pszMethod)
22✔
1028
{
1029
    CPLMutexHolderD(&hOGRAPISpyMutex);
44✔
1030
    OGRAPISpyFlushDefered();
22✔
1031
    fprintf(fpSpyFile, "%s.%s()\n", OGRAPISpyGetLayerVar(hLayer).c_str(),
22✔
1032
            pszMethod);
1033
    OGRAPISpyFileClose();
22✔
1034
}
22✔
1035

1036
void OGRAPISpy_L_StartTransaction(OGRLayerH hLayer)
2✔
1037
{
1038
    OGRAPISpy_L_Op(hLayer, "StartTransaction");
2✔
1039
}
2✔
1040

1041
void OGRAPISpy_L_CommitTransaction(OGRLayerH hLayer)
2✔
1042
{
1043
    OGRAPISpy_L_Op(hLayer, "CommitTransaction");
2✔
1044
}
2✔
1045

1046
void OGRAPISpy_L_RollbackTransaction(OGRLayerH hLayer)
2✔
1047
{
1048
    OGRAPISpy_L_Op(hLayer, "RollbackTransaction");
2✔
1049
}
2✔
1050

1051
void OGRAPISpy_L_GetLayerDefn(OGRLayerH hLayer)
15✔
1052
{
1053
    if (hLayer != hLayerGetLayerDefn)
15✔
1054
    {
1055
        OGRAPISpyFlushDefered();
13✔
1056
        hLayerGetLayerDefn = hLayer;
13✔
1057
        OGRAPISpyFileClose();
13✔
1058
    }
1059
}
15✔
1060

1061
void OGRAPISpy_L_GetSpatialRef(OGRLayerH hLayer)
2✔
1062
{
1063
    OGRAPISpy_L_Op(hLayer, "GetSpatialRef");
2✔
1064
}
2✔
1065

1066
void OGRAPISpy_L_GetSpatialFilter(OGRLayerH hLayer)
2✔
1067
{
1068
    OGRAPISpy_L_Op(hLayer, "GetSpatialFilter");
2✔
1069
}
2✔
1070

1071
void OGRAPISpy_L_ResetReading(OGRLayerH hLayer)
2✔
1072
{
1073
    OGRAPISpy_L_Op(hLayer, "ResetReading");
2✔
1074
}
2✔
1075

1076
void OGRAPISpy_L_SyncToDisk(OGRLayerH hLayer)
2✔
1077
{
1078
    OGRAPISpy_L_Op(hLayer, "SyncToDisk");
2✔
1079
}
2✔
1080

1081
void OGRAPISpy_L_GetFIDColumn(OGRLayerH hLayer)
2✔
1082
{
1083
    OGRAPISpy_L_Op(hLayer, "GetFIDColumn");
2✔
1084
}
2✔
1085

1086
void OGRAPISpy_L_GetGeometryColumn(OGRLayerH hLayer)
2✔
1087
{
1088
    OGRAPISpy_L_Op(hLayer, "GetGeometryColumn");
2✔
1089
}
2✔
1090

1091
void OGRAPISpy_L_GetName(OGRLayerH hLayer)
2✔
1092
{
1093
    OGRAPISpy_L_Op(hLayer, "GetName");
2✔
1094
}
2✔
1095

1096
void OGRAPISpy_L_GetGeomType(OGRLayerH hLayer)
2✔
1097
{
1098
    OGRAPISpy_L_Op(hLayer, "GetGeomType");
2✔
1099
}
2✔
1100

1101
void OGRAPISpy_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
2✔
1102
                                int bExactMatch)
1103
{
1104
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1105
    OGRAPISpyFlushDefered();
2✔
1106
    fprintf(fpSpyFile, "%s.FindFieldIndex(%s, %d)\n",
4✔
1107
            OGRAPISpyGetLayerVar(hLayer).c_str(),
4✔
1108
            OGRAPISpyGetString(pszFieldName).c_str(), bExactMatch);
4✔
1109
    OGRAPISpyFileClose();
2✔
1110
}
2✔
1111

1112
void OGRAPISpy_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
2✔
1113
{
1114
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1115
    OGRAPISpyFlushDefered();
2✔
1116
    fprintf(fpSpyFile, "%s.TestCapability(%s)\n",
4✔
1117
            OGRAPISpyGetLayerVar(hLayer).c_str(),
4✔
1118
            OGRAPISpyGetString(pszCap).c_str());
4✔
1119
    OGRAPISpyFileClose();
2✔
1120
}
2✔
1121

1122
void OGRAPISpy_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
4✔
1123
{
1124
    CPLMutexHolderD(&hOGRAPISpyMutex);
8✔
1125
    OGRAPISpyFlushDefered();
4✔
1126
    fprintf(fpSpyFile, "%s.SetSpatialFilter(%s)\n",
8✔
1127
            OGRAPISpyGetLayerVar(hLayer).c_str(),
8✔
1128
            OGRAPISpyGetGeom(hGeom).c_str());
8✔
1129
    OGRAPISpyFileClose();
4✔
1130
}
4✔
1131

1132
void OGRAPISpy_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
2✔
1133
                                    OGRGeometryH hGeom)
1134
{
1135
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1136
    OGRAPISpyFlushDefered();
2✔
1137
    fprintf(fpSpyFile, "%s.SetSpatialFilter(%d, %s)\n",
4✔
1138
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField,
4✔
1139
            OGRAPISpyGetGeom(hGeom).c_str());
4✔
1140
    OGRAPISpyFileClose();
2✔
1141
}
2✔
1142

1143
void OGRAPISpy_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX,
2✔
1144
                                      double dfMinY, double dfMaxX,
1145
                                      double dfMaxY)
1146
{
1147
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1148
    OGRAPISpyFlushDefered();
2✔
1149
    fprintf(fpSpyFile, "%s",
2✔
1150
            CPLSPrintf("%s.SetSpatialFilterRect(%.16g, %.16g, %.16g, %.16g)\n",
1151
                       OGRAPISpyGetLayerVar(hLayer).c_str(), dfMinX, dfMinY,
4✔
1152
                       dfMaxX, dfMaxY));
1153
    OGRAPISpyFileClose();
2✔
1154
}
2✔
1155

1156
void OGRAPISpy_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
2✔
1157
                                        double dfMinX, double dfMinY,
1158
                                        double dfMaxX, double dfMaxY)
1159
{
1160
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1161
    OGRAPISpyFlushDefered();
2✔
1162
    fprintf(fpSpyFile, "%s",
2✔
1163
            CPLSPrintf("%s.SetSpatialFilterRect(%d, "
1164
                       "%.16g, %.16g, %.16g, %.16g)\n",
1165
                       OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, dfMinX,
4✔
1166
                       dfMinY, dfMaxX, dfMaxY));
1167
    OGRAPISpyFileClose();
2✔
1168
}
2✔
1169

1170
void OGRAPISpy_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
2✔
1171
{
1172
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1173
    OGRAPISpyFlushDefered();
2✔
1174
    fprintf(fpSpyFile, "%s.DeleteFeature(" CPL_FRMT_GIB ")\n",
2✔
1175
            OGRAPISpyGetLayerVar(hLayer).c_str(), nFID);
4✔
1176
    OGRAPISpyFileClose();
2✔
1177
}
2✔
1178

1179
void OGRAPISpy_L_SetIgnoredFields(OGRLayerH hLayer,
2✔
1180
                                  const char **papszIgnoredFields)
1181
{
1182
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1183
    OGRAPISpyFlushDefered();
2✔
1184
    fprintf(
4✔
1185
        fpSpyFile, "%s.SetIgnoredFields(%s)\n",
1186
        OGRAPISpyGetLayerVar(hLayer).c_str(),
4✔
1187
        OGRAPISpyGetOptions(const_cast<char **>(papszIgnoredFields)).c_str());
4✔
1188
    OGRAPISpyFileClose();
2✔
1189
}
2✔
1190

1191
void OGRAPISpy_FD_GetGeomType(OGRFeatureDefnH hDefn)
2✔
1192
{
1193
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1194
    OGRAPISpyFlushDefered();
2✔
1195
    fprintf(fpSpyFile, "%s.GetGeomType()\n",
2✔
1196
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
4✔
1197
    OGRAPISpyFileClose();
2✔
1198
}
2✔
1199

1200
void OGRAPISpy_FD_GetFieldCount(OGRFeatureDefnH hDefn)
6✔
1201
{
1202
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
1203
    if (hLayerGetLayerDefn != nullptr &&
10✔
1204
        OGRFeatureDefn::ToHandle(
4✔
1205
            OGRLayer::FromHandle(hLayerGetLayerDefn)->GetLayerDefn()) == hDefn)
4✔
1206
    {
1207
        bDeferGetFieldCount = true;
4✔
1208
    }
1209
    else
1210
    {
1211
        OGRAPISpyFlushDefered();
2✔
1212
        fprintf(fpSpyFile, "%s.GetFieldCount()\n",
2✔
1213
                OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
4✔
1214
        OGRAPISpyFileClose();
2✔
1215
    }
1216
}
6✔
1217

1218
void OGRAPISpy_FD_GetFieldDefn(OGRFeatureDefnH hDefn, int iField,
2✔
1219
                               OGRFieldDefnH hField)
1220
{
1221
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1222
    OGRAPISpyFlushDefered();
2✔
1223
    fprintf(fpSpyFile, "%s_fielddefn%d = %s.GetFieldDefn(%d)\n",
4✔
1224
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField,
4✔
1225
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField);
4✔
1226

1227
    std::map<OGRFieldDefnH, CPLString>::iterator oIter =
1228
        oGlobalMapFieldDefn.find(hField);
2✔
1229
    if (oIter == oGlobalMapFieldDefn.end())
2✔
1230
    {
1231
        oMapFDefn[hDefn].oMapFieldDefn[hField] = iField;
2✔
1232
        oGlobalMapFieldDefn[hField] =
2✔
1233
            CPLSPrintf("%s_fielddefn%d",
1234
                       OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField);
4✔
1235
    }
1236

1237
    OGRAPISpyFileClose();
2✔
1238
}
2✔
1239

1240
void OGRAPISpy_FD_GetFieldIndex(OGRFeatureDefnH hDefn, const char *pszFieldName)
2✔
1241
{
1242
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1243
    OGRAPISpyFlushDefered();
2✔
1244
    fprintf(fpSpyFile, "%s.GetFieldIndex(%s)\n",
4✔
1245
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
4✔
1246
            OGRAPISpyGetString(pszFieldName).c_str());
4✔
1247
    OGRAPISpyFileClose();
2✔
1248
}
2✔
1249

1250
void OGRAPISpy_Fld_GetXXXX(OGRFieldDefnH hField, const char *pszOp)
6✔
1251
{
1252
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
1253
    OGRAPISpyFlushDefered();
6✔
1254
    fprintf(fpSpyFile, "%s.%s()\n", oGlobalMapFieldDefn[hField].c_str(), pszOp);
6✔
1255
    OGRAPISpyFileClose();
6✔
1256
}
6✔
1257

1258
void OGRAPISpy_FD_GetGeomFieldCount(OGRFeatureDefnH hDefn)
2✔
1259
{
1260
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1261
    OGRAPISpyFlushDefered();
2✔
1262
    fprintf(fpSpyFile, "%s.GetGeomFieldCount()\n",
2✔
1263
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
4✔
1264
    OGRAPISpyFileClose();
2✔
1265
}
2✔
1266

1267
void OGRAPISpy_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField,
2✔
1268
                                   OGRGeomFieldDefnH hGeomField)
1269
{
1270
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1271
    OGRAPISpyFlushDefered();
2✔
1272
    fprintf(fpSpyFile, "%s_geomfielddefn%d = %s.GetGeomFieldDefn(%d)\n",
4✔
1273
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField,
4✔
1274
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField);
4✔
1275

1276
    std::map<OGRGeomFieldDefnH, CPLString>::iterator oIter =
1277
        oGlobalMapGeomFieldDefn.find(hGeomField);
2✔
1278
    if (oIter == oGlobalMapGeomFieldDefn.end())
2✔
1279
    {
1280
        oMapFDefn[hDefn].oMapGeomFieldDefn[hGeomField] = iGeomField;
2✔
1281
        oGlobalMapGeomFieldDefn[hGeomField] =
2✔
1282
            CPLSPrintf("%s_geomfielddefn%d",
1283
                       OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField);
4✔
1284
    }
1285

1286
    OGRAPISpyFileClose();
2✔
1287
}
2✔
1288

1289
void OGRAPISpy_FD_GetGeomFieldIndex(OGRFeatureDefnH hDefn,
2✔
1290
                                    const char *pszFieldName)
1291
{
1292
    CPLMutexHolderD(&hOGRAPISpyMutex);
4✔
1293
    OGRAPISpyFlushDefered();
2✔
1294
    fprintf(fpSpyFile, "%s.GetGeomFieldIndex(%s)\n",
4✔
1295
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
4✔
1296
            OGRAPISpyGetString(pszFieldName).c_str());
4✔
1297
    OGRAPISpyFileClose();
2✔
1298
}
2✔
1299

1300
void OGRAPISpy_GFld_GetXXXX(OGRGeomFieldDefnH hGeomField, const char *pszOp)
6✔
1301
{
1302
    CPLMutexHolderD(&hOGRAPISpyMutex);
12✔
1303
    OGRAPISpyFlushDefered();
6✔
1304
    fprintf(fpSpyFile, "%s.%s()\n", oGlobalMapGeomFieldDefn[hGeomField].c_str(),
6✔
1305
            pszOp);
1306
    OGRAPISpyFileClose();
6✔
1307
}
6✔
1308

1309
void OGRAPISPYCPLSetConfigOption(const char *pszKey, const char *pszValue)
4,735✔
1310
{
1311
    if (STARTS_WITH(pszKey, "OGR_API_SPY_") || STARTS_WITH(pszKey, "__"))
4,735✔
1312
        return;
×
1313
    if (!OGRAPISpyEnabled())
4,735✔
1314
        return;
4,733✔
1315
    OGRAPISpyFlushDefered();
2✔
1316
    if (pszValue)
2✔
1317
    {
1318
        fprintf(fpSpyFile, "gdal.SetConfigOption(%s, %s)\n",
4✔
1319
                OGRAPISpyGetString(pszKey).c_str(),
4✔
1320
                OGRAPISpyGetString(pszValue).c_str());
4✔
1321
    }
1322
    else
1323
    {
1324
        fprintf(fpSpyFile, "gdal.SetConfigOption(%s, None)\n",
×
1325
                OGRAPISpyGetString(pszKey).c_str());
×
1326
    }
1327
    OGRAPISpyFileClose();
2✔
1328
}
1329

1330
void OGRAPISPYCPLSetThreadLocalConfigOption(const char *pszKey,
59,076✔
1331
                                            const char *pszValue)
1332
{
1333
    if (STARTS_WITH(pszKey, "OGR_API_SPY_") || STARTS_WITH(pszKey, "__"))
59,076✔
1334
        return;
17✔
1335
    if (!OGRAPISpyEnabled())
59,059✔
1336
        return;
59,035✔
UNCOV
1337
    OGRAPISpyFlushDefered();
×
1338
    if (pszValue)
×
1339
    {
1340
        fprintf(fpSpyFile,
×
1341
                "gdal.SetConfigOption(%s, %s) # SetThreadLocalConfigOption "
1342
                "actually\n",
1343
                OGRAPISpyGetString(pszKey).c_str(),
×
1344
                OGRAPISpyGetString(pszValue).c_str());
×
1345
    }
1346
    else
1347
    {
1348
        fprintf(fpSpyFile,
×
1349
                "gdal.SetConfigOption(%s, None) # SetThreadLocalConfigOption "
1350
                "actually\n",
1351
                OGRAPISpyGetString(pszKey).c_str());
×
1352
    }
1353
    OGRAPISpyFileClose();
×
1354
}
1355

1356
#endif  // OGRAPISPY_ENABLED
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc