Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ograpispy.cpp
Line
Count
Source
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
0
    LayerDescription() = default;
50
51
0
    explicit LayerDescription(int iLayerIn) : iLayer(iLayerIn)
52
0
    {
53
0
    }
54
};
55
56
class DatasetDescription
57
{
58
  public:
59
    int iDS = -1;
60
    std::map<OGRLayerH, LayerDescription> oMapLayer{};
61
62
0
    DatasetDescription() = default;
63
64
0
    explicit DatasetDescription(int iDSIn) : iDS(iDSIn)
65
0
    {
66
0
    }
67
68
0
    DatasetDescription &operator=(DatasetDescription &&) = default;
69
    ~DatasetDescription();
70
};
71
72
class FeatureDefnDescription
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
0
    FeatureDefnDescription() = default;
81
82
    FeatureDefnDescription(OGRFeatureDefnH hFDefnIn, int iUniqueNumberIn)
83
0
        : hFDefn(hFDefnIn), iUniqueNumber(iUniqueNumberIn)
84
0
    {
85
0
    }
86
87
    FeatureDefnDescription(const FeatureDefnDescription &) = default;
88
0
    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()
108
0
{
109
0
    {
110
0
        std::map<OGRGeomFieldDefnH, int>::iterator oIter =
111
0
            oMapGeomFieldDefn.begin();
112
0
        for (; oIter != oMapGeomFieldDefn.end(); ++oIter)
113
0
            oGlobalMapGeomFieldDefn.erase(oIter->first);
114
0
    }
115
0
    {
116
0
        std::map<OGRFieldDefnH, int>::iterator oIter = oMapFieldDefn.begin();
117
0
        for (; oIter != oMapFieldDefn.end(); ++oIter)
118
0
            oGlobalMapFieldDefn.erase(oIter->first);
119
0
    }
120
0
}
121
122
DatasetDescription::~DatasetDescription()
123
0
{
124
0
    {
125
0
        std::map<OGRLayerH, LayerDescription>::iterator oIter =
126
0
            oMapLayer.begin();
127
0
        for (; oIter != oMapLayer.end(); ++oIter)
128
0
            oGlobalMapLayer.erase(oIter->first);
129
0
    }
130
0
}
131
132
void OGRAPISpyDestroyMutex()
133
0
{
134
0
    if (hOGRAPISpyMutex)
135
0
    {
136
0
        CPLDestroyMutex(hOGRAPISpyMutex);
137
0
        hOGRAPISpyMutex = nullptr;
138
139
0
        aoSetCreatedDS.clear();
140
0
        oMapFDefn.clear();
141
0
        oGlobalMapGeomFieldDefn.clear();
142
0
        oGlobalMapFieldDefn.clear();
143
0
    }
144
0
}
145
146
static void OGRAPISpyFileReopen()
147
5.80k
{
148
5.80k
    if (fpSpyFile == nullptr)
149
1.53k
    {
150
1.53k
        fpSpyFile = fopen(osSpyFile, "ab");
151
1.53k
        if (fpSpyFile == nullptr)
152
0
            fpSpyFile = stderr;
153
1.53k
    }
154
5.80k
}
155
156
static void OGRAPISpyFileClose()
157
5.80k
{
158
5.80k
    if (fpSpyFile != stdout && fpSpyFile != stderr)
159
1.62k
    {
160
1.62k
        fclose(fpSpyFile);
161
1.62k
        fpSpyFile = nullptr;
162
1.62k
    }
163
5.80k
}
164
165
static bool OGRAPISpyEnabled()
166
8.94k
{
167
8.94k
    if (bOGRAPISpyEnabled < 0)
168
0
        return false;
169
170
8.94k
    const char *pszSpyFile = CPLGetConfigOption("OGR_API_SPY_FILE", nullptr);
171
8.94k
    bOGRAPISpyEnabled = pszSpyFile != nullptr;
172
8.94k
    if (!bOGRAPISpyEnabled)
173
3.13k
    {
174
3.13k
        osSpyFile.resize(0);
175
3.13k
        aoSetCreatedDS.clear();
176
3.13k
        return false;
177
3.13k
    }
178
5.80k
    if (!osSpyFile.empty())
179
3.66k
        return true;
180
181
2.14k
    CPLMutexHolderD(&hOGRAPISpyMutex);
182
2.14k
    if (!osSpyFile.empty())
183
0
        return true;
184
185
2.14k
    osSpyFile = pszSpyFile;
186
187
2.14k
    const char *pszSnapshotPath =
188
2.14k
        CPLGetConfigOption("OGR_API_SPY_SNAPSHOT_PATH", ".");
189
2.14k
    if (EQUAL(pszSnapshotPath, "NO"))
190
2
        osSnapshotPath = "";
191
2.13k
    else
192
2.13k
        osSnapshotPath = pszSnapshotPath;
193
194
2.14k
    if (EQUAL(pszSpyFile, "stdout"))
195
1
        fpSpyFile = stdout;
196
2.13k
    else if (EQUAL(pszSpyFile, "stderr"))
197
1
        fpSpyFile = stderr;
198
2.13k
    else
199
2.13k
        fpSpyFile = fopen(pszSpyFile, "wb");
200
2.14k
    if (fpSpyFile == nullptr)
201
2.04k
        fpSpyFile = stderr;
202
203
2.14k
    assert(fpSpyFile != nullptr);
204
2.14k
    fprintf(fpSpyFile,
205
2.14k
            "# This file is generated by the OGR_API_SPY mechanism.\n");
206
2.14k
    fprintf(fpSpyFile, "import os\n");
207
2.14k
    fprintf(fpSpyFile, "import shutil\n");
208
2.14k
    fprintf(fpSpyFile, "from osgeo import gdal\n");
209
2.14k
    fprintf(fpSpyFile, "from osgeo import ogr\n");
210
2.14k
    fprintf(fpSpyFile, "from osgeo import osr\n");
211
    // To make pyflakes happy in case it is unused later.
212
2.14k
    fprintf(fpSpyFile, "os.access\n");
213
2.14k
    fprintf(fpSpyFile, "shutil.copy\n");  // Same here.
214
2.14k
    fprintf(fpSpyFile, "\n");
215
216
2.14k
    return true;
217
2.14k
}
218
219
static CPLString OGRAPISpyGetOptions(CSLConstList papszOptions)
220
0
{
221
0
    if (papszOptions == nullptr)
222
0
    {
223
0
        return "[]";
224
0
    }
225
226
0
    CPLString options = "[";
227
0
    for (CSLConstList papszIter = papszOptions; *papszIter != nullptr;
228
0
         papszIter++)
229
0
    {
230
0
        if (papszIter != papszOptions)
231
0
            options += ", ";
232
0
        options += "'";
233
0
        options += *papszIter;
234
0
        options += "'";
235
0
    }
236
0
    options += "]";
237
238
0
    return options;
239
0
}
240
241
static CPLString OGRAPISpyGetString(const char *pszStr)
242
11.6k
{
243
11.6k
    if (pszStr == nullptr)
244
0
        return "None";
245
11.6k
    CPLString osRet = "'";
246
213k
    while (*pszStr)
247
201k
    {
248
201k
        if (*pszStr == '\'')
249
1.44k
            osRet += "\\'";
250
200k
        else if (*pszStr == '\\')
251
499
            osRet += "\\\\";
252
199k
        else
253
199k
            osRet += *pszStr;
254
201k
        pszStr++;
255
201k
    }
256
11.6k
    osRet += "'";
257
11.6k
    return osRet;
258
11.6k
}
259
260
static CPLString OGRAPISpyGetDSVar(GDALDatasetH hDS)
261
0
{
262
0
    if (hDS && oMapDS.find(hDS) == oMapDS.end())
263
0
    {
264
0
        int i = 1;
265
0
        while (oSetDSIndex.find(i) != oSetDSIndex.end())
266
0
            i++;
267
0
        oMapDS[hDS] = DatasetDescription(i);
268
0
        oSetDSIndex.insert(i);
269
0
    }
270
0
    return CPLSPrintf("ds%d", hDS ? oMapDS[hDS].iDS : 0);
271
0
}
272
273
static CPLString OGRAPISpyGetLayerVar(OGRLayerH hLayer)
274
0
{
275
0
    return oGlobalMapLayer[hLayer];
276
0
}
277
278
static CPLString OGRAPISpyGetAndRegisterLayerVar(GDALDatasetH hDS,
279
                                                 OGRLayerH hLayer)
280
0
{
281
0
    DatasetDescription &dd = oMapDS[hDS];
282
0
    if (hLayer && dd.oMapLayer.find(hLayer) == dd.oMapLayer.end())
283
0
    {
284
0
        const int i = static_cast<int>(dd.oMapLayer.size()) + 1;
285
0
        dd.oMapLayer[hLayer] = LayerDescription(i);
286
0
        oGlobalMapLayer[hLayer] =
287
0
            OGRAPISpyGetDSVar(hDS) + "_" + CPLSPrintf("lyr%d", i);
288
0
    }
289
290
0
    return OGRAPISpyGetDSVar(hDS) + "_" +
291
0
           CPLSPrintf("lyr%d", hLayer ? dd.oMapLayer[hLayer].iLayer : 0);
292
0
}
293
294
static CPLString OGRAPISpyGetSRS(OGRSpatialReferenceH hSpatialRef)
295
0
{
296
0
    if (hSpatialRef == nullptr)
297
0
        return "None";
298
299
0
    char *pszWKT = nullptr;
300
0
    OGRSpatialReference::FromHandle(hSpatialRef)->exportToWkt(&pszWKT);
301
0
    const char *pszRet =
302
0
        CPLSPrintf(R"(osr.SpatialReference("""%s"""))", pszWKT);
303
0
    CPLFree(pszWKT);
304
0
    return pszRet;
305
0
}
306
307
static CPLString OGRAPISpyGetGeom(OGRGeometryH hGeom)
308
0
{
309
0
    if (hGeom == nullptr)
310
0
        return "None";
311
312
0
    char *pszWKT = nullptr;
313
0
    OGRGeometry::FromHandle(hGeom)->exportToWkt(&pszWKT);
314
0
    const char *pszRet = CPLSPrintf("ogr.CreateGeometryFromWkt('%s')", pszWKT);
315
0
    CPLFree(pszWKT);
316
0
    return pszRet;
317
0
}
318
319
#define casePrefixOgrDot(x)                                                    \
320
0
    case x:                                                                    \
321
0
        return "ogr." #x;
322
323
static CPLString OGRAPISpyGetGeomType(OGRwkbGeometryType eType)
324
0
{
325
0
    switch (eType)
326
0
    {
327
0
        casePrefixOgrDot(wkbUnknown) casePrefixOgrDot(wkbPoint) casePrefixOgrDot(wkbLineString) casePrefixOgrDot(
328
0
            wkbPolygon) casePrefixOgrDot(wkbMultiPoint) casePrefixOgrDot(wkbMultiLineString)
329
0
            casePrefixOgrDot(wkbMultiPolygon) casePrefixOgrDot(wkbGeometryCollection) casePrefixOgrDot(
330
0
                wkbCircularString) casePrefixOgrDot(wkbCompoundCurve) casePrefixOgrDot(wkbCurvePolygon)
331
0
                casePrefixOgrDot(wkbMultiCurve) casePrefixOgrDot(wkbMultiSurface) casePrefixOgrDot(
332
0
                    wkbCurve) casePrefixOgrDot(wkbSurface) casePrefixOgrDot(wkbNone) casePrefixOgrDot(wkbLinearRing)
333
0
                    casePrefixOgrDot(wkbCircularStringZ) casePrefixOgrDot(wkbCompoundCurveZ) casePrefixOgrDot(
334
0
                        wkbCurvePolygonZ) casePrefixOgrDot(wkbMultiCurveZ) casePrefixOgrDot(wkbMultiSurfaceZ)
335
0
                        casePrefixOgrDot(wkbCurveZ) casePrefixOgrDot(wkbSurfaceZ) casePrefixOgrDot(
336
0
                            wkbPoint25D) casePrefixOgrDot(wkbLineString25D) casePrefixOgrDot(wkbPolygon25D)
337
0
                            casePrefixOgrDot(wkbMultiPoint25D) casePrefixOgrDot(wkbMultiLineString25D) casePrefixOgrDot(
338
0
                                wkbMultiPolygon25D) casePrefixOgrDot(wkbGeometryCollection25D)
339
0
                                casePrefixOgrDot(wkbPolyhedralSurface) casePrefixOgrDot(
340
0
                                    wkbTIN) casePrefixOgrDot(wkbTriangle) casePrefixOgrDot(wkbPolyhedralSurfaceZ)
341
0
                                    casePrefixOgrDot(wkbTINZ) casePrefixOgrDot(wkbTriangleZ) casePrefixOgrDot(
342
0
                                        wkbPointM) casePrefixOgrDot(wkbLineStringM) casePrefixOgrDot(wkbPolygonM)
343
0
                                        casePrefixOgrDot(wkbMultiPointM) casePrefixOgrDot(
344
0
                                            wkbMultiLineStringM) casePrefixOgrDot(wkbMultiPolygonM)
345
0
                                            casePrefixOgrDot(wkbGeometryCollectionM) casePrefixOgrDot(
346
0
                                                wkbCircularStringM) casePrefixOgrDot(wkbCompoundCurveM)
347
0
                                                casePrefixOgrDot(wkbCurvePolygonM) casePrefixOgrDot(
348
0
                                                    wkbMultiCurveM) casePrefixOgrDot(wkbMultiSurfaceM)
349
0
                                                    casePrefixOgrDot(wkbCurveM) casePrefixOgrDot(
350
0
                                                        wkbSurfaceM) casePrefixOgrDot(wkbPolyhedralSurfaceM)
351
0
                                                        casePrefixOgrDot(wkbTINM) casePrefixOgrDot(
352
0
                                                            wkbTriangleM) casePrefixOgrDot(wkbPointZM)
353
0
                                                            casePrefixOgrDot(wkbLineStringZM) casePrefixOgrDot(
354
0
                                                                wkbPolygonZM) casePrefixOgrDot(wkbMultiPointZM)
355
0
                                                                casePrefixOgrDot(wkbMultiLineStringZM) casePrefixOgrDot(
356
0
                                                                    wkbMultiPolygonZM) casePrefixOgrDot(wkbGeometryCollectionZM)
357
0
                                                                    casePrefixOgrDot(wkbCircularStringZM) casePrefixOgrDot(
358
0
                                                                        wkbCompoundCurveZM)
359
0
                                                                        casePrefixOgrDot(wkbCurvePolygonZM) casePrefixOgrDot(
360
0
                                                                            wkbMultiCurveZM)
361
0
                                                                            casePrefixOgrDot(
362
0
                                                                                wkbMultiSurfaceZM)
363
0
                                                                                casePrefixOgrDot(
364
0
                                                                                    wkbCurveZM)
365
0
                                                                                    casePrefixOgrDot(
366
0
                                                                                        wkbSurfaceZM)
367
0
                                                                                        casePrefixOgrDot(
368
0
                                                                                            wkbPolyhedralSurfaceZM)
369
0
                                                                                            casePrefixOgrDot(
370
0
                                                                                                wkbTriangleZM)
371
0
                                                                                                casePrefixOgrDot(
372
0
                                                                                                    wkbTINZM)
373
0
    }
374
0
    return "error";
375
0
}
376
377
static CPLString OGRAPISpyGetFieldType(OGRFieldType eType)
378
0
{
379
0
    switch (eType)
380
0
    {
381
0
        casePrefixOgrDot(OFTInteger) casePrefixOgrDot(OFTInteger64)
382
0
            casePrefixOgrDot(OFTIntegerList) casePrefixOgrDot(OFTInteger64List)
383
0
                casePrefixOgrDot(OFTReal) casePrefixOgrDot(OFTRealList)
384
0
                    casePrefixOgrDot(OFTString) casePrefixOgrDot(OFTStringList)
385
0
                        casePrefixOgrDot(OFTWideString)
386
0
                            casePrefixOgrDot(OFTWideStringList)
387
0
                                casePrefixOgrDot(OFTBinary)
388
0
                                    casePrefixOgrDot(OFTDate)
389
0
                                        casePrefixOgrDot(OFTTime)
390
0
                                            casePrefixOgrDot(OFTDateTime)
391
0
    }
392
0
    return "error";
393
0
}
394
395
#undef casePrefixOgrDot
396
397
static CPLString OGRAPISpyGetFeatureDefnVar(OGRFeatureDefnH hFDefn)
398
0
{
399
0
    std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter =
400
0
        oMapFDefn.find(hFDefn);
401
0
    int i = 0;
402
0
    if (oIter == oMapFDefn.end())
403
0
    {
404
0
        i = static_cast<int>(oMapFDefn.size()) + 1;
405
0
        oMapFDefn[hFDefn] = FeatureDefnDescription(hFDefn, i);
406
407
        // So that we can check when they are no longer used.
408
0
        OGRFeatureDefn::FromHandle(hFDefn)->Reference();
409
0
    }
410
0
    else
411
0
    {
412
0
        i = oIter->second.iUniqueNumber;
413
0
    }
414
0
    return CPLSPrintf("fdefn%d", i);
415
0
}
416
417
static void OGRAPISpyFlushDefered()
418
5.80k
{
419
5.80k
    OGRAPISpyFileReopen();
420
5.80k
    if (hLayerGetLayerDefn != nullptr)
421
0
    {
422
0
        OGRFeatureDefnH hDefn = OGRFeatureDefn::ToHandle(
423
0
            OGRLayer::FromHandle(hLayerGetLayerDefn)->GetLayerDefn());
424
0
        fprintf(fpSpyFile, "%s = %s.GetLayerDefn()\n",
425
0
                OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
426
0
                OGRAPISpyGetLayerVar(hLayerGetLayerDefn).c_str());
427
428
0
        if (bDeferGetFieldCount)
429
0
        {
430
0
            fprintf(fpSpyFile, "%s.GetFieldCount()\n",
431
0
                    OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
432
0
            bDeferGetFieldCount = false;
433
0
        }
434
435
0
        hLayerGetLayerDefn = nullptr;
436
0
    }
437
438
5.80k
    if (nGetNextFeatureCalls == 1)
439
0
    {
440
0
        fprintf(fpSpyFile, "%s.GetNextFeature()\n",
441
0
                OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
442
0
        hLayerGetNextFeature = nullptr;
443
0
        nGetNextFeatureCalls = 0;
444
0
    }
445
5.80k
    else if (nGetNextFeatureCalls > 0)
446
0
    {
447
0
        fprintf(fpSpyFile, "for i in range(%d):\n", nGetNextFeatureCalls);
448
0
        fprintf(fpSpyFile, "    %s.GetNextFeature()\n",
449
0
                OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
450
0
        hLayerGetNextFeature = nullptr;
451
0
        nGetNextFeatureCalls = 0;
452
0
    }
453
5.80k
}
454
455
int OGRAPISpyOpenTakeSnapshot(const char *pszName, int bUpdate)
456
0
{
457
0
    if (!OGRAPISpyEnabled() || !bUpdate || osSnapshotPath.empty() ||
458
0
        aoSetCreatedDS.find(pszName) != aoSetCreatedDS.end())
459
0
        return -1;
460
0
    OGRAPISpyFlushDefered();
461
462
0
    VSIStatBufL sStat;
463
0
    if (VSIStatL(pszName, &sStat) == 0)
464
0
    {
465
0
        bOGRAPISpyEnabled = -1;
466
0
        GDALDatasetH hDS =
467
0
            GDALOpenEx(pszName, GDAL_OF_VECTOR, nullptr, nullptr, nullptr);
468
0
        char **papszFileList =
469
0
            hDS ? GDALDataset::FromHandle(hDS)->GetFileList() : nullptr;
470
0
        GDALClose(hDS);
471
0
        bOGRAPISpyEnabled = true;
472
0
        if (papszFileList)
473
0
        {
474
0
            int i = 1;
475
0
            CPLString osBaseDir;
476
0
            CPLString osSrcDir;
477
0
            CPLString osWorkingDir;
478
0
            while (true)
479
0
            {
480
0
                osBaseDir = CPLFormFilenameSafe(
481
0
                    osSnapshotPath, CPLSPrintf("snapshot_%d", i), nullptr);
482
0
                if (VSIStatL(osBaseDir, &sStat) != 0)
483
0
                    break;
484
0
                i++;
485
0
            }
486
0
            VSIMkdir(osSnapshotPath, 0777);
487
0
            VSIMkdir(osBaseDir, 0777);
488
0
            osSrcDir = CPLFormFilenameSafe(osBaseDir, "source", nullptr);
489
0
            VSIMkdir(osSrcDir, 0777);
490
0
            osWorkingDir = CPLFormFilenameSafe(osBaseDir, "working", nullptr);
491
0
            VSIMkdir(osWorkingDir, 0777);
492
493
0
            OGRAPISpyFileReopen();
494
0
            fprintf(fpSpyFile, "# Take snapshot of %s\n", pszName);
495
0
            fprintf(fpSpyFile, "try:\n");
496
0
            fprintf(fpSpyFile, "    shutil.rmtree('%s')\n",
497
0
                    osWorkingDir.c_str());
498
0
            fprintf(fpSpyFile, "except:\n");
499
0
            fprintf(fpSpyFile, "    pass\n");
500
0
            fprintf(fpSpyFile, "os.mkdir('%s')\n", osWorkingDir.c_str());
501
0
            for (char **papszIter = papszFileList; *papszIter; papszIter++)
502
0
            {
503
0
                CPLString osSnapshotSrcFile = CPLFormFilenameSafe(
504
0
                    osSrcDir, CPLGetFilename(*papszIter), nullptr);
505
0
                CPLString osSnapshotWorkingFile = CPLFormFilenameSafe(
506
0
                    osWorkingDir, CPLGetFilename(*papszIter), nullptr);
507
0
                CPL_IGNORE_RET_VAL(CPLCopyFile(osSnapshotSrcFile, *papszIter));
508
0
                CPL_IGNORE_RET_VAL(
509
0
                    CPLCopyFile(osSnapshotWorkingFile, *papszIter));
510
0
                fprintf(fpSpyFile, "shutil.copy('%s', '%s')\n",
511
0
                        osSnapshotSrcFile.c_str(),
512
0
                        osSnapshotWorkingFile.c_str());
513
0
            }
514
0
            CSLDestroy(papszFileList);
515
0
            return i;
516
0
        }
517
0
    }
518
0
    return -1;
519
0
}
520
521
void OGRAPISpyOpen(const char *pszName, int bUpdate, int iSnapshot,
522
                   GDALDatasetH *phDS)
523
0
{
524
0
    if (!OGRAPISpyEnabled())
525
0
        return;
526
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
527
0
    OGRAPISpyFlushDefered();
528
529
0
    CPLString osName;
530
0
    if (iSnapshot > 0)
531
0
    {
532
0
        CPLString osBaseDir = CPLFormFilenameSafe(
533
0
            osSnapshotPath, CPLSPrintf("snapshot_%d", iSnapshot), nullptr);
534
0
        CPLString osWorkingDir =
535
0
            CPLFormFilenameSafe(osBaseDir, "working", nullptr);
536
0
        osName =
537
0
            CPLFormFilenameSafe(osWorkingDir, CPLGetFilename(pszName), nullptr);
538
0
        pszName = osName.c_str();
539
540
0
        if (*phDS != nullptr)
541
0
        {
542
0
            bOGRAPISpyEnabled = -1;
543
0
            GDALClose(GDALDataset::FromHandle(*phDS));
544
0
            *phDS = GDALOpenEx(pszName, GDAL_OF_VECTOR | GDAL_OF_UPDATE,
545
0
                               nullptr, nullptr, nullptr);
546
0
            bOGRAPISpyEnabled = true;
547
0
        }
548
0
    }
549
550
0
    OGRAPISpyFileReopen();
551
0
    if (*phDS != nullptr)
552
0
        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar(*phDS).c_str());
553
0
    if (bUpdate)
554
0
        fprintf(fpSpyFile, "gdal.OpenEx(%s, gdal.OF_VECTOR | gdal.OF_UPDATE)\n",
555
0
                OGRAPISpyGetString(pszName).c_str());
556
0
    else
557
0
        fprintf(fpSpyFile, "gdal.OpenEx(%s, gdal.OF_VECTOR)\n",
558
0
                OGRAPISpyGetString(pszName).c_str());
559
0
    OGRAPISpyFileClose();
560
0
}
561
562
void OGRAPISpyPreClose(GDALDatasetH hDS)
563
0
{
564
0
    if (!OGRAPISpyEnabled())
565
0
        return;
566
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
567
0
    OGRAPISpyFlushDefered();
568
0
    fprintf(fpSpyFile, "ds%d = None\n", oMapDS[hDS].iDS);
569
0
    oSetDSIndex.erase(oMapDS[hDS].iDS);
570
0
    oMapDS.erase(hDS);
571
0
    OGRAPISpyFileClose();
572
0
}
573
574
void OGRAPISpyPostClose()
575
0
{
576
0
    {
577
0
        if (!OGRAPISpyEnabled())
578
0
            return;
579
0
        CPLMutexHolderD(&hOGRAPISpyMutex);
580
0
        std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter =
581
0
            oMapFDefn.begin();
582
0
        std::vector<OGRFeatureDefnH> oArray;
583
0
        for (; oIter != oMapFDefn.end(); ++oIter)
584
0
        {
585
0
            FeatureDefnDescription &featureDefnDescription = oIter->second;
586
0
            if (OGRFeatureDefn::FromHandle(featureDefnDescription.hFDefn)
587
0
                    ->GetReferenceCount() == 1)
588
0
            {
589
0
                oArray.push_back(featureDefnDescription.hFDefn);
590
0
            }
591
0
        }
592
0
        for (auto &hFDefn : oArray)
593
0
        {
594
0
            FeatureDefnDescription &featureDefnDescription = oMapFDefn[hFDefn];
595
0
            OGRFeatureDefn::FromHandle(featureDefnDescription.hFDefn)
596
0
                ->Release();
597
0
            featureDefnDescription.Free();
598
0
            oMapFDefn.erase(hFDefn);
599
0
        }
600
0
    }
601
0
}
602
603
void OGRAPISpyCreateDataSource(GDALDriverH hDriver, const char *pszName,
604
                               CSLConstList papszOptions, GDALDatasetH hDS)
605
0
{
606
0
    if (!OGRAPISpyEnabled())
607
0
        return;
608
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
609
0
    OGRAPISpyFlushDefered();
610
0
    if (hDS != nullptr)
611
0
        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar(hDS).c_str());
612
0
    fprintf(fpSpyFile,
613
0
            "ogr.GetDriverByName('%s').CreateDataSource(%s, options=%s)\n",
614
0
            GDALGetDriverShortName(hDriver),
615
0
            OGRAPISpyGetString(pszName).c_str(),
616
0
            OGRAPISpyGetOptions(papszOptions).c_str());
617
0
    if (hDS != nullptr)
618
0
    {
619
0
        aoSetCreatedDS.insert(pszName);
620
0
    }
621
0
    OGRAPISpyFileClose();
622
0
}
623
624
void OGRAPISpyDeleteDataSource(GDALDriverH hDriver, const char *pszName)
625
0
{
626
0
    if (!OGRAPISpyEnabled())
627
0
        return;
628
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
629
0
    OGRAPISpyFlushDefered();
630
0
    fprintf(fpSpyFile, "ogr.GetDriverByName('%s').DeleteDataSource(%s)\n",
631
0
            GDALGetDriverShortName(hDriver),
632
0
            OGRAPISpyGetString(pszName).c_str());
633
0
    aoSetCreatedDS.erase(pszName);
634
0
    OGRAPISpyFileClose();
635
0
}
636
637
void OGRAPISpy_DS_GetLayer(GDALDatasetH hDS, int iLayer, OGRLayerH hLayer)
638
0
{
639
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
640
0
    OGRAPISpyFlushDefered();
641
0
    if (hLayer != nullptr)
642
0
        fprintf(fpSpyFile,
643
0
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
644
0
    fprintf(fpSpyFile, "%s.GetLayer(%d)\n", OGRAPISpyGetDSVar(hDS).c_str(),
645
0
            iLayer);
646
0
    OGRAPISpyFileClose();
647
0
}
648
649
void OGRAPISpy_DS_GetLayerCount(GDALDatasetH hDS)
650
0
{
651
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
652
0
    OGRAPISpyFlushDefered();
653
0
    fprintf(fpSpyFile, "%s.GetLayerCount()\n", OGRAPISpyGetDSVar(hDS).c_str());
654
0
    OGRAPISpyFileClose();
655
0
}
656
657
void OGRAPISpy_DS_GetLayerByName(GDALDatasetH hDS, const char *pszLayerName,
658
                                 OGRLayerH hLayer)
659
0
{
660
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
661
0
    OGRAPISpyFlushDefered();
662
0
    if (hLayer != nullptr)
663
0
        fprintf(fpSpyFile,
664
0
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
665
0
    fprintf(fpSpyFile, "%s.GetLayerByName(%s)\n",
666
0
            OGRAPISpyGetDSVar(hDS).c_str(),
667
0
            OGRAPISpyGetString(pszLayerName).c_str());
668
0
    OGRAPISpyFileClose();
669
0
}
670
671
void OGRAPISpy_DS_ExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
672
                             OGRGeometryH hSpatialFilter,
673
                             const char *pszDialect, OGRLayerH hLayer)
674
0
{
675
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
676
0
    OGRAPISpyFlushDefered();
677
0
    if (hLayer != nullptr)
678
0
        fprintf(fpSpyFile,
679
0
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
680
0
    fprintf(fpSpyFile, "%s.ExecuteSQL(%s, %s, %s)\n",
681
0
            OGRAPISpyGetDSVar(hDS).c_str(),
682
0
            OGRAPISpyGetString(pszStatement).c_str(),
683
0
            OGRAPISpyGetGeom(hSpatialFilter).c_str(),
684
0
            OGRAPISpyGetString(pszDialect).c_str());
685
0
    OGRAPISpyFileClose();
686
0
}
687
688
void OGRAPISpy_DS_ReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
689
0
{
690
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
691
0
    OGRAPISpyFlushDefered();
692
0
    fprintf(fpSpyFile, "%s.ReleaseResultSet(%s)\n",
693
0
            OGRAPISpyGetDSVar(hDS).c_str(),
694
0
            (hLayer) ? OGRAPISpyGetLayerVar(hLayer).c_str() : "None");
695
696
0
    DatasetDescription &dd = oMapDS[hDS];
697
0
    dd.oMapLayer.erase(hLayer);
698
0
    oGlobalMapLayer.erase(hLayer);
699
700
0
    OGRAPISpyFileClose();
701
0
}
702
703
void OGRAPISpy_DS_CreateLayer(GDALDatasetH hDS, const char *pszName,
704
                              OGRSpatialReferenceH hSpatialRef,
705
                              OGRwkbGeometryType eType,
706
                              CSLConstList papszOptions, OGRLayerH hLayer)
707
0
{
708
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
709
0
    OGRAPISpyFlushDefered();
710
0
    if (hLayer != nullptr)
711
0
        fprintf(fpSpyFile,
712
0
                "%s = ", OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
713
0
    fprintf(fpSpyFile, "%s.CreateLayer(%s, srs=%s, geom_type=%s, options=%s)\n",
714
0
            OGRAPISpyGetDSVar(hDS).c_str(), OGRAPISpyGetString(pszName).c_str(),
715
0
            OGRAPISpyGetSRS(hSpatialRef).c_str(),
716
0
            OGRAPISpyGetGeomType(eType).c_str(),
717
0
            OGRAPISpyGetOptions(papszOptions).c_str());
718
0
    OGRAPISpyFileClose();
719
0
}
720
721
void OGRAPISpy_DS_DeleteLayer(GDALDatasetH hDS, int iLayer)
722
0
{
723
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
724
0
    OGRAPISpyFlushDefered();
725
0
    fprintf(fpSpyFile, "%s.DeleteLayer(%d)\n", OGRAPISpyGetDSVar(hDS).c_str(),
726
0
            iLayer);
727
    // Should perhaps remove from the maps.
728
0
    OGRAPISpyFileClose();
729
0
}
730
731
void OGRAPISpy_Dataset_StartTransaction(GDALDatasetH hDS, int bForce)
732
0
{
733
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
734
0
    OGRAPISpyFlushDefered();
735
0
    fprintf(fpSpyFile, "%s.StartTransaction(%d)\n",
736
0
            OGRAPISpyGetDSVar(hDS).c_str(), bForce);
737
0
    OGRAPISpyFileClose();
738
0
}
739
740
void OGRAPISpy_Dataset_CommitTransaction(GDALDatasetH hDS)
741
0
{
742
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
743
0
    OGRAPISpyFlushDefered();
744
0
    fprintf(fpSpyFile, "%s.CommitTransaction()\n",
745
0
            OGRAPISpyGetDSVar(hDS).c_str());
746
0
    OGRAPISpyFileClose();
747
0
}
748
749
void OGRAPISpy_Dataset_RollbackTransaction(GDALDatasetH hDS)
750
0
{
751
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
752
0
    OGRAPISpyFlushDefered();
753
0
    fprintf(fpSpyFile, "%s.RollbackTransaction()\n",
754
0
            OGRAPISpyGetDSVar(hDS).c_str());
755
0
    OGRAPISpyFileClose();
756
0
}
757
758
void OGRAPISpy_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
759
0
{
760
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
761
0
    OGRAPISpyFlushDefered();
762
0
    fprintf(fpSpyFile, "%s.GetFeatureCount(force=%d)\n",
763
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
764
0
    OGRAPISpyFileClose();
765
0
}
766
767
void OGRAPISpy_L_GetExtent(OGRLayerH hLayer, int bForce)
768
0
{
769
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
770
0
    OGRAPISpyFlushDefered();
771
0
    fprintf(fpSpyFile, "%s.GetExtent(force=%d)\n",
772
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
773
0
    OGRAPISpyFileClose();
774
0
}
775
776
void OGRAPISpy_L_GetExtentEx(OGRLayerH hLayer, int iGeomField, int bForce)
777
0
{
778
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
779
0
    OGRAPISpyFlushDefered();
780
0
    fprintf(fpSpyFile, "%s.GetExtent(geom_field=%d, force=%d)\n",
781
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, bForce);
782
0
    OGRAPISpyFileClose();
783
0
}
784
785
void OGRAPISpy_L_GetExtent3D(OGRLayerH hLayer, int iGeomField, int bForce)
786
0
{
787
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
788
0
    OGRAPISpyFlushDefered();
789
0
    fprintf(fpSpyFile, "%s.GetExtent3D(geom_field=%d, force=%d)\n",
790
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, bForce);
791
0
    OGRAPISpyFileClose();
792
0
}
793
794
void OGRAPISpy_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszFilter)
795
0
{
796
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
797
0
    OGRAPISpyFlushDefered();
798
0
    fprintf(fpSpyFile, "%s.SetAttributeFilter(%s)\n",
799
0
            OGRAPISpyGetLayerVar(hLayer).c_str(),
800
0
            OGRAPISpyGetString(pszFilter).c_str());
801
0
    OGRAPISpyFileClose();
802
0
}
803
804
void OGRAPISpy_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
805
0
{
806
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
807
0
    OGRAPISpyFlushDefered();
808
0
    fprintf(fpSpyFile, "%s.GetFeature(" CPL_FRMT_GIB ")\n",
809
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), nFeatureId);
810
0
    OGRAPISpyFileClose();
811
0
}
812
813
void OGRAPISpy_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
814
0
{
815
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
816
0
    OGRAPISpyFlushDefered();
817
0
    fprintf(fpSpyFile, "%s.SetNextByIndex(" CPL_FRMT_GIB ")\n",
818
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), nIndex);
819
0
    OGRAPISpyFileClose();
820
0
}
821
822
void OGRAPISpy_L_GetNextFeature(OGRLayerH hLayer)
823
0
{
824
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
825
0
    if (hLayerGetNextFeature != hLayer)
826
0
    {
827
0
        OGRAPISpyFlushDefered();
828
0
        OGRAPISpyFileClose();
829
0
    }
830
0
    hLayerGetNextFeature = hLayer;
831
0
    nGetNextFeatureCalls++;
832
0
}
833
834
static void OGRAPISpyDumpFeature(OGRFeatureH hFeat)
835
0
{
836
0
    OGRFeature *poFeature = OGRFeature::FromHandle(hFeat);
837
838
0
    fprintf(fpSpyFile, "f = ogr.Feature(%s)\n",
839
0
            OGRAPISpyGetFeatureDefnVar(
840
0
                OGRFeatureDefn::ToHandle(
841
0
                    const_cast<OGRFeatureDefn *>(poFeature->GetDefnRef())))
842
0
                .c_str());
843
0
    if (poFeature->GetFID() != -1)
844
0
        fprintf(fpSpyFile, "f.SetFID(" CPL_FRMT_GIB ")\n", poFeature->GetFID());
845
0
    for (int i = 0; i < poFeature->GetFieldCount(); i++)
846
0
    {
847
0
        if (poFeature->IsFieldNull(i))
848
0
        {
849
0
            fprintf(fpSpyFile, "f.SetFieldNull(%d)\n", i);
850
0
        }
851
0
        else if (poFeature->IsFieldSet(i))
852
0
        {
853
0
            switch (poFeature->GetFieldDefnRef(i)->GetType())
854
0
            {
855
0
                case OFTInteger:
856
0
                    fprintf(fpSpyFile, "f.SetField(%d, %d)\n", i,
857
0
                            poFeature->GetFieldAsInteger(i));
858
0
                    break;
859
0
                case OFTReal:
860
0
                    fprintf(fpSpyFile, "%s",
861
0
                            CPLSPrintf("f.SetField(%d, %.16g)\n", i,
862
0
                                       poFeature->GetFieldAsDouble(i)));
863
0
                    break;
864
0
                case OFTString:
865
0
                    fprintf(fpSpyFile, "f.SetField(%d, %s)\n", i,
866
0
                            OGRAPISpyGetString(poFeature->GetFieldAsString(i))
867
0
                                .c_str());
868
0
                    break;
869
0
                default:
870
0
                    fprintf(fpSpyFile, "f.SetField(%d, %s) #FIXME\n", i,
871
0
                            OGRAPISpyGetString(poFeature->GetFieldAsString(i))
872
0
                                .c_str());
873
0
                    break;
874
0
            }
875
0
        }
876
0
    }
877
0
    for (int i = 0; i < poFeature->GetGeomFieldCount(); i++)
878
0
    {
879
0
        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
880
0
        if (poGeom != nullptr)
881
0
        {
882
0
            fprintf(fpSpyFile, "f.SetGeomField(%d, %s)\n", i,
883
0
                    OGRAPISpyGetGeom(OGRGeometry::ToHandle(poGeom)).c_str());
884
0
        }
885
0
    }
886
0
    const char *pszStyleString = poFeature->GetStyleString();
887
0
    if (pszStyleString != nullptr)
888
0
        fprintf(fpSpyFile, "f.SetStyleString(%s)\n",
889
0
                OGRAPISpyGetString(pszStyleString).c_str());
890
0
}
891
892
void OGRAPISpy_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
893
0
{
894
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
895
0
    OGRAPISpyFlushDefered();
896
0
    OGRAPISpyDumpFeature(hFeat);
897
0
    fprintf(fpSpyFile, "%s.SetFeature(f)\n",
898
0
            OGRAPISpyGetLayerVar(hLayer).c_str());
899
    // In case layer defn is changed afterwards.
900
0
    fprintf(fpSpyFile, "f = None\n");
901
0
    OGRAPISpyFileClose();
902
0
}
903
904
void OGRAPISpy_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
905
0
{
906
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
907
0
    OGRAPISpyFlushDefered();
908
0
    OGRAPISpyDumpFeature(hFeat);
909
0
    fprintf(fpSpyFile, "%s.CreateFeature(f)\n",
910
0
            OGRAPISpyGetLayerVar(hLayer).c_str());
911
    // In case layer defn is changed afterwards.
912
0
    fprintf(fpSpyFile, "f = None\n");
913
0
    OGRAPISpyFileClose();
914
0
}
915
916
void OGRAPISpy_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
917
0
{
918
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
919
0
    OGRAPISpyFlushDefered();
920
0
    OGRAPISpyDumpFeature(hFeat);
921
0
    fprintf(fpSpyFile, "%s.UpsertFeature(f)\n",
922
0
            OGRAPISpyGetLayerVar(hLayer).c_str());
923
    // In case layer defn is changed afterwards.
924
0
    fprintf(fpSpyFile, "f = None\n");
925
0
    OGRAPISpyFileClose();
926
0
}
927
928
static void OGRAPISpyDumpFieldDefn(OGRFieldDefn *poFieldDefn)
929
0
{
930
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
931
0
    fprintf(fpSpyFile, "fd = ogr.FieldDefn(%s, %s)\n",
932
0
            OGRAPISpyGetString(poFieldDefn->GetNameRef()).c_str(),
933
0
            OGRAPISpyGetFieldType(poFieldDefn->GetType()).c_str());
934
0
    if (poFieldDefn->GetWidth() > 0)
935
0
        fprintf(fpSpyFile, "fd.SetWidth(%d)\n", poFieldDefn->GetWidth());
936
0
    if (poFieldDefn->GetPrecision() > 0)
937
0
        fprintf(fpSpyFile, "fd.SetPrecision(%d)\n",
938
0
                poFieldDefn->GetPrecision());
939
0
    if (!poFieldDefn->IsNullable())
940
0
        fprintf(fpSpyFile, "fd.SetNullable(0)\n");
941
0
    if (poFieldDefn->GetDefault() != nullptr)
942
0
        fprintf(fpSpyFile, "fd.SetDefault(%s)\n",
943
0
                OGRAPISpyGetString(poFieldDefn->GetDefault()).c_str());
944
0
}
945
946
void OGRAPISpy_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField,
947
                             int bApproxOK)
948
0
{
949
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
950
0
    OGRAPISpyFlushDefered();
951
0
    OGRFieldDefn *poFieldDefn = OGRFieldDefn::FromHandle(hField);
952
0
    OGRAPISpyDumpFieldDefn(poFieldDefn);
953
0
    fprintf(fpSpyFile, "%s.CreateField(fd, approx_ok=%d)\n",
954
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
955
0
    OGRAPISpyFileClose();
956
0
}
957
958
void OGRAPISpy_L_DeleteField(OGRLayerH hLayer, int iField)
959
0
{
960
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
961
0
    OGRAPISpyFlushDefered();
962
0
    fprintf(fpSpyFile, "%s.DeleteField(%d)\n",
963
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iField);
964
0
    OGRAPISpyFileClose();
965
0
}
966
967
void OGRAPISpy_L_ReorderFields(OGRLayerH hLayer, int *panMap)
968
0
{
969
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
970
0
    OGRAPISpyFlushDefered();
971
0
    OGRLayer *poLayer = OGRLayer::FromHandle(hLayer);
972
0
    fprintf(fpSpyFile, "%s.ReorderFields([",
973
0
            OGRAPISpyGetLayerVar(hLayer).c_str());
974
0
    for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++)
975
0
    {
976
0
        if (i > 0)
977
0
            fprintf(fpSpyFile, ", ");
978
0
        fprintf(fpSpyFile, "%d", panMap[i]);
979
0
    }
980
0
    fprintf(fpSpyFile, "])\n");
981
0
    OGRAPISpyFileClose();
982
0
}
983
984
void OGRAPISpy_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos,
985
                              int iNewFieldPos)
986
0
{
987
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
988
0
    OGRAPISpyFlushDefered();
989
0
    fprintf(fpSpyFile, "%s.ReorderField(%d, %d)\n",
990
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iOldFieldPos, iNewFieldPos);
991
0
    OGRAPISpyFileClose();
992
0
}
993
994
void OGRAPISpy_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
995
                                OGRFieldDefnH hNewFieldDefn, int nFlags)
996
0
{
997
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
998
0
    OGRAPISpyFlushDefered();
999
0
    OGRFieldDefn *poFieldDefn = OGRFieldDefn::FromHandle(hNewFieldDefn);
1000
0
    OGRAPISpyDumpFieldDefn(poFieldDefn);
1001
0
    fprintf(fpSpyFile, "%s.AlterFieldDefn(%d, fd, %d)\n",
1002
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iField, nFlags);
1003
0
    OGRAPISpyFileClose();
1004
0
}
1005
1006
void OGRAPISpy_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1007
                                 int bApproxOK)
1008
0
{
1009
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1010
0
    OGRAPISpyFlushDefered();
1011
0
    OGRGeomFieldDefn *poGeomFieldDefn = OGRGeomFieldDefn::FromHandle(hField);
1012
1013
0
    fprintf(fpSpyFile, "geom_fd = ogr.GeomFieldDefn(%s, %s)\n",
1014
0
            OGRAPISpyGetString(poGeomFieldDefn->GetNameRef()).c_str(),
1015
0
            OGRAPISpyGetGeomType(poGeomFieldDefn->GetType()).c_str());
1016
0
    if (poGeomFieldDefn->GetSpatialRef() != nullptr)
1017
0
        fprintf(fpSpyFile, "geom_fd.SetSpatialRef(%s)\n",
1018
0
                OGRAPISpyGetSRS(OGRSpatialReference::ToHandle(
1019
0
                                    const_cast<OGRSpatialReference *>(
1020
0
                                        poGeomFieldDefn->GetSpatialRef())))
1021
0
                    .c_str());
1022
0
    if (!poGeomFieldDefn->IsNullable())
1023
0
        fprintf(fpSpyFile, "geom_fd.SetNullable(0)\n");
1024
0
    fprintf(fpSpyFile, "%s.CreateGeomField(geom_fd, approx_ok=%d)\n",
1025
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
1026
0
    OGRAPISpyFileClose();
1027
0
}
1028
1029
static void OGRAPISpy_L_Op(OGRLayerH hLayer, const char *pszMethod)
1030
0
{
1031
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1032
0
    OGRAPISpyFlushDefered();
1033
0
    fprintf(fpSpyFile, "%s.%s()\n", OGRAPISpyGetLayerVar(hLayer).c_str(),
1034
0
            pszMethod);
1035
0
    OGRAPISpyFileClose();
1036
0
}
1037
1038
void OGRAPISpy_L_StartTransaction(OGRLayerH hLayer)
1039
0
{
1040
0
    OGRAPISpy_L_Op(hLayer, "StartTransaction");
1041
0
}
1042
1043
void OGRAPISpy_L_CommitTransaction(OGRLayerH hLayer)
1044
0
{
1045
0
    OGRAPISpy_L_Op(hLayer, "CommitTransaction");
1046
0
}
1047
1048
void OGRAPISpy_L_RollbackTransaction(OGRLayerH hLayer)
1049
0
{
1050
0
    OGRAPISpy_L_Op(hLayer, "RollbackTransaction");
1051
0
}
1052
1053
void OGRAPISpy_L_GetLayerDefn(OGRLayerH hLayer)
1054
0
{
1055
0
    if (hLayer != hLayerGetLayerDefn)
1056
0
    {
1057
0
        OGRAPISpyFlushDefered();
1058
0
        hLayerGetLayerDefn = hLayer;
1059
0
        OGRAPISpyFileClose();
1060
0
    }
1061
0
}
1062
1063
void OGRAPISpy_L_GetSpatialRef(OGRLayerH hLayer)
1064
0
{
1065
0
    OGRAPISpy_L_Op(hLayer, "GetSpatialRef");
1066
0
}
1067
1068
void OGRAPISpy_L_GetSpatialFilter(OGRLayerH hLayer)
1069
0
{
1070
0
    OGRAPISpy_L_Op(hLayer, "GetSpatialFilter");
1071
0
}
1072
1073
void OGRAPISpy_L_ResetReading(OGRLayerH hLayer)
1074
0
{
1075
0
    OGRAPISpy_L_Op(hLayer, "ResetReading");
1076
0
}
1077
1078
void OGRAPISpy_L_SyncToDisk(OGRLayerH hLayer)
1079
0
{
1080
0
    OGRAPISpy_L_Op(hLayer, "SyncToDisk");
1081
0
}
1082
1083
void OGRAPISpy_L_GetFIDColumn(OGRLayerH hLayer)
1084
0
{
1085
0
    OGRAPISpy_L_Op(hLayer, "GetFIDColumn");
1086
0
}
1087
1088
void OGRAPISpy_L_GetGeometryColumn(OGRLayerH hLayer)
1089
0
{
1090
0
    OGRAPISpy_L_Op(hLayer, "GetGeometryColumn");
1091
0
}
1092
1093
void OGRAPISpy_L_GetName(OGRLayerH hLayer)
1094
0
{
1095
0
    OGRAPISpy_L_Op(hLayer, "GetName");
1096
0
}
1097
1098
void OGRAPISpy_L_GetGeomType(OGRLayerH hLayer)
1099
0
{
1100
0
    OGRAPISpy_L_Op(hLayer, "GetGeomType");
1101
0
}
1102
1103
void OGRAPISpy_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
1104
                                int bExactMatch)
1105
0
{
1106
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1107
0
    OGRAPISpyFlushDefered();
1108
0
    fprintf(fpSpyFile, "%s.FindFieldIndex(%s, %d)\n",
1109
0
            OGRAPISpyGetLayerVar(hLayer).c_str(),
1110
0
            OGRAPISpyGetString(pszFieldName).c_str(), bExactMatch);
1111
0
    OGRAPISpyFileClose();
1112
0
}
1113
1114
void OGRAPISpy_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1115
0
{
1116
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1117
0
    OGRAPISpyFlushDefered();
1118
0
    fprintf(fpSpyFile, "%s.TestCapability(%s)\n",
1119
0
            OGRAPISpyGetLayerVar(hLayer).c_str(),
1120
0
            OGRAPISpyGetString(pszCap).c_str());
1121
0
    OGRAPISpyFileClose();
1122
0
}
1123
1124
void OGRAPISpy_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
1125
0
{
1126
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1127
0
    OGRAPISpyFlushDefered();
1128
0
    fprintf(fpSpyFile, "%s.SetSpatialFilter(%s)\n",
1129
0
            OGRAPISpyGetLayerVar(hLayer).c_str(),
1130
0
            OGRAPISpyGetGeom(hGeom).c_str());
1131
0
    OGRAPISpyFileClose();
1132
0
}
1133
1134
void OGRAPISpy_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
1135
                                    OGRGeometryH hGeom)
1136
0
{
1137
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1138
0
    OGRAPISpyFlushDefered();
1139
0
    fprintf(fpSpyFile, "%s.SetSpatialFilter(%d, %s)\n",
1140
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField,
1141
0
            OGRAPISpyGetGeom(hGeom).c_str());
1142
0
    OGRAPISpyFileClose();
1143
0
}
1144
1145
void OGRAPISpy_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX,
1146
                                      double dfMinY, double dfMaxX,
1147
                                      double dfMaxY)
1148
0
{
1149
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1150
0
    OGRAPISpyFlushDefered();
1151
0
    fprintf(fpSpyFile, "%s",
1152
0
            CPLSPrintf("%s.SetSpatialFilterRect(%.16g, %.16g, %.16g, %.16g)\n",
1153
0
                       OGRAPISpyGetLayerVar(hLayer).c_str(), dfMinX, dfMinY,
1154
0
                       dfMaxX, dfMaxY));
1155
0
    OGRAPISpyFileClose();
1156
0
}
1157
1158
void OGRAPISpy_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
1159
                                        double dfMinX, double dfMinY,
1160
                                        double dfMaxX, double dfMaxY)
1161
0
{
1162
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1163
0
    OGRAPISpyFlushDefered();
1164
0
    fprintf(fpSpyFile, "%s",
1165
0
            CPLSPrintf("%s.SetSpatialFilterRect(%d, "
1166
0
                       "%.16g, %.16g, %.16g, %.16g)\n",
1167
0
                       OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, dfMinX,
1168
0
                       dfMinY, dfMaxX, dfMaxY));
1169
0
    OGRAPISpyFileClose();
1170
0
}
1171
1172
void OGRAPISpy_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
1173
0
{
1174
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1175
0
    OGRAPISpyFlushDefered();
1176
0
    fprintf(fpSpyFile, "%s.DeleteFeature(" CPL_FRMT_GIB ")\n",
1177
0
            OGRAPISpyGetLayerVar(hLayer).c_str(), nFID);
1178
0
    OGRAPISpyFileClose();
1179
0
}
1180
1181
void OGRAPISpy_L_SetIgnoredFields(OGRLayerH hLayer,
1182
                                  const char **papszIgnoredFields)
1183
0
{
1184
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1185
0
    OGRAPISpyFlushDefered();
1186
0
    fprintf(
1187
0
        fpSpyFile, "%s.SetIgnoredFields(%s)\n",
1188
0
        OGRAPISpyGetLayerVar(hLayer).c_str(),
1189
0
        OGRAPISpyGetOptions(const_cast<char **>(papszIgnoredFields)).c_str());
1190
0
    OGRAPISpyFileClose();
1191
0
}
1192
1193
void OGRAPISpy_FD_GetGeomType(OGRFeatureDefnH hDefn)
1194
0
{
1195
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1196
0
    OGRAPISpyFlushDefered();
1197
0
    fprintf(fpSpyFile, "%s.GetGeomType()\n",
1198
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
1199
0
    OGRAPISpyFileClose();
1200
0
}
1201
1202
void OGRAPISpy_FD_GetFieldCount(OGRFeatureDefnH hDefn)
1203
0
{
1204
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1205
0
    if (hLayerGetLayerDefn != nullptr &&
1206
0
        OGRFeatureDefn::ToHandle(
1207
0
            OGRLayer::FromHandle(hLayerGetLayerDefn)->GetLayerDefn()) == hDefn)
1208
0
    {
1209
0
        bDeferGetFieldCount = true;
1210
0
    }
1211
0
    else
1212
0
    {
1213
0
        OGRAPISpyFlushDefered();
1214
0
        fprintf(fpSpyFile, "%s.GetFieldCount()\n",
1215
0
                OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
1216
0
        OGRAPISpyFileClose();
1217
0
    }
1218
0
}
1219
1220
void OGRAPISpy_FD_GetFieldDefn(OGRFeatureDefnH hDefn, int iField,
1221
                               OGRFieldDefnH hField)
1222
0
{
1223
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1224
0
    OGRAPISpyFlushDefered();
1225
0
    fprintf(fpSpyFile, "%s_fielddefn%d = %s.GetFieldDefn(%d)\n",
1226
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField,
1227
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField);
1228
1229
0
    std::map<OGRFieldDefnH, CPLString>::iterator oIter =
1230
0
        oGlobalMapFieldDefn.find(hField);
1231
0
    if (oIter == oGlobalMapFieldDefn.end())
1232
0
    {
1233
0
        oMapFDefn[hDefn].oMapFieldDefn[hField] = iField;
1234
0
        oGlobalMapFieldDefn[hField] =
1235
0
            CPLSPrintf("%s_fielddefn%d",
1236
0
                       OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iField);
1237
0
    }
1238
1239
0
    OGRAPISpyFileClose();
1240
0
}
1241
1242
void OGRAPISpy_FD_GetFieldIndex(OGRFeatureDefnH hDefn, const char *pszFieldName)
1243
0
{
1244
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1245
0
    OGRAPISpyFlushDefered();
1246
0
    fprintf(fpSpyFile, "%s.GetFieldIndex(%s)\n",
1247
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
1248
0
            OGRAPISpyGetString(pszFieldName).c_str());
1249
0
    OGRAPISpyFileClose();
1250
0
}
1251
1252
void OGRAPISpy_Fld_GetXXXX(OGRFieldDefnH hField, const char *pszOp)
1253
0
{
1254
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1255
0
    OGRAPISpyFlushDefered();
1256
0
    fprintf(fpSpyFile, "%s.%s()\n", oGlobalMapFieldDefn[hField].c_str(), pszOp);
1257
0
    OGRAPISpyFileClose();
1258
0
}
1259
1260
void OGRAPISpy_FD_GetGeomFieldCount(OGRFeatureDefnH hDefn)
1261
0
{
1262
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1263
0
    OGRAPISpyFlushDefered();
1264
0
    fprintf(fpSpyFile, "%s.GetGeomFieldCount()\n",
1265
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
1266
0
    OGRAPISpyFileClose();
1267
0
}
1268
1269
void OGRAPISpy_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField,
1270
                                   OGRGeomFieldDefnH hGeomField)
1271
0
{
1272
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1273
0
    OGRAPISpyFlushDefered();
1274
0
    fprintf(fpSpyFile, "%s_geomfielddefn%d = %s.GetGeomFieldDefn(%d)\n",
1275
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField,
1276
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField);
1277
1278
0
    std::map<OGRGeomFieldDefnH, CPLString>::iterator oIter =
1279
0
        oGlobalMapGeomFieldDefn.find(hGeomField);
1280
0
    if (oIter == oGlobalMapGeomFieldDefn.end())
1281
0
    {
1282
0
        oMapFDefn[hDefn].oMapGeomFieldDefn[hGeomField] = iGeomField;
1283
0
        oGlobalMapGeomFieldDefn[hGeomField] =
1284
0
            CPLSPrintf("%s_geomfielddefn%d",
1285
0
                       OGRAPISpyGetFeatureDefnVar(hDefn).c_str(), iGeomField);
1286
0
    }
1287
1288
0
    OGRAPISpyFileClose();
1289
0
}
1290
1291
void OGRAPISpy_FD_GetGeomFieldIndex(OGRFeatureDefnH hDefn,
1292
                                    const char *pszFieldName)
1293
0
{
1294
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1295
0
    OGRAPISpyFlushDefered();
1296
0
    fprintf(fpSpyFile, "%s.GetGeomFieldIndex(%s)\n",
1297
0
            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
1298
0
            OGRAPISpyGetString(pszFieldName).c_str());
1299
0
    OGRAPISpyFileClose();
1300
0
}
1301
1302
void OGRAPISpy_GFld_GetXXXX(OGRGeomFieldDefnH hGeomField, const char *pszOp)
1303
0
{
1304
0
    CPLMutexHolderD(&hOGRAPISpyMutex);
1305
0
    OGRAPISpyFlushDefered();
1306
0
    fprintf(fpSpyFile, "%s.%s()\n", oGlobalMapGeomFieldDefn[hGeomField].c_str(),
1307
0
            pszOp);
1308
0
    OGRAPISpyFileClose();
1309
0
}
1310
1311
void OGRAPISPYCPLSetConfigOption(const char *pszKey, const char *pszValue)
1312
9.17k
{
1313
9.17k
    if (STARTS_WITH(pszKey, "OGR_API_SPY_") || STARTS_WITH(pszKey, "__"))
1314
231
        return;
1315
8.94k
    if (!OGRAPISpyEnabled())
1316
3.13k
        return;
1317
5.80k
    OGRAPISpyFlushDefered();
1318
5.80k
    if (pszValue)
1319
5.80k
    {
1320
5.80k
        fprintf(fpSpyFile, "gdal.SetConfigOption(%s, %s)\n",
1321
5.80k
                OGRAPISpyGetString(pszKey).c_str(),
1322
5.80k
                OGRAPISpyGetString(pszValue).c_str());
1323
5.80k
    }
1324
0
    else
1325
0
    {
1326
0
        fprintf(fpSpyFile, "gdal.SetConfigOption(%s, None)\n",
1327
0
                OGRAPISpyGetString(pszKey).c_str());
1328
0
    }
1329
5.80k
    OGRAPISpyFileClose();
1330
5.80k
}
1331
1332
void OGRAPISPYCPLSetThreadLocalConfigOption(const char *pszKey,
1333
                                            const char *pszValue)
1334
0
{
1335
0
    if (STARTS_WITH(pszKey, "OGR_API_SPY_") || STARTS_WITH(pszKey, "__"))
1336
0
        return;
1337
0
    if (!OGRAPISpyEnabled())
1338
0
        return;
1339
0
    OGRAPISpyFlushDefered();
1340
0
    if (pszValue)
1341
0
    {
1342
0
        fprintf(fpSpyFile,
1343
0
                "gdal.SetConfigOption(%s, %s) # SetThreadLocalConfigOption "
1344
0
                "actually\n",
1345
0
                OGRAPISpyGetString(pszKey).c_str(),
1346
0
                OGRAPISpyGetString(pszValue).c_str());
1347
0
    }
1348
0
    else
1349
0
    {
1350
0
        fprintf(fpSpyFile,
1351
0
                "gdal.SetConfigOption(%s, None) # SetThreadLocalConfigOption "
1352
0
                "actually\n",
1353
0
                OGRAPISpyGetString(pszKey).c_str());
1354
0
    }
1355
0
    OGRAPISpyFileClose();
1356
0
}
1357
1358
#endif  // OGRAPISPY_ENABLED