Coverage Report

Created: 2025-06-09 08:44

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