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

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

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

87.8
/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()
940✔
133
{
134
    if (hOGRAPISpyMutex)
940✔
135
    {
136
        CPLDestroyMutex(hOGRAPISpyMutex);
×
137
        hOGRAPISpyMutex = nullptr;
×
138

139
        aoSetCreatedDS.clear();
×
140
        oMapFDefn.clear();
×
141
        oGlobalMapGeomFieldDefn.clear();
×
142
        oGlobalMapFieldDefn.clear();
×
143
    }
144
}
940✔
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()
89,094✔
166
{
167
    if (bOGRAPISpyEnabled < 0)
89,094✔
168
        return false;
8✔
169

170
    const char *pszSpyFile = CPLGetConfigOption("OGR_API_SPY_FILE", nullptr);
89,086✔
171
    bOGRAPISpyEnabled = pszSpyFile != nullptr;
89,126✔
172
    if (!bOGRAPISpyEnabled)
89,126✔
173
    {
174
        osSpyFile.resize(0);
89,075✔
175
        aoSetCreatedDS.clear();
89,075✔
176
        return false;
88,974✔
177
    }
178
    if (!osSpyFile.empty())
51✔
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,814✔
455
{
456
    if (!OGRAPISpyEnabled() || !bUpdate || osSnapshotPath.empty() ||
11,819✔
457
        aoSetCreatedDS.find(pszName) != aoSetCreatedDS.end())
11,819✔
458
        return -1;
11,811✔
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 = CPLFormFilename(
×
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 = CPLFormFilename(osBaseDir, "source", nullptr);
1✔
488
            VSIMkdir(osSrcDir, 0777);
1✔
489
            osWorkingDir = CPLFormFilename(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 = CPLFormFilename(
503
                    osSrcDir, CPLGetFilename(*papszIter), nullptr);
6✔
504
                CPLString osSnapshotWorkingFile = CPLFormFilename(
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,814✔
521
                   GDALDatasetH *phDS)
522
{
523
    if (!OGRAPISpyEnabled())
11,814✔
524
        return;
11,807✔
525
    CPLMutexHolderD(&hOGRAPISpyMutex);
14✔
526
    OGRAPISpyFlushDefered();
7✔
527

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1355
#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