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/kml/ogrkmldriver.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  KML Driver
4
 * Purpose:  Implementation of OGRKMLDriver class.
5
 * Author:   Christopher Condit, condit@sdsc.edu;
6
 *           Jens Oberender, j.obi@troja.net
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2006, Christopher Condit
10
 *               2007, Jens Oberender
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "ogr_kml.h"
17
18
#include <cstring>
19
20
#include "cpl_conv.h"
21
#include "cpl_error.h"
22
#include "gdal.h"
23
#include "gdal_priv.h"
24
25
/************************************************************************/
26
/*                        OGRKMLDriverIdentify()                        */
27
/************************************************************************/
28
29
static int OGRKMLDriverIdentify(GDALOpenInfo *poOpenInfo)
30
31
135k
{
32
135k
    if (poOpenInfo->fpL == nullptr)
33
45.9k
        return FALSE;
34
35
89.8k
    return strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader), "<kml") !=
36
89.8k
               nullptr ||
37
82.1k
           strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
38
82.1k
                  "<kml:kml") != nullptr;
39
135k
}
40
41
/************************************************************************/
42
/*                                Open()                                */
43
/************************************************************************/
44
45
static GDALDataset *OGRKMLDriverOpen(GDALOpenInfo *poOpenInfo)
46
47
3.84k
{
48
3.84k
    if (poOpenInfo->eAccess == GA_Update)
49
0
        return nullptr;
50
51
3.84k
    if (!OGRKMLDriverIdentify(poOpenInfo))
52
0
        return nullptr;
53
54
3.84k
#ifdef HAVE_EXPAT
55
3.84k
    OGRKMLDataSource *poDS = new OGRKMLDataSource();
56
57
3.84k
    if (poDS->Open(poOpenInfo->pszFilename, TRUE))
58
440
    {
59
#ifdef DEBUG_VERBOSE
60
        if (poDS->GetLayerCount() == 0)
61
        {
62
            CPLError(CE_Failure, CPLE_OpenFailed, "No layers in KML file: %s.",
63
                     poOpenInfo->pszFilename);
64
65
            delete poDS;
66
            poDS = nullptr;
67
        }
68
#endif
69
440
    }
70
3.40k
    else
71
3.40k
    {
72
3.40k
        delete poDS;
73
3.40k
        poDS = nullptr;
74
3.40k
    }
75
76
3.84k
    return poDS;
77
#else
78
    return nullptr;
79
#endif
80
3.84k
}
81
82
/************************************************************************/
83
/*                               Create()                               */
84
/************************************************************************/
85
86
static GDALDataset *OGRKMLDriverCreate(const char *pszName, int /* nBands */,
87
                                       int /* nXSize */, int /* nYSize */,
88
                                       GDALDataType /* eDT */,
89
                                       CSLConstList papszOptions)
90
601
{
91
601
    CPLAssert(nullptr != pszName);
92
601
    CPLDebug("KML", "Attempt to create: %s", pszName);
93
94
601
    OGRKMLDataSource *poDS = new OGRKMLDataSource();
95
96
601
    if (!poDS->Create(pszName, papszOptions))
97
0
    {
98
0
        delete poDS;
99
0
        poDS = nullptr;
100
0
    }
101
102
601
    return poDS;
103
601
}
104
105
/************************************************************************/
106
/*                           RegisterOGRKML()                           */
107
/************************************************************************/
108
109
void RegisterOGRKML()
110
22
{
111
22
    if (GDALGetDriverByName("KML") != nullptr)
112
0
        return;
113
114
22
    GDALDriver *poDriver = new GDALDriver();
115
116
22
    poDriver->SetDescription("KML");
117
22
    poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
118
22
    poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
119
22
    poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
120
22
    poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
121
22
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
122
22
                              "Keyhole Markup Language (KML)");
123
22
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kml");
124
22
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/kml.html");
125
22
    poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
126
127
22
    poDriver->SetMetadataItem(
128
22
        GDAL_DMD_CREATIONOPTIONLIST,
129
22
        "<CreationOptionList>"
130
22
        "  <Option name='DOCUMENT_ID' type='string' description='Id of the "
131
22
        "root &lt;Document&gt; node' default='root_doc'/>"
132
22
        "  <Option name='GPX_USE_EXTENSIONS' type='boolean' "
133
22
        "description='Whether to write non-GPX attributes in an "
134
22
        "&lt;extensions&gt; tag' default='NO'/>"
135
22
        "  <Option name='NameField' type='string' description='Field to use to "
136
22
        "fill the KML &lt;name&gt; element' default='Name'/>"
137
22
        "  <Option name='DescriptionField' type='string' description='Field to "
138
22
        "use to fill the KML &lt;description&gt; element' "
139
22
        "default='Description'/>"
140
22
        "  <Option name='AltitudeMode' type='string-select' description='Value "
141
22
        "of the &lt;AltitudeMode&gt; element for 3D geometries'>"
142
22
        "    <Value>clampToGround</Value>"
143
22
        "    <Value>relativeToGround</Value>"
144
22
        "    <Value>absolute</Value>"
145
22
        "  </Option>"
146
22
        "</CreationOptionList>");
147
148
22
    poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST,
149
22
                              "<LayerCreationOptionList/>");
150
22
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
151
22
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
152
22
                              "Integer Real String");
153
22
    poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES");
154
22
    poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_WRITE, "YES");
155
22
    poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
156
157
22
    poDriver->pfnOpen = OGRKMLDriverOpen;
158
22
    poDriver->pfnIdentify = OGRKMLDriverIdentify;
159
22
    poDriver->pfnCreate = OGRKMLDriverCreate;
160
161
22
    GetGDALDriverManager()->RegisterDriver(poDriver);
162
22
}