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