Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements OGRGmtDataSource class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "cpl_conv.h"
14
#include "cpl_string.h"
15
#include "ogr_gmt.h"
16
17
/************************************************************************/
18
/*                          OGRGmtDataSource()                          */
19
/************************************************************************/
20
21
OGRGmtDataSource::OGRGmtDataSource()
22
10.5k
    : papoLayers(nullptr), nLayers(0), bUpdate(false)
23
10.5k
{
24
10.5k
}
25
26
/************************************************************************/
27
/*                         ~OGRGmtDataSource()                          */
28
/************************************************************************/
29
30
OGRGmtDataSource::~OGRGmtDataSource()
31
32
10.5k
{
33
21.0k
    for (int i = 0; i < nLayers; i++)
34
10.4k
        delete papoLayers[i];
35
10.5k
    CPLFree(papoLayers);
36
10.5k
}
37
38
/************************************************************************/
39
/*                                Open()                                */
40
/************************************************************************/
41
42
int OGRGmtDataSource::Open(const char *pszFilename, VSILFILE *fp,
43
                           const OGRSpatialReference *poSRS, bool bUpdateIn)
44
45
10.5k
{
46
10.5k
    bUpdate = bUpdateIn;
47
48
10.5k
    OGRGmtLayer *poLayer =
49
10.5k
        new OGRGmtLayer(this, pszFilename, fp, poSRS, bUpdate);
50
10.5k
    if (!poLayer->bValidFile)
51
101
    {
52
101
        delete poLayer;
53
101
        return FALSE;
54
101
    }
55
56
10.4k
    papoLayers = static_cast<OGRGmtLayer **>(
57
10.4k
        CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRGmtLayer *)));
58
10.4k
    papoLayers[nLayers] = poLayer;
59
10.4k
    nLayers++;
60
61
10.4k
    return TRUE;
62
10.5k
}
63
64
/************************************************************************/
65
/*                            ICreateLayer()                            */
66
/************************************************************************/
67
68
OGRLayer *
69
OGRGmtDataSource::ICreateLayer(const char *pszLayerName,
70
                               const OGRGeomFieldDefn *poGeomFieldDefn,
71
                               CSLConstList /*papszOptions*/)
72
689
{
73
689
    if (nLayers != 0)
74
588
        return nullptr;
75
76
101
    const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
77
101
    const auto poSRS =
78
101
        poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
79
80
    /* -------------------------------------------------------------------- */
81
    /*      Establish the geometry type.  Note this logic                   */
82
    /* -------------------------------------------------------------------- */
83
101
    const char *pszGeom = nullptr;
84
85
101
    switch (wkbFlatten(eType))
86
101
    {
87
0
        case wkbPoint:
88
0
            pszGeom = " @GPOINT";
89
0
            break;
90
1
        case wkbLineString:
91
1
            pszGeom = " @GLINESTRING";
92
1
            break;
93
2
        case wkbPolygon:
94
2
            pszGeom = " @GPOLYGON";
95
2
            break;
96
4
        case wkbMultiPoint:
97
4
            pszGeom = " @GMULTIPOINT";
98
4
            break;
99
0
        case wkbMultiLineString:
100
0
            pszGeom = " @GMULTILINESTRING";
101
0
            break;
102
0
        case wkbMultiPolygon:
103
0
            pszGeom = " @GMULTIPOLYGON";
104
0
            break;
105
94
        default:
106
94
            pszGeom = "";
107
94
            break;
108
101
    }
109
110
    /* -------------------------------------------------------------------- */
111
    /*      If this is the first layer for this datasource, and if the      */
112
    /*      datasource name ends in .gmt we will override the provided      */
113
    /*      layer name with the name from the gmt.                          */
114
    /* -------------------------------------------------------------------- */
115
116
101
    CPLString osPath = CPLGetPathSafe(GetDescription());
117
101
    CPLString osFilename(GetDescription());
118
101
    const char *pszFlags = "wb+";
119
120
101
    if (osFilename == "/dev/stdout")
121
0
        osFilename = "/vsistdout";
122
123
101
    if (STARTS_WITH(osFilename, "/vsistdout"))
124
0
        pszFlags = "wb";
125
101
    else if (!EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "gmt"))
126
0
        osFilename = CPLFormFilenameSafe(osPath, pszLayerName, "gmt");
127
128
    /* -------------------------------------------------------------------- */
129
    /*      Open the file.                                                  */
130
    /* -------------------------------------------------------------------- */
131
101
    VSILFILE *fp = VSIFOpenL(osFilename, pszFlags);
132
101
    if (fp == nullptr)
133
0
    {
134
0
        CPLError(CE_Failure, CPLE_OpenFailed, "open(%s) failed: %s",
135
0
                 osFilename.c_str(), VSIStrerror(errno));
136
0
        return nullptr;
137
0
    }
138
139
    /* -------------------------------------------------------------------- */
140
    /*      Write out header.                                               */
141
    /* -------------------------------------------------------------------- */
142
101
    VSIFPrintfL(fp, "# @VGMT1.0%s\n", pszGeom);
143
101
    if (!STARTS_WITH(osFilename, "/vsistdout"))
144
101
    {
145
101
        VSIFPrintfL(fp, "# REGION_STUB                                      "
146
101
                        "                       \n");
147
101
    }
148
149
    /* -------------------------------------------------------------------- */
150
    /*      Write the projection, if possible.                              */
151
    /* -------------------------------------------------------------------- */
152
101
    if (poSRS != nullptr)
153
12
    {
154
12
        if (poSRS->GetAuthorityName() &&
155
4
            EQUAL(poSRS->GetAuthorityName(), "EPSG"))
156
4
        {
157
4
            VSIFPrintfL(fp, "# @Je%s\n", poSRS->GetAuthorityCode());
158
4
        }
159
160
12
        char *pszValue = nullptr;
161
12
        if (poSRS->exportToProj4(&pszValue) == OGRERR_NONE)
162
4
        {
163
4
            VSIFPrintfL(fp, "# @Jp\"%s\"\n", pszValue);
164
4
        }
165
12
        CPLFree(pszValue);
166
12
        pszValue = nullptr;
167
168
12
        if (poSRS->exportToWkt(&pszValue) == OGRERR_NONE)
169
4
        {
170
4
            char *pszEscapedWkt =
171
4
                CPLEscapeString(pszValue, -1, CPLES_BackslashQuotable);
172
173
4
            VSIFPrintfL(fp, "# @Jw\"%s\"\n", pszEscapedWkt);
174
4
            CPLFree(pszEscapedWkt);
175
4
        }
176
12
        CPLFree(pszValue);
177
12
    }
178
179
    /* -------------------------------------------------------------------- */
180
    /*      Return open layer handle.                                       */
181
    /* -------------------------------------------------------------------- */
182
101
    if (Open(osFilename, fp, poSRS, true))
183
101
    {
184
101
        OGRLayer *poLayer = papoLayers[nLayers - 1];
185
101
        if (strcmp(pszGeom, "") != 0)
186
7
        {
187
7
            poLayer->GetLayerDefn()->SetGeomType(wkbFlatten(eType));
188
7
        }
189
101
        return poLayer;
190
101
    }
191
192
0
    VSIFCloseL(fp);
193
0
    return nullptr;
194
101
}
195
196
/************************************************************************/
197
/*                           TestCapability()                           */
198
/************************************************************************/
199
200
int OGRGmtDataSource::TestCapability(const char *pszCap) const
201
202
1.51k
{
203
1.51k
    if (EQUAL(pszCap, ODsCCreateLayer))
204
689
        return TRUE;
205
823
    else if (EQUAL(pszCap, ODsCZGeometries))
206
0
        return TRUE;
207
208
823
    return FALSE;
209
1.51k
}
210
211
/************************************************************************/
212
/*                              GetLayer()                              */
213
/************************************************************************/
214
215
const OGRLayer *OGRGmtDataSource::GetLayer(int iLayer) const
216
217
10.6k
{
218
10.6k
    if (iLayer < 0 || iLayer >= nLayers)
219
0
        return nullptr;
220
221
10.6k
    return papoLayers[iLayer];
222
10.6k
}