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