/src/gdal/ogr/ogrsf_frmts/miramon/ogrmiramondatasource.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /******************************************************************************  | 
2  |  |  *  | 
3  |  |  * Project:  OpenGIS Simple Features Reference Implementation  | 
4  |  |  * Purpose:  Implements OGRMiraMonDataSource class.  | 
5  |  |  * Author:   Abel Pau  | 
6  |  |  ******************************************************************************  | 
7  |  |  * Copyright (c) 2024, Xavier Pons  | 
8  |  |  *  | 
9  |  |  * SPDX-License-Identifier: MIT  | 
10  |  |  ****************************************************************************/  | 
11  |  |  | 
12  |  | #include "ogrmiramon.h"  | 
13  |  |  | 
14  |  | /****************************************************************************/  | 
15  |  | /*                          OGRMiraMonDataSource()                          */  | 
16  |  | /****************************************************************************/  | 
17  |  | OGRMiraMonDataSource::OGRMiraMonDataSource()  | 
18  | 2.30k  | { | 
19  | 2.30k  |     memset(&m_MMMap, 0, sizeof(m_MMMap));  | 
20  | 2.30k  | }  | 
21  |  |  | 
22  |  | /****************************************************************************/  | 
23  |  | /*                         ~OGRMiraMonDataSource()                          */  | 
24  |  | /****************************************************************************/  | 
25  |  |  | 
26  |  | OGRMiraMonDataSource::~OGRMiraMonDataSource()  | 
27  |  |  | 
28  | 2.30k  | { | 
29  | 2.30k  |     m_apoLayers.clear();  | 
30  |  |  | 
31  | 2.30k  |     if (m_MMMap.fMMMap)  | 
32  | 0  |         VSIFCloseL(m_MMMap.fMMMap);  | 
33  | 2.30k  | }  | 
34  |  |  | 
35  |  | /****************************************************************************/  | 
36  |  | /*                                Open()                                    */  | 
37  |  | /****************************************************************************/  | 
38  |  |  | 
39  |  | bool OGRMiraMonDataSource::Open(const char *pszFilename, VSILFILE *fp,  | 
40  |  |                                 const OGRSpatialReference *poSRS,  | 
41  |  |                                 CSLConstList papszOpenOptionsUsr)  | 
42  |  |  | 
43  | 3.91k  | { | 
44  | 3.91k  |     auto poLayer = std::make_unique<OGRMiraMonLayer>(  | 
45  | 3.91k  |         this, pszFilename, fp, poSRS, m_bUpdate, papszOpenOptionsUsr, &m_MMMap);  | 
46  | 3.91k  |     if (!poLayer->bValidFile)  | 
47  | 1.68k  |     { | 
48  | 1.68k  |         return false;  | 
49  | 1.68k  |     }  | 
50  |  |  | 
51  | 2.23k  |     if (!m_osRootName.empty())  | 
52  | 1.66k  |     { | 
53  | 1.66k  |         const std::string osExtension =  | 
54  | 1.66k  |             CPLGetExtensionSafe(m_osRootName.c_str());  | 
55  | 1.66k  |         if (!EQUAL(osExtension.c_str(), "pol") &&  | 
56  | 1.66k  |             !EQUAL(osExtension.c_str(), "arc") &&  | 
57  | 1.66k  |             !EQUAL(osExtension.c_str(), "pnt"))  | 
58  | 0  |         { | 
59  | 0  |             CPLStrlcpy(m_MMMap.pszMapName,  | 
60  | 0  |                        CPLFormFilenameSafe(  | 
61  | 0  |                            m_osRootName.c_str(),  | 
62  | 0  |                            CPLGetBasenameSafe(m_osRootName.c_str()).c_str(),  | 
63  | 0  |                            "mmm")  | 
64  | 0  |                            .c_str(),  | 
65  | 0  |                        sizeof(m_MMMap.pszMapName));  | 
66  | 0  |             if (!m_MMMap.nNumberOfLayers)  | 
67  | 0  |             { | 
68  | 0  |                 m_MMMap.fMMMap = VSIFOpenL(m_MMMap.pszMapName, "w+");  | 
69  | 0  |                 if (!m_MMMap.fMMMap)  | 
70  | 0  |                 { | 
71  |  |                     // It could be an error but it is not so important  | 
72  |  |                     // to stop the process. This map is an extra element  | 
73  |  |                     // to open all layers in one click, at least in MiraMon  | 
74  |  |                     // software.  | 
75  | 0  |                     *m_MMMap.pszMapName = '\0';  | 
76  | 0  |                 }  | 
77  | 0  |                 else  | 
78  | 0  |                 { | 
79  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "[VERSIO]\n");  | 
80  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "Vers=2\n");  | 
81  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "SubVers=0\n");  | 
82  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "variant=b\n");  | 
83  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "\n");  | 
84  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "[DOCUMENT]\n");  | 
85  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "Titol= %s(map)\n",  | 
86  | 0  |                                 CPLGetBasenameSafe(poLayer->GetName()).c_str());  | 
87  | 0  |                     VSIFPrintfL(m_MMMap.fMMMap, "\n");  | 
88  | 0  |                 }  | 
89  | 0  |             }  | 
90  | 0  |         }  | 
91  | 1.66k  |         else  | 
92  | 1.66k  |             *m_MMMap.pszMapName = '\0';  | 
93  | 1.66k  |     }  | 
94  | 568  |     else  | 
95  | 568  |         *m_MMMap.pszMapName = '\0';  | 
96  |  |  | 
97  | 2.23k  |     m_apoLayers.emplace_back(std::move(poLayer));  | 
98  |  |  | 
99  | 2.23k  |     return true;  | 
100  | 3.91k  | }  | 
101  |  |  | 
102  |  | /****************************************************************************/  | 
103  |  | /*                               Create()                                   */  | 
104  |  | /*                                                                          */  | 
105  |  | /*      Create a new datasource.  This does not really do anything          */  | 
106  |  | /*      currently but save the name.                                        */  | 
107  |  | /****************************************************************************/  | 
108  |  |  | 
109  |  | bool OGRMiraMonDataSource::Create(const char *pszDataSetName,  | 
110  |  |                                   CSLConstList /* papszOptions */)  | 
111  |  |  | 
112  | 50  | { | 
113  | 50  |     m_bUpdate = true;  | 
114  | 50  |     m_osRootName = pszDataSetName;  | 
115  |  |  | 
116  | 50  |     return true;  | 
117  | 50  | }  | 
118  |  |  | 
119  |  | /****************************************************************************/  | 
120  |  | /*                           ICreateLayer()                                 */  | 
121  |  | /****************************************************************************/  | 
122  |  |  | 
123  |  | OGRLayer *  | 
124  |  | OGRMiraMonDataSource::ICreateLayer(const char *pszLayerName,  | 
125  |  |                                    const OGRGeomFieldDefn *poGeomFieldDefn,  | 
126  |  |                                    CSLConstList papszOptions)  | 
127  | 1.66k  | { | 
128  | 1.66k  |     CPLAssert(nullptr != pszLayerName);  | 
129  |  |  | 
130  | 1.66k  |     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;  | 
131  | 1.66k  |     const auto poSRS =  | 
132  | 1.66k  |         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;  | 
133  |  |  | 
134  |  |     // It's a seed to be able to generate a random identifier in  | 
135  |  |     // MMGenerateFileIdentifierFromMetadataFileName() function  | 
136  | 1.66k  |     srand((unsigned int)time(nullptr));  | 
137  |  |  | 
138  | 1.66k  |     if (OGR_GT_HasM(eType))  | 
139  | 0  |     { | 
140  | 0  |         CPLError(CE_Warning, CPLE_NotSupported,  | 
141  | 0  |                  "Measures in this layer will be ignored.");  | 
142  | 0  |     }  | 
143  |  |  | 
144  |  |     /* -------------------------------------------------------------------- */  | 
145  |  |     /*    If the dataset has an extension, it is understood that the path   */  | 
146  |  |     /*       of the file is where to write, and the layer name is the       */  | 
147  |  |     /*       dataset name (without extension).                              */  | 
148  |  |     /* -------------------------------------------------------------------- */  | 
149  | 1.66k  |     const std::string osExtension = CPLGetExtensionSafe(m_osRootName.c_str());  | 
150  | 1.66k  |     std::string osFullMMLayerName;  | 
151  | 1.66k  |     if (EQUAL(osExtension.c_str(), "pol") ||  | 
152  | 1.66k  |         EQUAL(osExtension.c_str(), "arc") || EQUAL(osExtension.c_str(), "pnt"))  | 
153  | 1.66k  |     { | 
154  | 1.66k  |         osFullMMLayerName = CPLResetExtensionSafe(m_osRootName.c_str(), "");  | 
155  | 1.66k  |         if (!osFullMMLayerName.empty())  | 
156  | 1.66k  |             osFullMMLayerName.pop_back();  | 
157  |  |  | 
158  |  |         // Checking that the folder where to write exists  | 
159  | 1.66k  |         const std::string osDestFolder =  | 
160  | 1.66k  |             CPLGetDirnameSafe(osFullMMLayerName.c_str());  | 
161  | 1.66k  |         if (!STARTS_WITH(osDestFolder.c_str(), "/vsimem"))  | 
162  | 0  |         { | 
163  | 0  |             VSIStatBufL sStat;  | 
164  | 0  |             if (VSIStatL(osDestFolder.c_str(), &sStat) != 0 ||  | 
165  | 0  |                 !VSI_ISDIR(sStat.st_mode))  | 
166  | 0  |             { | 
167  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
168  | 0  |                          "The folder %s does not exist.", osDestFolder.c_str());  | 
169  | 0  |                 return nullptr;  | 
170  | 0  |             }  | 
171  | 0  |         }  | 
172  | 1.66k  |     }  | 
173  | 0  |     else  | 
174  | 0  |     { | 
175  | 0  |         osFullMMLayerName =  | 
176  | 0  |             CPLFormFilenameSafe(m_osRootName.c_str(), pszLayerName, "");  | 
177  |  |  | 
178  |  |         /* -------------------------------------------------------------------- */  | 
179  |  |         /*      Let's create the folder if it's not already created.            */  | 
180  |  |         /*      (only the las level of the folder)                              */  | 
181  |  |         /* -------------------------------------------------------------------- */  | 
182  | 0  |         if (!STARTS_WITH(m_osRootName.c_str(), "/vsimem"))  | 
183  | 0  |         { | 
184  | 0  |             VSIStatBufL sStat;  | 
185  | 0  |             if (VSIStatL(m_osRootName.c_str(), &sStat) != 0 ||  | 
186  | 0  |                 !VSI_ISDIR(sStat.st_mode))  | 
187  | 0  |             { | 
188  | 0  |                 if (VSIMkdir(m_osRootName.c_str(), 0755) != 0)  | 
189  | 0  |                 { | 
190  | 0  |                     CPLError(CE_Failure, CPLE_AppDefined,  | 
191  | 0  |                              "Unable to create the folder %s.",  | 
192  | 0  |                              m_osRootName.c_str());  | 
193  | 0  |                     return nullptr;  | 
194  | 0  |                 }  | 
195  | 0  |             }  | 
196  | 0  |         }  | 
197  | 0  |     }  | 
198  |  |  | 
199  |  |     /* -------------------------------------------------------------------- */  | 
200  |  |     /*      Return open layer handle.                                       */  | 
201  |  |     /* -------------------------------------------------------------------- */  | 
202  | 1.66k  |     if (Open(osFullMMLayerName.c_str(), nullptr, poSRS, papszOptions))  | 
203  | 1.66k  |     { | 
204  | 1.66k  |         return m_apoLayers.back().get();  | 
205  | 1.66k  |     }  | 
206  |  |  | 
207  | 0  |     return nullptr;  | 
208  | 1.66k  | }  | 
209  |  |  | 
210  |  | /****************************************************************************/  | 
211  |  | /*                           TestCapability()                               */  | 
212  |  | /****************************************************************************/  | 
213  |  |  | 
214  |  | int OGRMiraMonDataSource::TestCapability(const char *pszCap)  | 
215  |  |  | 
216  | 3.55k  | { | 
217  | 3.55k  |     if (EQUAL(pszCap, ODsCCreateLayer))  | 
218  | 1.66k  |         return m_bUpdate;  | 
219  | 1.89k  |     else if (EQUAL(pszCap, ODsCZGeometries))  | 
220  | 0  |         return TRUE;  | 
221  |  |  | 
222  | 1.89k  |     return FALSE;  | 
223  | 3.55k  | }  | 
224  |  |  | 
225  |  | /****************************************************************************/  | 
226  |  | /*                              GetLayer()                                  */  | 
227  |  | /****************************************************************************/  | 
228  |  |  | 
229  |  | OGRLayer *OGRMiraMonDataSource::GetLayer(int iLayer)  | 
230  |  |  | 
231  | 69.4k  | { | 
232  | 69.4k  |     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))  | 
233  | 0  |         return nullptr;  | 
234  |  |  | 
235  | 69.4k  |     return m_apoLayers[iLayer].get();  | 
236  | 69.4k  | }  | 
237  |  |  | 
238  |  | /************************************************************************/  | 
239  |  | /*                            GetFileList()                             */  | 
240  |  | /************************************************************************/  | 
241  |  |  | 
242  |  | char **OGRMiraMonDataSource::GetFileList()  | 
243  | 0  | { | 
244  | 0  |     CPLStringList oFileList;  | 
245  | 0  |     for (auto &poLayer : m_apoLayers)  | 
246  | 0  |     { | 
247  | 0  |         poLayer->AddToFileList(oFileList);  | 
248  | 0  |     }  | 
249  | 0  |     return oFileList.StealList();  | 
250  | 0  | }  |