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