Line data Source code
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 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "ogrmiramon.h"
29 :
30 : /****************************************************************************/
31 : /* OGRMiraMonDataSource() */
32 : /****************************************************************************/
33 184 : OGRMiraMonDataSource::OGRMiraMonDataSource()
34 : {
35 184 : memset(&m_MMMap, 0, sizeof(m_MMMap));
36 184 : }
37 :
38 : /****************************************************************************/
39 : /* ~OGRMiraMonDataSource() */
40 : /****************************************************************************/
41 :
42 368 : OGRMiraMonDataSource::~OGRMiraMonDataSource()
43 :
44 : {
45 184 : m_apoLayers.clear();
46 :
47 184 : if (m_MMMap.fMMMap)
48 45 : VSIFCloseL(m_MMMap.fMMMap);
49 368 : }
50 :
51 : /****************************************************************************/
52 : /* Open() */
53 : /****************************************************************************/
54 :
55 199 : bool OGRMiraMonDataSource::Open(const char *pszFilename, VSILFILE *fp,
56 : const OGRSpatialReference *poSRS,
57 : CSLConstList papszOpenOptionsUsr)
58 :
59 : {
60 : auto poLayer = std::make_unique<OGRMiraMonLayer>(
61 398 : this, pszFilename, fp, poSRS, m_bUpdate, papszOpenOptionsUsr, &m_MMMap);
62 199 : if (!poLayer->bValidFile)
63 : {
64 8 : return false;
65 : }
66 :
67 191 : if (!m_osRootName.empty())
68 : {
69 81 : const char *pszExtension = CPLGetExtension(m_osRootName.c_str());
70 81 : if (!EQUAL(pszExtension, "pol") && !EQUAL(pszExtension, "arc") &&
71 70 : !EQUAL(pszExtension, "pnt"))
72 : {
73 61 : CPLStrlcpy(m_MMMap.pszMapName,
74 : CPLFormFilename(m_osRootName.c_str(),
75 : CPLGetBasename(m_osRootName.c_str()),
76 : "mmm"),
77 : sizeof(m_MMMap.pszMapName));
78 61 : if (!m_MMMap.nNumberOfLayers)
79 : {
80 45 : m_MMMap.fMMMap = VSIFOpenL(m_MMMap.pszMapName, "w+");
81 45 : if (!m_MMMap.fMMMap)
82 : {
83 : // It could be an error but it is not so important
84 : // to stop the process. This map is an extra element
85 : // to open all layers in one click, at least in MiraMon
86 : // software.
87 0 : *m_MMMap.pszMapName = '\0';
88 : }
89 : else
90 : {
91 45 : VSIFPrintfL(m_MMMap.fMMMap, "[VERSIO]\n");
92 45 : VSIFPrintfL(m_MMMap.fMMMap, "Vers=2\n");
93 45 : VSIFPrintfL(m_MMMap.fMMMap, "SubVers=0\n");
94 45 : VSIFPrintfL(m_MMMap.fMMMap, "variant=b\n");
95 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
96 45 : VSIFPrintfL(m_MMMap.fMMMap, "[DOCUMENT]\n");
97 45 : VSIFPrintfL(m_MMMap.fMMMap, "Titol= %s(map)\n",
98 45 : CPLGetBasename(poLayer->GetName()));
99 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
100 : }
101 : }
102 : }
103 : else
104 20 : *m_MMMap.pszMapName = '\0';
105 : }
106 : else
107 110 : *m_MMMap.pszMapName = '\0';
108 :
109 191 : m_apoLayers.emplace_back(std::move(poLayer));
110 :
111 191 : return true;
112 : }
113 :
114 : /****************************************************************************/
115 : /* Create() */
116 : /* */
117 : /* Create a new datasource. This does not really do anything */
118 : /* currently but save the name. */
119 : /****************************************************************************/
120 :
121 66 : bool OGRMiraMonDataSource::Create(const char *pszDataSetName,
122 : CSLConstList /* papszOptions */)
123 :
124 : {
125 66 : m_bUpdate = true;
126 66 : m_osRootName = pszDataSetName;
127 :
128 66 : return true;
129 : }
130 :
131 : /****************************************************************************/
132 : /* ICreateLayer() */
133 : /****************************************************************************/
134 :
135 : OGRLayer *
136 82 : OGRMiraMonDataSource::ICreateLayer(const char *pszLayerName,
137 : const OGRGeomFieldDefn *poGeomFieldDefn,
138 : CSLConstList papszOptions)
139 : {
140 82 : CPLAssert(nullptr != pszLayerName);
141 :
142 82 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
143 : const auto poSRS =
144 82 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
145 :
146 : // It's a seed to be able to generate a random identifier in
147 : // MMGenerateFileIdentifierFromMetadataFileName() function
148 82 : srand((unsigned int)time(nullptr));
149 :
150 82 : if (OGR_GT_HasM(eType))
151 : {
152 0 : CPLError(CE_Warning, CPLE_NotSupported,
153 : "Measures in this layer will be ignored.");
154 : }
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* If the dataset has an extension, it is understood that the path */
158 : /* of the file is where to write, and the layer name is the */
159 : /* dataset name (without extension). */
160 : /* -------------------------------------------------------------------- */
161 82 : const char *pszExtension = CPLGetExtension(m_osRootName.c_str());
162 164 : std::string osFullMMLayerName;
163 82 : if (EQUAL(pszExtension, "pol") || EQUAL(pszExtension, "arc") ||
164 71 : EQUAL(pszExtension, "pnt"))
165 : {
166 20 : osFullMMLayerName = CPLResetExtension(m_osRootName.c_str(), "");
167 20 : if (!osFullMMLayerName.empty())
168 20 : osFullMMLayerName.pop_back();
169 :
170 : // Checking that the folder where to write exists
171 : const std::string osDestFolder =
172 20 : CPLGetDirname(osFullMMLayerName.c_str());
173 20 : if (!STARTS_WITH(osDestFolder.c_str(), "/vsimem"))
174 : {
175 : VSIStatBufL sStat;
176 0 : if (VSIStatL(osDestFolder.c_str(), &sStat) != 0 ||
177 0 : !VSI_ISDIR(sStat.st_mode))
178 : {
179 0 : CPLError(CE_Failure, CPLE_AppDefined,
180 : "The folder %s does not exist.", osDestFolder.c_str());
181 0 : return nullptr;
182 : }
183 20 : }
184 : }
185 : else
186 : {
187 : osFullMMLayerName =
188 62 : CPLFormFilename(m_osRootName.c_str(), pszLayerName, "");
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Let's create the folder if it's not already created. */
192 : /* (only the las level of the folder) */
193 : /* -------------------------------------------------------------------- */
194 62 : if (!STARTS_WITH(m_osRootName.c_str(), "/vsimem"))
195 : {
196 : VSIStatBufL sStat;
197 14 : if (VSIStatL(m_osRootName.c_str(), &sStat) != 0 ||
198 0 : !VSI_ISDIR(sStat.st_mode))
199 : {
200 14 : if (VSIMkdir(m_osRootName.c_str(), 0755) != 0)
201 : {
202 1 : CPLError(CE_Failure, CPLE_AppDefined,
203 : "Unable to create the folder %s.",
204 : m_osRootName.c_str());
205 1 : return nullptr;
206 : }
207 : }
208 : }
209 : }
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* Return open layer handle. */
213 : /* -------------------------------------------------------------------- */
214 81 : if (Open(osFullMMLayerName.c_str(), nullptr, poSRS, papszOptions))
215 : {
216 81 : return m_apoLayers.back().get();
217 : }
218 :
219 0 : return nullptr;
220 : }
221 :
222 : /****************************************************************************/
223 : /* TestCapability() */
224 : /****************************************************************************/
225 :
226 198 : int OGRMiraMonDataSource::TestCapability(const char *pszCap)
227 :
228 : {
229 198 : if (EQUAL(pszCap, ODsCCreateLayer))
230 62 : return m_bUpdate;
231 136 : else if (EQUAL(pszCap, ODsCZGeometries))
232 20 : return TRUE;
233 :
234 116 : return FALSE;
235 : }
236 :
237 : /****************************************************************************/
238 : /* GetLayer() */
239 : /****************************************************************************/
240 :
241 360 : OGRLayer *OGRMiraMonDataSource::GetLayer(int iLayer)
242 :
243 : {
244 360 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
245 20 : return nullptr;
246 :
247 340 : return m_apoLayers[iLayer].get();
248 : }
249 :
250 : /************************************************************************/
251 : /* GetFileList() */
252 : /************************************************************************/
253 :
254 10 : char **OGRMiraMonDataSource::GetFileList()
255 : {
256 20 : CPLStringList oFileList;
257 20 : for (auto &poLayer : m_apoLayers)
258 : {
259 10 : poLayer->AddToFileList(oFileList);
260 : }
261 20 : return oFileList.StealList();
262 : }
|