/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  | 2.13k  | { | 
148  | 2.13k  |     if (fpSpyFile == nullptr)  | 
149  | 2.13k  |     { | 
150  | 2.13k  |         fpSpyFile = fopen(osSpyFile, "ab");  | 
151  | 2.13k  |         if (fpSpyFile == nullptr)  | 
152  | 0  |             fpSpyFile = stderr;  | 
153  | 2.13k  |     }  | 
154  | 2.13k  | }  | 
155  |  |  | 
156  |  | static void OGRAPISpyFileClose()  | 
157  | 2.13k  | { | 
158  | 2.13k  |     if (fpSpyFile != stdout && fpSpyFile != stderr)  | 
159  | 2.13k  |     { | 
160  | 2.13k  |         fclose(fpSpyFile);  | 
161  | 2.13k  |         fpSpyFile = nullptr;  | 
162  | 2.13k  |     }  | 
163  | 2.13k  | }  | 
164  |  |  | 
165  |  | static bool OGRAPISpyEnabled()  | 
166  | 2.22k  | { | 
167  | 2.22k  |     if (bOGRAPISpyEnabled < 0)  | 
168  | 0  |         return false;  | 
169  |  |  | 
170  | 2.22k  |     const char *pszSpyFile = CPLGetConfigOption("OGR_API_SPY_FILE", nullptr); | 
171  | 2.22k  |     bOGRAPISpyEnabled = pszSpyFile != nullptr;  | 
172  | 2.22k  |     if (!bOGRAPISpyEnabled)  | 
173  | 93  |     { | 
174  | 93  |         osSpyFile.resize(0);  | 
175  | 93  |         aoSetCreatedDS.clear();  | 
176  | 93  |         return false;  | 
177  | 93  |     }  | 
178  | 2.13k  |     if (!osSpyFile.empty())  | 
179  | 2.13k  |         return true;  | 
180  |  |  | 
181  | 1  |     CPLMutexHolderD(&hOGRAPISpyMutex);  | 
182  | 1  |     if (!osSpyFile.empty())  | 
183  | 0  |         return true;  | 
184  |  |  | 
185  | 1  |     osSpyFile = pszSpyFile;  | 
186  |  |  | 
187  | 1  |     const char *pszSnapshotPath =  | 
188  | 1  |         CPLGetConfigOption("OGR_API_SPY_SNAPSHOT_PATH", "."); | 
189  | 1  |     if (EQUAL(pszSnapshotPath, "NO"))  | 
190  | 0  |         osSnapshotPath = "";  | 
191  | 1  |     else  | 
192  | 1  |         osSnapshotPath = pszSnapshotPath;  | 
193  |  |  | 
194  | 1  |     if (EQUAL(pszSpyFile, "stdout"))  | 
195  | 0  |         fpSpyFile = stdout;  | 
196  | 1  |     else if (EQUAL(pszSpyFile, "stderr"))  | 
197  | 0  |         fpSpyFile = stderr;  | 
198  | 1  |     else  | 
199  | 1  |         fpSpyFile = fopen(pszSpyFile, "wb");  | 
200  | 1  |     if (fpSpyFile == nullptr)  | 
201  | 0  |         fpSpyFile = stderr;  | 
202  |  |  | 
203  | 1  |     assert(fpSpyFile != nullptr);  | 
204  | 1  |     fprintf(fpSpyFile,  | 
205  | 1  |             "# This file is generated by the OGR_API_SPY mechanism.\n");  | 
206  | 1  |     fprintf(fpSpyFile, "import os\n");  | 
207  | 1  |     fprintf(fpSpyFile, "import shutil\n");  | 
208  | 1  |     fprintf(fpSpyFile, "from osgeo import gdal\n");  | 
209  | 1  |     fprintf(fpSpyFile, "from osgeo import ogr\n");  | 
210  | 1  |     fprintf(fpSpyFile, "from osgeo import osr\n");  | 
211  |  |     // To make pyflakes happy in case it is unused later.  | 
212  | 1  |     fprintf(fpSpyFile, "os.access\n");  | 
213  | 1  |     fprintf(fpSpyFile, "shutil.copy\n");  // Same here.  | 
214  | 1  |     fprintf(fpSpyFile, "\n");  | 
215  |  |  | 
216  | 1  |     return true;  | 
217  | 1  | }  | 
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  | 4.26k  | { | 
242  | 4.26k  |     if (pszStr == nullptr)  | 
243  | 0  |         return "None";  | 
244  | 4.26k  |     CPLString osRet = "'";  | 
245  | 159k  |     while (*pszStr)  | 
246  | 155k  |     { | 
247  | 155k  |         if (*pszStr == '\'')  | 
248  | 839  |             osRet += "\\'";  | 
249  | 154k  |         else if (*pszStr == '\\')  | 
250  | 226  |             osRet += "\\\\";  | 
251  | 154k  |         else  | 
252  | 154k  |             osRet += *pszStr;  | 
253  | 155k  |         pszStr++;  | 
254  | 155k  |     }  | 
255  | 4.26k  |     osRet += "'";  | 
256  | 4.26k  |     return osRet;  | 
257  | 4.26k  | }  | 
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  | 2.13k  | { | 
418  | 2.13k  |     OGRAPISpyFileReopen();  | 
419  | 2.13k  |     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  | 2.13k  |     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  | 2.13k  |     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  | 2.13k  | }  | 
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  | 2.26k  | { | 
1311  | 2.26k  |     if (STARTS_WITH(pszKey, "OGR_API_SPY_") || STARTS_WITH(pszKey, "__"))  | 
1312  | 36  |         return;  | 
1313  | 2.22k  |     if (!OGRAPISpyEnabled())  | 
1314  | 93  |         return;  | 
1315  | 2.13k  |     OGRAPISpyFlushDefered();  | 
1316  | 2.13k  |     if (pszValue)  | 
1317  | 2.13k  |     { | 
1318  | 2.13k  |         fprintf(fpSpyFile, "gdal.SetConfigOption(%s, %s)\n",  | 
1319  | 2.13k  |                 OGRAPISpyGetString(pszKey).c_str(),  | 
1320  | 2.13k  |                 OGRAPISpyGetString(pszValue).c_str());  | 
1321  | 2.13k  |     }  | 
1322  | 0  |     else  | 
1323  | 0  |     { | 
1324  | 0  |         fprintf(fpSpyFile, "gdal.SetConfigOption(%s, None)\n",  | 
1325  | 0  |                 OGRAPISpyGetString(pszKey).c_str());  | 
1326  | 0  |     }  | 
1327  | 2.13k  |     OGRAPISpyFileClose();  | 
1328  | 2.13k  | }  | 
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  |