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