Coverage Report

Created: 2025-06-13 06:29

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