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 186 : OGRMiraMonDataSource::OGRMiraMonDataSource()
18 : {
19 186 : memset(&m_MMMap, 0, sizeof(m_MMMap));
20 186 : }
21 :
22 : /****************************************************************************/
23 : /* ~OGRMiraMonDataSource() */
24 : /****************************************************************************/
25 :
26 372 : OGRMiraMonDataSource::~OGRMiraMonDataSource()
27 :
28 : {
29 186 : m_apoLayers.clear();
30 :
31 186 : if (m_MMMap.fMMMap)
32 45 : VSIFCloseL(m_MMMap.fMMMap);
33 372 : }
34 :
35 : /****************************************************************************/
36 : /* Open() */
37 : /****************************************************************************/
38 :
39 201 : 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 402 : this, pszFilename, fp, poSRS, m_bUpdate, papszOpenOptionsUsr, &m_MMMap);
46 201 : if (!poLayer->bValidFile)
47 : {
48 8 : return false;
49 : }
50 :
51 193 : if (!m_osRootName.empty())
52 : {
53 : const std::string osExtension =
54 164 : CPLGetExtensionSafe(m_osRootName.c_str());
55 82 : if (!EQUAL(osExtension.c_str(), "pol") &&
56 152 : !EQUAL(osExtension.c_str(), "arc") &&
57 70 : !EQUAL(osExtension.c_str(), "pnt"))
58 : {
59 61 : CPLStrlcpy(m_MMMap.pszMapName,
60 122 : CPLFormFilenameSafe(
61 : m_osRootName.c_str(),
62 122 : CPLGetBasenameSafe(m_osRootName.c_str()).c_str(),
63 : "mmm")
64 : .c_str(),
65 : sizeof(m_MMMap.pszMapName));
66 61 : if (!m_MMMap.nNumberOfLayers)
67 : {
68 45 : m_MMMap.fMMMap = VSIFOpenL(m_MMMap.pszMapName, "w+");
69 45 : 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 45 : VSIFPrintfL(m_MMMap.fMMMap, "[VERSIO]\n");
80 45 : VSIFPrintfL(m_MMMap.fMMMap, "Vers=2\n");
81 45 : VSIFPrintfL(m_MMMap.fMMMap, "SubVers=0\n");
82 45 : VSIFPrintfL(m_MMMap.fMMMap, "variant=b\n");
83 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
84 45 : VSIFPrintfL(m_MMMap.fMMMap, "[DOCUMENT]\n");
85 45 : VSIFPrintfL(m_MMMap.fMMMap, "Titol= %s(map)\n",
86 90 : CPLGetBasenameSafe(poLayer->GetName()).c_str());
87 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
88 : }
89 : }
90 : }
91 : else
92 21 : *m_MMMap.pszMapName = '\0';
93 : }
94 : else
95 111 : *m_MMMap.pszMapName = '\0';
96 :
97 193 : m_apoLayers.emplace_back(std::move(poLayer));
98 :
99 193 : return true;
100 : }
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 67 : bool OGRMiraMonDataSource::Create(const char *pszDataSetName,
110 : CSLConstList /* papszOptions */)
111 :
112 : {
113 67 : m_bUpdate = true;
114 67 : m_osRootName = pszDataSetName;
115 :
116 67 : return true;
117 : }
118 :
119 : /****************************************************************************/
120 : /* ICreateLayer() */
121 : /****************************************************************************/
122 :
123 : OGRLayer *
124 83 : OGRMiraMonDataSource::ICreateLayer(const char *pszLayerName,
125 : const OGRGeomFieldDefn *poGeomFieldDefn,
126 : CSLConstList papszOptions)
127 : {
128 83 : CPLAssert(nullptr != pszLayerName);
129 :
130 83 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
131 : const auto poSRS =
132 83 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
133 :
134 : // It's a seed to be able to generate a random identifier in
135 : // MMGenerateFileIdentifierFromMetadataFileName() function
136 83 : srand((unsigned int)time(nullptr));
137 :
138 83 : if (OGR_GT_HasM(eType))
139 : {
140 0 : CPLError(CE_Warning, CPLE_NotSupported,
141 : "Measures in this layer will be ignored.");
142 : }
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 166 : const std::string osExtension = CPLGetExtensionSafe(m_osRootName.c_str());
150 166 : std::string osFullMMLayerName;
151 83 : if (EQUAL(osExtension.c_str(), "pol") ||
152 83 : EQUAL(osExtension.c_str(), "arc") || EQUAL(osExtension.c_str(), "pnt"))
153 : {
154 21 : osFullMMLayerName = CPLResetExtensionSafe(m_osRootName.c_str(), "");
155 21 : if (!osFullMMLayerName.empty())
156 21 : osFullMMLayerName.pop_back();
157 :
158 : // Checking that the folder where to write exists
159 : const std::string osDestFolder =
160 21 : CPLGetDirnameSafe(osFullMMLayerName.c_str());
161 21 : if (!STARTS_WITH(osDestFolder.c_str(), "/vsimem"))
162 : {
163 : VSIStatBufL sStat;
164 0 : if (VSIStatL(osDestFolder.c_str(), &sStat) != 0 ||
165 0 : !VSI_ISDIR(sStat.st_mode))
166 : {
167 0 : CPLError(CE_Failure, CPLE_AppDefined,
168 : "The folder %s does not exist.", osDestFolder.c_str());
169 0 : return nullptr;
170 : }
171 : }
172 : }
173 : else
174 : {
175 : osFullMMLayerName =
176 62 : 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 62 : if (!STARTS_WITH(m_osRootName.c_str(), "/vsimem"))
183 : {
184 : VSIStatBufL sStat;
185 14 : if (VSIStatL(m_osRootName.c_str(), &sStat) != 0 ||
186 0 : !VSI_ISDIR(sStat.st_mode))
187 : {
188 14 : if (VSIMkdir(m_osRootName.c_str(), 0755) != 0)
189 : {
190 1 : CPLError(CE_Failure, CPLE_AppDefined,
191 : "Unable to create the folder %s.",
192 : m_osRootName.c_str());
193 1 : return nullptr;
194 : }
195 : }
196 : }
197 : }
198 :
199 : /* -------------------------------------------------------------------- */
200 : /* Return open layer handle. */
201 : /* -------------------------------------------------------------------- */
202 82 : if (Open(osFullMMLayerName.c_str(), nullptr, poSRS, papszOptions))
203 : {
204 82 : return m_apoLayers.back().get();
205 : }
206 :
207 0 : return nullptr;
208 : }
209 :
210 : /****************************************************************************/
211 : /* TestCapability() */
212 : /****************************************************************************/
213 :
214 201 : int OGRMiraMonDataSource::TestCapability(const char *pszCap)
215 :
216 : {
217 201 : if (EQUAL(pszCap, ODsCCreateLayer))
218 63 : return m_bUpdate;
219 138 : else if (EQUAL(pszCap, ODsCZGeometries))
220 20 : return TRUE;
221 :
222 118 : return FALSE;
223 : }
224 :
225 : /****************************************************************************/
226 : /* GetLayer() */
227 : /****************************************************************************/
228 :
229 362 : OGRLayer *OGRMiraMonDataSource::GetLayer(int iLayer)
230 :
231 : {
232 362 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
233 20 : return nullptr;
234 :
235 342 : return m_apoLayers[iLayer].get();
236 : }
237 :
238 : /************************************************************************/
239 : /* GetFileList() */
240 : /************************************************************************/
241 :
242 10 : char **OGRMiraMonDataSource::GetFileList()
243 : {
244 20 : CPLStringList oFileList;
245 20 : for (auto &poLayer : m_apoLayers)
246 : {
247 10 : poLayer->AddToFileList(oFileList);
248 : }
249 20 : return oFileList.StealList();
250 : }
|