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 82 : const char *pszExtension = CPLGetExtension(m_osRootName.c_str());
54 82 : if (!EQUAL(pszExtension, "pol") && !EQUAL(pszExtension, "arc") &&
55 70 : !EQUAL(pszExtension, "pnt"))
56 : {
57 61 : CPLStrlcpy(m_MMMap.pszMapName,
58 : CPLFormFilename(m_osRootName.c_str(),
59 : CPLGetBasename(m_osRootName.c_str()),
60 : "mmm"),
61 : sizeof(m_MMMap.pszMapName));
62 61 : if (!m_MMMap.nNumberOfLayers)
63 : {
64 45 : m_MMMap.fMMMap = VSIFOpenL(m_MMMap.pszMapName, "w+");
65 45 : if (!m_MMMap.fMMMap)
66 : {
67 : // It could be an error but it is not so important
68 : // to stop the process. This map is an extra element
69 : // to open all layers in one click, at least in MiraMon
70 : // software.
71 0 : *m_MMMap.pszMapName = '\0';
72 : }
73 : else
74 : {
75 45 : VSIFPrintfL(m_MMMap.fMMMap, "[VERSIO]\n");
76 45 : VSIFPrintfL(m_MMMap.fMMMap, "Vers=2\n");
77 45 : VSIFPrintfL(m_MMMap.fMMMap, "SubVers=0\n");
78 45 : VSIFPrintfL(m_MMMap.fMMMap, "variant=b\n");
79 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
80 45 : VSIFPrintfL(m_MMMap.fMMMap, "[DOCUMENT]\n");
81 45 : VSIFPrintfL(m_MMMap.fMMMap, "Titol= %s(map)\n",
82 45 : CPLGetBasename(poLayer->GetName()));
83 45 : VSIFPrintfL(m_MMMap.fMMMap, "\n");
84 : }
85 : }
86 : }
87 : else
88 21 : *m_MMMap.pszMapName = '\0';
89 : }
90 : else
91 111 : *m_MMMap.pszMapName = '\0';
92 :
93 193 : m_apoLayers.emplace_back(std::move(poLayer));
94 :
95 193 : return true;
96 : }
97 :
98 : /****************************************************************************/
99 : /* Create() */
100 : /* */
101 : /* Create a new datasource. This does not really do anything */
102 : /* currently but save the name. */
103 : /****************************************************************************/
104 :
105 67 : bool OGRMiraMonDataSource::Create(const char *pszDataSetName,
106 : CSLConstList /* papszOptions */)
107 :
108 : {
109 67 : m_bUpdate = true;
110 67 : m_osRootName = pszDataSetName;
111 :
112 67 : return true;
113 : }
114 :
115 : /****************************************************************************/
116 : /* ICreateLayer() */
117 : /****************************************************************************/
118 :
119 : OGRLayer *
120 83 : OGRMiraMonDataSource::ICreateLayer(const char *pszLayerName,
121 : const OGRGeomFieldDefn *poGeomFieldDefn,
122 : CSLConstList papszOptions)
123 : {
124 83 : CPLAssert(nullptr != pszLayerName);
125 :
126 83 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
127 : const auto poSRS =
128 83 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
129 :
130 : // It's a seed to be able to generate a random identifier in
131 : // MMGenerateFileIdentifierFromMetadataFileName() function
132 83 : srand((unsigned int)time(nullptr));
133 :
134 83 : if (OGR_GT_HasM(eType))
135 : {
136 0 : CPLError(CE_Warning, CPLE_NotSupported,
137 : "Measures in this layer will be ignored.");
138 : }
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* If the dataset has an extension, it is understood that the path */
142 : /* of the file is where to write, and the layer name is the */
143 : /* dataset name (without extension). */
144 : /* -------------------------------------------------------------------- */
145 83 : const char *pszExtension = CPLGetExtension(m_osRootName.c_str());
146 166 : std::string osFullMMLayerName;
147 83 : if (EQUAL(pszExtension, "pol") || EQUAL(pszExtension, "arc") ||
148 71 : EQUAL(pszExtension, "pnt"))
149 : {
150 21 : osFullMMLayerName = CPLResetExtension(m_osRootName.c_str(), "");
151 21 : if (!osFullMMLayerName.empty())
152 21 : osFullMMLayerName.pop_back();
153 :
154 : // Checking that the folder where to write exists
155 : const std::string osDestFolder =
156 21 : CPLGetDirname(osFullMMLayerName.c_str());
157 21 : if (!STARTS_WITH(osDestFolder.c_str(), "/vsimem"))
158 : {
159 : VSIStatBufL sStat;
160 0 : if (VSIStatL(osDestFolder.c_str(), &sStat) != 0 ||
161 0 : !VSI_ISDIR(sStat.st_mode))
162 : {
163 0 : CPLError(CE_Failure, CPLE_AppDefined,
164 : "The folder %s does not exist.", osDestFolder.c_str());
165 0 : return nullptr;
166 : }
167 21 : }
168 : }
169 : else
170 : {
171 : osFullMMLayerName =
172 62 : CPLFormFilename(m_osRootName.c_str(), pszLayerName, "");
173 :
174 : /* -------------------------------------------------------------------- */
175 : /* Let's create the folder if it's not already created. */
176 : /* (only the las level of the folder) */
177 : /* -------------------------------------------------------------------- */
178 62 : if (!STARTS_WITH(m_osRootName.c_str(), "/vsimem"))
179 : {
180 : VSIStatBufL sStat;
181 14 : if (VSIStatL(m_osRootName.c_str(), &sStat) != 0 ||
182 0 : !VSI_ISDIR(sStat.st_mode))
183 : {
184 14 : if (VSIMkdir(m_osRootName.c_str(), 0755) != 0)
185 : {
186 1 : CPLError(CE_Failure, CPLE_AppDefined,
187 : "Unable to create the folder %s.",
188 : m_osRootName.c_str());
189 1 : return nullptr;
190 : }
191 : }
192 : }
193 : }
194 :
195 : /* -------------------------------------------------------------------- */
196 : /* Return open layer handle. */
197 : /* -------------------------------------------------------------------- */
198 82 : if (Open(osFullMMLayerName.c_str(), nullptr, poSRS, papszOptions))
199 : {
200 82 : return m_apoLayers.back().get();
201 : }
202 :
203 0 : return nullptr;
204 : }
205 :
206 : /****************************************************************************/
207 : /* TestCapability() */
208 : /****************************************************************************/
209 :
210 201 : int OGRMiraMonDataSource::TestCapability(const char *pszCap)
211 :
212 : {
213 201 : if (EQUAL(pszCap, ODsCCreateLayer))
214 63 : return m_bUpdate;
215 138 : else if (EQUAL(pszCap, ODsCZGeometries))
216 20 : return TRUE;
217 :
218 118 : return FALSE;
219 : }
220 :
221 : /****************************************************************************/
222 : /* GetLayer() */
223 : /****************************************************************************/
224 :
225 362 : OGRLayer *OGRMiraMonDataSource::GetLayer(int iLayer)
226 :
227 : {
228 362 : if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
229 20 : return nullptr;
230 :
231 342 : return m_apoLayers[iLayer].get();
232 : }
233 :
234 : /************************************************************************/
235 : /* GetFileList() */
236 : /************************************************************************/
237 :
238 10 : char **OGRMiraMonDataSource::GetFileList()
239 : {
240 20 : CPLStringList oFileList;
241 20 : for (auto &poLayer : m_apoLayers)
242 : {
243 10 : poLayer->AddToFileList(oFileList);
244 : }
245 20 : return oFileList.StealList();
246 : }
|