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 190 : OGRMiraMonDataSource::OGRMiraMonDataSource()
18 : {
19 190 : memset(&m_MMMap, 0, sizeof(m_MMMap));
20 190 : }
21 :
22 : /****************************************************************************/
23 : /* ~OGRMiraMonDataSource() */
24 : /****************************************************************************/
25 :
26 380 : OGRMiraMonDataSource::~OGRMiraMonDataSource()
27 :
28 : {
29 190 : m_apoLayers.clear();
30 :
31 190 : if (m_MMMap.fMMMap)
32 46 : VSIFCloseL(m_MMMap.fMMMap);
33 380 : }
34 :
35 : /****************************************************************************/
36 : /* Open() */
37 : /****************************************************************************/
38 :
39 205 : 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 410 : this, pszFilename, fp, poSRS, m_bUpdate, papszOpenOptionsUsr, &m_MMMap);
46 205 : if (!poLayer->bValidFile)
47 : {
48 8 : return false;
49 : }
50 :
51 197 : if (!m_osRootName.empty())
52 : {
53 : const std::string osExtension =
54 168 : CPLGetExtensionSafe(m_osRootName.c_str());
55 84 : if (!EQUAL(osExtension.c_str(), "pol") &&
56 156 : !EQUAL(osExtension.c_str(), "arc") &&
57 72 : !EQUAL(osExtension.c_str(), "pnt"))
58 : {
59 62 : CPLStrlcpy(m_MMMap.pszMapName,
60 124 : CPLFormFilenameSafe(
61 : m_osRootName.c_str(),
62 124 : CPLGetBasenameSafe(m_osRootName.c_str()).c_str(),
63 : "mmm")
64 : .c_str(),
65 : sizeof(m_MMMap.pszMapName));
66 62 : if (!m_MMMap.nNumberOfLayers)
67 : {
68 46 : m_MMMap.fMMMap = VSIFOpenL(m_MMMap.pszMapName, "w+");
69 46 : 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 46 : VSIFPrintfL(m_MMMap.fMMMap, "[VERSIO]\n");
82 46 : VSIFPrintfL(m_MMMap.fMMMap, "Vers=2\n");
83 46 : VSIFPrintfL(m_MMMap.fMMMap, "SubVers=0\n");
84 46 : VSIFPrintfL(m_MMMap.fMMMap, "variant=b\n");
85 46 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
86 46 : VSIFPrintfL(m_MMMap.fMMMap, "[DOCUMENT]\n");
87 46 : pszChaiCP1252 = CPLRecode(
88 92 : CPLGetBasenameSafe(poLayer->GetName()).c_str(),
89 : CPL_ENC_UTF8, "CP1252");
90 46 : VSIFPrintfL(
91 : m_MMMap.fMMMap, "Titol= %s(map)\n",
92 : pszChaiCP1252
93 : ? pszChaiCP1252
94 46 : : CPLGetBasenameSafe(poLayer->GetName()).c_str());
95 46 : CPLFree(pszChaiCP1252);
96 46 : 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 197 : m_apoLayers.emplace_back(std::move(poLayer));
107 :
108 197 : 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 69 : bool OGRMiraMonDataSource::Create(const char *pszDataSetName,
119 : CSLConstList /* papszOptions */)
120 :
121 : {
122 69 : m_bUpdate = true;
123 69 : m_osRootName = pszDataSetName;
124 :
125 69 : return true;
126 : }
127 :
128 : /****************************************************************************/
129 : /* ICreateLayer() */
130 : /****************************************************************************/
131 :
132 : OGRLayer *
133 85 : OGRMiraMonDataSource::ICreateLayer(const char *pszLayerName,
134 : const OGRGeomFieldDefn *poGeomFieldDefn,
135 : CSLConstList papszOptions)
136 : {
137 85 : CPLAssert(nullptr != pszLayerName);
138 :
139 85 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
140 : const auto poSRS =
141 85 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
142 :
143 : // It's a seed to be able to generate a random identifier in
144 : // MMGenerateFileIdentifierFromMetadataFileName() function
145 85 : srand(static_cast<unsigned int>(time(nullptr)));
146 :
147 85 : 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 170 : const std::string osExtension = CPLGetExtensionSafe(m_osRootName.c_str());
159 170 : std::string osFullMMLayerName;
160 85 : if (EQUAL(osExtension.c_str(), "pol") ||
161 85 : 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 : osFullMMLayerName =
185 63 : CPLFormFilenameSafe(m_osRootName.c_str(), pszLayerName, "");
186 :
187 : /* -------------------------------------------------------------------- */
188 : /* Let's create the folder if it's not already created. */
189 : /* (only the las level of the folder) */
190 : /* -------------------------------------------------------------------- */
191 63 : if (!STARTS_WITH(m_osRootName.c_str(), "/vsimem"))
192 : {
193 : VSIStatBufL sStat;
194 14 : if (VSIStatL(m_osRootName.c_str(), &sStat) != 0 ||
195 0 : !VSI_ISDIR(sStat.st_mode))
196 : {
197 14 : if (VSIMkdir(m_osRootName.c_str(), 0755) != 0)
198 : {
199 1 : CPLError(CE_Failure, CPLE_AppDefined,
200 : "Unable to create the folder %s.",
201 : m_osRootName.c_str());
202 1 : return nullptr;
203 : }
204 : }
205 : }
206 : }
207 :
208 : /* -------------------------------------------------------------------- */
209 : /* Return open layer handle. */
210 : /* -------------------------------------------------------------------- */
211 84 : if (Open(osFullMMLayerName.c_str(), nullptr, poSRS, papszOptions))
212 : {
213 84 : return m_apoLayers.back().get();
214 : }
215 :
216 0 : return nullptr;
217 : }
218 :
219 : /****************************************************************************/
220 : /* TestCapability() */
221 : /****************************************************************************/
222 :
223 207 : int OGRMiraMonDataSource::TestCapability(const char *pszCap) const
224 :
225 : {
226 207 : if (EQUAL(pszCap, ODsCCreateLayer))
227 65 : return m_bUpdate;
228 142 : else if (EQUAL(pszCap, ODsCZGeometries))
229 20 : return TRUE;
230 :
231 122 : return FALSE;
232 : }
233 :
234 : /****************************************************************************/
235 : /* GetLayer() */
236 : /****************************************************************************/
237 :
238 366 : const OGRLayer *OGRMiraMonDataSource::GetLayer(int iLayer) const
239 :
240 : {
241 366 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
242 20 : return nullptr;
243 :
244 346 : return m_apoLayers[iLayer].get();
245 : }
246 :
247 : /************************************************************************/
248 : /* GetFileList() */
249 : /************************************************************************/
250 :
251 10 : char **OGRMiraMonDataSource::GetFileList()
252 : {
253 20 : CPLStringList oFileList;
254 20 : for (auto &poLayer : m_apoLayers)
255 : {
256 10 : poLayer->AddToFileList(oFileList);
257 : }
258 20 : return oFileList.StealList();
259 : }
|