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